-Wed Feb 21 17:01:01 EET 2007 Pekka Riikonen <priikone@silcnet.org>
+Mon Mar 5 23:27:32 CET 2007 Jochen Eisinger <coffee@silcnet.org>
- * Fixed WHOIS command and requested attributes handling in
- client library. Affected files are lib/silcclient/command.c
- and lib/silcclient/client_attrs.c.
+ * Update patch to makefile from trunk so parallel make will link
+ the silc-client correctly. Affected file lib/Makefile.ad
- * Fixed silc_time_value to actually work. Added new function
- silc_timezone. Affected files are lib/silcutil/silctime.[ch].
+Sun Nov 19 18:58:26 CET 2006 Jochen Eisinger <coffee@silcnet.org>
-Tue Feb 20 08:31:28 EET 2007 Pekka Riikonen <priikone@silcnet.org>
+ * Import perl script for sign_messages from silc-plugin. Affected
+ file apps/irssi/scripts/silc.pl
- * SILC Client 1.1 beta2.
+Tue Oct 3 21:22:00 CEST 2006 Jochen Eisinger <coffee@silcnet.org>
-Mon Feb 19 16:06:27 EET 2007 Pekka Riikonen <priikone@silcnet.org>
+ * When joining channels with a password given in the config file,
+ use it. Also use it when cycling (it would be better to get
+ the password from the server, but this isn't possible in SILC).
+ Affected files apps/irssi/src/silc/core/silc-servers.c,
+ apps/irssi/src/silc/core/silc-channels.c
- * Fixed client to properly abort TCP stream creation when
- giving /QUIT. Affected file
- apps/irssi/src/silc/core/silc-servers.c.
+Sun Oct 1 20:39:34 CEST 2006 Jochen Eisinger <coffee@silcnet.org>
- * Fixed several connecting aborting crashes from the client
- library, packet engine and socket stream. Affected files
- are in lib/silclient/, lib/silccore/silcpacket.c and
- lib/silcutil/unix/silcunixsocketstream.c.
+ * Always return a valid username. Affected file
+ lib/silcutil/unix/silcunixutil.c
+ * Only wait for a nick on connecting, when it differs
+ (not counting case) from the username. Affected file
+ apps/irssi/src/silc/core/client_ops.c
- * Fixed private key export double free crash in key generation.
- Affected file is lib/silccrypt/silcpk.c.
+Sun Jul 2 19:12:36 CEST 2006 Jochen Eisinger <coffee@silcnet.org>
- * Fixed FSM event waiting when there are multiple signallers
- and the waiter goes away after the first signal. Affected
- file in lib/silcutil/silcfsm.c.
+ * Make gmake the default for autodist, so I can properly work
+ on otaku. Affected files README.DIST, distdir/autodist.conf
-Sun Feb 18 22:02:22 EET 2007 Pekka Riikonen <priikone@silcnet.org>
+Fri Jan 6 13:08:15 CET 2006 Jochen Eisinger <coffee@silcnet.org>
- * Fixed FSM event signalling to check if the waiter has gone
- away already. Affected file is lib/silcutil/silcfsm.c.
-
- * Fixed counter mode encryption/decryption to handle non-padded
- SILC packets correctly. The silc_cipher_set_iv now
- in counter mode resets for a new block. Affected files are
- in lib/silcske/, lib/silccrypt/, lib/silcpacket/.
-
-Sun Feb 18 12:15:21 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * SILC Client 1.1 beta1.
-
- * Memory leak fixes around the libraries.
-
-Fri Feb 16 16:53:16 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added better check for epoll() in configure. Affected file
- is lib/configure.ad.
-
-Thu Feb 15 16:50:34 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Fixed per scheduler data input buffer in packet engine. Use
- list of inbufs instead of just one so that multiple streams
- can do partial reads to different buffers. Affected file is
- lib/silccore/silcpacket.c.
-
- * Fixed WATCH notify handling in client library. Affected file
- is lib/silcclient/client_notify.c.
-
-Wed Feb 14 17:05:38 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Fixed packet wrapper stream API to support encoder/decoder
- for packets, and to handle partial reading correctly. Fixed
- also inbuf size checking in reading to have enough space before
- reading. Affected files are lib/silccore/silcpacket.[ch].
-
- * Rewrote file transfer in client library. Affected files are
- in lib/silcclient/.
-
- * Added TCP/UDP listener (internal) API to client library to have
- generic way of dealing with listeners. Fixed Key Agreement and
- file transfer to use it. Affected files are in lib/silcclient/.
-
- * Fixed SKE to process SUCCESS packets synchronously and to call
- completion synchronously. Affected file is lib/silcske/silske.c.
-
- * Fixed pthread rwlock detection. Affected file includes/silc.h.in.
-
- * Implemented SILC_ATTRIBYUTE_PHONE_NUMBER. Affected files are
- lib/silccore/silcattrs.[ch]. SILC Protocol version 1.3 change.
-
-Fri Feb 2 22:24:11 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added support for SILC protocol version 1.3 NEW_CLIENT packet
- to client library. Affected file is
- lib/silcclient/client_register.c.
-
- * Serialize NICK and JOIN commands to avoid problems locally
- with changing ID while joining to channel. Affected file is
- lib/silcclient/command.c.
-
- * Fixed entry resolving while handling incoming JOIN notify.
- Handle properly cases, in re-processing of notify packets, where
- the IDs may become invalid while resolving the entry (like nick
- change). Entry is invalid if it doesn't have nickname, and such
- entries are not delivered to application anymore. These fixes
- problems of not seeing JOINs when remote user changes nickname
- at the same time. Affected files are in lib/silcclient/.
-
-Thu Feb 1 18:35:58 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added support for computing message payload MAC in new way
- (SILC Protocol version 1.3). Bakcwards support for old way
- remains. Affected files are lib/silccore/silcmessage.[ch].
-
-Sat Jan 27 22:37:30 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added SilcRwLock API, a read/write lock. Affected files are
- lib/silcutil/silcmutex.h and in lib/silcutil/[unix|win32|symbian]/.
-
-Wed Jan 24 18:55:21 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Merged Irssi SVN (irssi 0.8.11). Affected files in apps/irssi/.
-
-Tue Jan 23 16:05:27 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * The silc_schedule_set_listen_fd now returns boolean value.
- Fixed FD task adding to check correctly for already added
- FD tasks. Added stricter error checking for FD scheduling
- with epoll(). Affected files are lib/silcutil/silcschedule.[ch]
- and lib/silcutil/unix/silcunixschedule.c.
-
- * The silc_stream_set_notifier now returns boolean value. Changed
- all streams to support and check for the error condition.
- Affected files are in lib/silcutil/.
-
- * Fixed SKE library session aborting and deletion. Affected
- file are lib/silcske/silcske.c.
-
-Tue Jan 16 18:22:08 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Implemented PKCS #1 with appendix with hash OID in the
- signature. Affected files are lib/silccrypt/silcpkcs1.[ch],
- lib/silccrypt/silchash.[ch] and
- lib/silcasn1/silcasn1[_encode|decode].[ch].
-
-Sun Jan 14 23:12:41 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added support for Version (V) SILC public key identifier.
- Affected files are lib/silccrypt/silcpk.[ch].
-
-Tue Jan 9 19:37:51 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Rewrote connection auth request in client library. It is now
- done automatically by the library and the resolved method given
- as a hint to get_auth_method client operation. Affected files
- are lib/silcclient/.
-
-Wed Jan 3 18:06:33 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added silc_packet_stream_wrap into lib/silccore/silcpacket.[ch].
- It can be used to wrap SilcPacketStream into SilcStream.
-
- * Fixed %p formatting from silc_snprintf. Affected file is
- lib/silcutil/silcsnprintf.c.
-
- * Ported SFTP library to new utility library. Ported also
- the SFTP testers. Affected files in lib/silcsftp/.
-
-Tue Jan 2 17:18:46 EET 2007 Pekka Riikonen <priikone@silcnet.org>
-
- * Added lib/silcutil/silcsnprintf.[ch]. Added in addition
- of silc_snprintf, silc_vsnprintf, silc_asprintf and
- silc_vasprintf.
-
-Sat Dec 30 23:23:17 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added preliminary Symbian support. Changes around the source
- tree. The symbian/ directory now includes Carbide.c++ project
- files to compile the sources.
-
- * Added silc_snprintf. Affected files are
- lib/silcutil/silcstrutil.[ch].
-
-Thu Dec 21 18:01:51 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Changed SILC_FSM_[CONTINUE|YIELD|WAIT|FINISH] enums to
- macros. SILC_FSM_CONTINUE macro now immediately calls the
- next state instead of first returning back to FSM. Helps
- in debugging crashes etc.
-
- Removed FSM Semaphores. Introduced FSM Event which is
- asynchronous event. Affected files are in lib/.
-
- * Added epoll(7) support to SILC Scheduler. It is used by default
- if it is available. Affected files are
- lib/silcutil/silcschedule.[ch],
- lib/silcutil/unix/silcunixschedule.c.
-
-Tue Dec 19 20:39:35 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added CTR mode to AES. Simplified cipher implementation API
- more. Affected files are in lib/silccrypt/.
-
-Sun Dec 17 16:46:55 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Removed `detach' client operation. The detachment data is
- now delivered in SILC_COMMAND_DETACH command reply to
- application. Affected file in lib/silcclient/.
-
- * Rewrote resuming/detaching in client library.
-
- * Added boolean encryption indicator for silc_cipher_set_key.
- Affected files lib/silccrypt/silccipher.[ch].
-
-Wed Dec 13 18:05:50 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added silc_likely and silc_unlikely macros for GCC branch
- prediction optimizations. Affected file lib/silcutil/silctypes.h.
-
- * Added assembler AES optimization. Cleaned up the SILC Cipher
- implementation API. Affected files are in lib/silccrypt/.
-
-Tue Dec 12 18:56:14 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Changed back the SILC_FSM_THREAD_WAIT operation to not
- continue to next state if thread is finished already. That
- check is not done anymore. Affected files are
- lib/silcutil/silcfsm.[ch].
-
-Sun Dec 10 13:54:52 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Removed silc_packet_[get|set]_ciphers and
- silc_packet_[get|set]_hmacs. Added silc_packet_set_keys that
- handle REKEY_DONE packet sending in rekey. Affected files
- are lib/silccore/silcpacket.[ch].
-
- * Added silc_fsm_is_started. Affected files are
- lib/silcutil/silcfsm.[ch].
-
- * Added settings sign_channel_message, sign_private_message
- and key_exchange_rekey_pfs to SILC Client. Added UDP transport
- support for key agreement in /KEY command. Affected files
- in apps/irssi/src/silc/core/.
-
- * During SILC Client initialization forward log messages to
- stderr. Affected files in apps/irssi/src/silc/core/.
-
-Thu Dec 7 19:07:21 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added silc_ske_get_key_material. Affected files are
- lib/silcske/silcske.[ch].
-
- * Added silc_packet_stream_is_udp. Affected files are
- lib/silccore/silcpacket.[ch].
-
- * Added SKE packet retransmission support with UDP transport.
- Affected file is lib/silcske/silcske.c.
-
-Sun Dec 3 22:00:12 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added silc_socket_stream_is_udp. Affected file is
- lib/silcutil/silcsocketstream.[ch].
-
- * Added UDP transport support to packet engine. Affected file
- is lib/silccore/silcpacket.c.
-
- * Added silc_socket_stream_is_udp. Affected file is
- lib/silcutil/silcsocketstream.[ch].
-
-Sat Nov 18 11:33:03 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added silc_packet_send_va[_ext] to send variable argument
- formatted buffers. Affected files lib/silcore/silcpacket.[ch].
-
- * Timeout freelist garbage collection added to scheduler.
- Affected file lib/silcutil/silcschedule.c.
-
-Thu Nov 9 18:12:15 EET 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added silc_show_public_key_file to
- lib/silcapputil/silcapputil.[ch].
-
- * Added SILC_STR_ADVANCE support for buffer unformatting.
- Affected file lib/silcutil/silcbuffmt.c.
-
-Tue Nov 7 18:04:36 EET 2006 Pekka Riikonen <priikone@silcnet.org
-
- * Added silc_string_split to lib/silcutil/silcstrutil.[ch].
-
- * Added silc_mutex_assert_locked to lib/silcutil/silcmutex.h.
-
- * silc_fsm_continue[_sync] now cancels erlier timeout set with
- silc_fsm_next_later. Affected file lib/silcutil/silcfsm.c.
-
-Sat Nov 4 21:50:37 EET 2006 Pekka Riikonen <priikone@silcnet.org
-
- * Added SILC_STR_FUNC to buffer format API. Affected files
- are lib/silcutil/silcbuffmt.[ch].
-
- * Added silc_buffer_[s]enlarge to lib/silcutil/silcbuffer.h.
-
- * No more memory allocation for message payload parsing.
- Pre-allocated buffer can be used with message payload encoding.
- Affected files lib/silccore/silcmessage.[ch].
-
-Fri Oct 27 21:01:26 EEST 2006 Pekka Riikonen <priikone@silcnet.org
-
- * Added silc_buffer_sunformat and silc_buffer_sunformat_vp
- to silcutil/silcbuffmt.[ch].
-
-Sun Oct 22 13:03:07 EEST 2006 Pekka Riikonen <priikone@silcnet.org
-
- * Added SILC_STR_BUFFER to format and unformat SilcBuffer.
- Affected file lib/silcutil/silcbuffmt.[ch].
-
- * Removed silc_schedule_signal_[un]register and
- silc_schedule_signal_call. Added silc_schedule_task_add_signal
- to add signal task. Only one callback per signal may be
- added. The signals are now automatically called back to
- caller. Affected files lib/silcutil/silcschedule.[ch] and
- silcutil/[unix/win32]/silc[unix/win32]schedule.c.
-
- * Added silc_time_msec and silc_time_usec to silcutil/silctime.[ch].
-
- * Added SilcSKEParams for SKE parameters and simplied even more
- the SKE interface. Affected files are lib/silcske/silcske.[ch].
- Added support for IV included and session port handling with
- UDP/IP connections.
-
- * Added Secure ID (SID) support with IV Included flag (for UDP/IP)
- in lib/silccore/silcpacket.[ch]. Added silc_packet_set_sid
- which is called after every rekey when IV Included flag is used.
- See SILC specifications for details.
-
-Thu Oct 19 10:03:03 EEST 2006 Pekka Riikonen <priikone@silcnet.org
-
- * Added lib/silcapputil and moved SILC application specific
- utility routines from the generic util library lib/silcutil
- to the new library. Removed lib/silcidcache and moved that
- to lib/silcapputil as well.
-
-Tue Sep 19 00:14:11 EEST 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added SILC_STR_ADVANCE. Affected file is
- lib/silcutil/silcbuffmt.[ch].
-
- * The silc_buffer_strformat preserves buffer locations now.
-
- * Added lib/silcutil/silcatomic.h for atomic operations.
-
-Sat Sep 16 11:23:06 EEST 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added lib/silchttp, SILC HTTP server, a very simple HTTP
- server.
-
- * Fixed MIME deocing when data portion is not present.
- Affected file lib/silcutil/silcmime.c.
-
-Wed Jul 19 12:06:38 EEST 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Moved lib/silccore/silcidcache.[ch] to lib/silcutil/.
-
- * Added IV Included support to packet routines, to allow
- packet sending and receiving on UDP/IP. Affected files are
- lib/silccore/silcpacket.[ch].
-
- * Added SILC_FSM_YIELD. Affected files lib/silcutil/silcfsm.[ch].
-
-Tue Jul 18 20:10:28 EEST 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added UDP support to network and socket stream library.
-
-Sat Jun 24 22:33:18 EEST 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Added conditional variables. New files are
- lib/silcutil/silcondvar.h and platform specific implementations.
+ * Fixed more autodist issues. Affected file doc/Makefile.ad,
+ apps/irssi/src/perl/Makefile.am, distdir/post-process-dist.
Thu Jan 5 20:02:31 CET 2006 Patrik Weiskircher <pat@icore.at>
file lib/silcclient/client_ftp.c.
Patch received from Stefan Siegel <stesie@brokenpipe.de>, thanks!
-Fri Dec 30 22:54:21 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+Wed Dec 14 19:21:42 CET 2005 Jochen Eisinger <coffee@silcnet.org>
- * New SILC PKCS API enabling support for other public keys
- and certificates, lib/silccrypt/silcpkcs.[ch], silcpk.[ch].
+ * Fixed autodist configuration for silc-client. Affected file
+ configure.ad
+ * Honor user set hostname. Also give the user a chance to
+ read the error message. Affected file
+ apps/irssi/src/silc/core/silc-core.c
- * Separated SILC Public Key Payload routines from the PKCS API
- to lib/silccore/silcpubkey.[ch].
+Tue Nov 29 07:52:11 CET 2005 Patrik Weiskircher <pat@icore.at>
-Wed Dec 28 13:55:22 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+ * Fixed compile error on non-i386. Affected file
+ lib/silccrypt/sha256.c.
- * Added SILC Key Repository library, lib/silcskr.
+Mon Nov 21 19:18:15 EET 2005 Pekka Riikonen <priikone@silcnet.org>
- * Added SILC Server library, lib/silcserver.
+ * Added SILC_ATTRIBUTE_USER_ICON to lib/silccore/silcattrs.[ch].
-Mon Dec 19 18:04:24 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+Sun Nov 20 19:13:35 EET 2005 Pekka Riikonen <priikone@silcnet.org>
- * MIME objects in attributes now use SilcMime. Affected files
- are lib/silccore/silcattrs.[ch].
+ * Removed callback system from SilcMimeAssembler. Return
+ the multipart type in silc_mime_get_multiparts. Affected
+ files are lib/silcutil/silcmime.[ch].
-Sat Dec 17 20:13:31 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+Sat Nov 19 17:34:51 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.
+ * Added SilcMime API to lib/silcutil/silcmime.[ch]. The old
+ silc_mime_parse is available but deprecated.
-Mon Nov 28 17:06:54 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+ * Check that packet is valid when processing key exchange,
+ authentication and rekey protocols. Fixes a crashbug.
+ Affected files are apps/silcd/protocol.c and
+ lib/silcclient/protocol.c.
+
+ * Added SILC_HASH_MAXLEN to lib/silccrypt/silchash.h, and changed
+ all hash buffers to use that instead of fixed values.
- * Added silc_file_set_nonblock. Affected file is
- lib/silcutil/silcfileutil.h.
+Wed Nov 16 15:47:12 EET 2005 Pekka Riikonen <priikone@silcnet.org>
- * Added silc_fd_stream_file to lib/silcutil/silcfdstream.[ch].
+ * Added SHA-256 to crypto library. The SHA-256 takes now
+ precedence over SHA-1.
-Sat Nov 26 16:13:40 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+Wed Nov 16 00:36:53 CET 2005 Jochen Eisinger <c0ffee@penguin-breeder.org>
- * FSM based implementation of SILC SKE. Simpler interface also.
- Affected files are in lib/silcske/.
+ * fixed wrong return code in term_init. Affected file
+ apps/irssi/src/fe-text/terminfo-core.c
+
+Mon Sep 12 18:13:38 CEST 2005 Jochen Eisinger <c0ffee@penguin-breeder.org>
- * Added SilcBool type. Affected file lib/silcutil/silctypes.h.
+ * and it doesn't return FILE* but a file descriptor. Affected
+ file apps/silcd/silcd.c
-Sat Nov 19 17:34:51 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+Mon Sep 5 18:40:22 CEST 2005 Jochen Eisinger <c0ffee@penguin-breeder.org>
- * Added SilcMime API to lib/silcutil/silcmime.[ch]. The old
- silc_mime_parse is available but deprecated.
+ * mkstemp returns -1 on error, thanks to brad@comstyle.com for
+ pointing this out. Affected file apps/silcd/silcd.c
- * Check that packet is valid when processing key exchange,
- authentication and rekey protocols. Fixes a crashbug.
- Affected files are apps/silcd/protocol.c and
- lib/silcclient/protocol.c.
+Fri Sep 2 23:44:37 CEST 2005 Jochen Eisinger <c0ffee@penguin-breeder.org>
- * Added SILC_HASH_MAXLEN to lib/silccrypt/silchash.h, and changed
- all hash buffers to use that instead of fixed values.
+ * Fixed the insecure temporary file creation issue now that it's
+ even on bugtraq... Affected file apps/silcd/silcd.c
-Wed Nov 16 15:47:12 EET 2005 Pekka Riikonen <priikone@silcnet.org>
+Wed Aug 24 18:27:48 CEST 2005 Patrik Weiskircher <pat@icore.at>
- * Added SHA-256 to crypto library. The SHA-256 takes now
- precedence over SHA-1.
+ * Before creating a channel key we need to remove the private key
+ mode, otherwise no key is created. Affected file
+ apps/silcd/command.c
+
+Fri Aug 19 15:20:05 CEST 2005 Patrik Weiskircher <pat@icore.at>
+
+ * Before checking ip/hostname of SilcSocketConnection, check
+ if its not doing a host lookup currently. Fixes atleast one
+ crash when many people connect at the same time.
+ Affected file apps/silcd/server_util.c.
Thu May 26 20:31:06 EEST 2005 Pekka Riikonen <priikone@silcnet.org>
* Check for valid return value from regcomp. Affected file
lib/silcutil/unix/silcunixutil.c.
-Tue May 10 23:11:17 EEST 2005 Pekka Riikonen <priikone@silcnet.org>
+Tue May 10 19:55:13 EEST 2005 Pekka Riikonen <priikone@silcnet.org>
- * Fixed silc_hash_uint to work with integers. Affected
- file lib/silcutil/silcutil.c.
+ * Check for FD_SETSIZE in silc_select to not go over.
+ Affected file lib/silcutil/unix/silcunixschedule.c.
Tue May 10 15:11:53 EEST 2005 Pekka Riikonen <priikone@silcnet.org>
EXTRA_DIST = \
silcdefs.h.in \
-#ifdef SILC_DIST_TOOLKIT
- symbian \
-#endif SILC_DIST_TOOLKIT
#ifdef SILC_DIST_SILC
libtoolfix \
CHANGES CREDITS
extra files. If you haven't compiled them after the CVS checkout, they do
not include any extra files.
+NOTE: The default make command use by autodist is gmake. You can change
+this by editing distdir/autodist.conf.
+
NOTE for 'toolkit' distribution: Running ./configure for toolkit
distribution is not necessary. Toolkit is packaged simply by giving
command:
+++ /dev/null
-Compiling SILC Toolkit for Symbian OS
-=====================================
-
-The SILC Toolkit works on Symbian OS. This document is intended for those
-that want to compile the SILC Toolkit by themselves for Symbian OS, or for
-Symbian OS emulator. The building environment expects Carbide.c++ and
-WINSCW compiler for emulator target and GCCE (variant of GCC) for device
-target. The SILC Toolkit has not been tested with other compilers or
-build systems. The build environment expects MS Windows.
-
-
-Installing Build Environment
-============================
-
-If you do not have a working Carbide.c++ and Symbian OS SDK environment
-installed in your MS Windows system it needs to be done first.
-
-1) Download the freely available Carbide.c++ Express from Nokia at
- http://forum.nokia.com. The exact hyprelink location changes often, so
- it is not referenced here. It is usually under "Tools and SDKs" link.
-
-2) After installation a web browser is opened automatically by the
- Carbide.c++ installer. Follow its instructions by installing the Perl,
- CTags and the SDK. Perl and the SDK are required, but CTags is
- optional and if necessary can be omitted.
-
-3) The SILC Toolkit is generic C and C++ code and should work with any
- SDK. If you don't have SDK already installed, install the latest
- version you can find. The links to SDKs are found in the Carbide.c++
- instructions after installation. If you already have SDK in your
- system, you should use that.
-
-4) After installation the environment should be ready for SILC Toolkit
- building.
-
-
-Building with Carbide.c++
-=========================
-
-After starting the Carbide.c++, you should import one of the SILC Toolkit
-projects under symbian/ directory in the SILC Toolkit package. Four
-projects exist:
-
- libsilc/ - SILC Core DLL
- libsilcclient/ - SILC Client DLL
- libsilc_static/ - SILC Core static library
- libsilcclient_static/ - SILC Client static library
-
-After loading the project, the first thing to do is to add a path variable
-to define where the SILC Toolkit sources are located. Go to Window ->
-Preferences. Then, go to General -> Workspace -> Linked Resources. Add
-a new SILCROOT path variable. It should point to the drive and directory
-where the extracted SILC Toolkit sources are located. For example, if you
-extracted the SILC Toolkit package into C:\temp\silc-toolkit-1.1.5 the
-SILCROOT should point to C:\temp. This needs to be done only once.
-
-After that, the building is ready to begin. Choose the target you want
-(emulator or device, debug or release version) and start building.
-TODO for 1.1 And Beyond
-=======================
-
-NOTE: Any item that doesn't have (***DONE) in it, isn't done yet. The
-(***TESTING NEEDED) means that the item has been done but not yet properly
-tested.
-
-
-SILC Client ****PARTLY DONE****
-===========
-
- o Porting to new Toolkit API and new Client Library API (***TESTING NEEDED)
-
- o Improve help files, especially /cmode, /cumode and /key.
-
-
-lib/silcclient, The Client Library ***PARTLY DONE****
-==================================
-
- o silcclient.h clean up and API rewrites.
-
- o silcclient_entry.h finishing, all entry relates APIs to this header.
-
- o SilcChannelEntry, SilcServerEntry, SilcChannelUser, allocating,
- freeing, finding, etc. rewrite. Also making them reference counted for
- multi threads use. (***DONE)
-
- o Rewrite silc_client_get_clients_by_channel.
-
- o Rewrite client side WHOIS command (for whois -details). (***DONE)
-
- o Finish all the missing SILC packet processings, rewrites. (***DONE)
-
- o The client_notify.c rewrite. (***DONE)
-
- o Resuming to client_register.c (remove client_resume.c) (***DONE)
-
- o Rekey rewrite. (***DONE)
-
- o Remove protocol.[ch]. (***DONE)
-
- o File transfer rewrite. (***DONE)
-
- o File transfer API documentation.
-
- o Connection auth request. (***DONE)
-
- o Password auth test, public key auth test.
-
- o Starting key exchange directly, rewrite. (***DONE)
-
- o Channel messages, channel private keys, channel entires, channel
- search, etc. rewrite. (***TESTING NEEDED)
-
- o For many APIs leave the hash context allocations to the caller instead
- of using client->sha1hash and client->md5hash, or some kind of thread
- safe (no locking) concept. (***DONE)
-
- o Key agreement rewrite. (***TESTING NEEDED)
-
- o Connecting to remote client (***DONE)
-
- o peer-to-peer private messages
-
- o Private message waiting API (in threads) (***TESING NEEDED)
-
- o client_attrs.c, attributes rewrite. (***TESTING NEEDED)
-
- o No SilcBuffer lists back to application in command_reply operations.
- Convert them all to real lists and/or structures for easier use.
- (***DONE)
-
- o Nickname formatting rewrite. (***TESTING NEEDED)
-
- o UDP connections. (***TESTING NEEDED)
-
- o Message ACKing.
-
- o in /cmode and /cumode with +r, maybe the public key and private key
- could be just some "string", which would then match to "string.pub" and
- "string.prv".
-
- o All packet waiting timeout tests and error condition tests.
-
-
-lib/silcsftp ****DONE****
-============
-
- o Porting to use the new util library. (***DONE)
-
- o Read-ahead (1.2)
-
-
-lib/silccore/silcpacket.[ch] ****PARTLY DONE****
-============================
-
- o Implement silc_packet_engine_stop and silc_packet_stream_destroy.
-
- o Implement ACK packet and packet payload.
-
- o SilcPacketEngine. (***DONE)
-
- o New SILC Packet API. (***DONE)
-
-
-lib/silccore/silcpacket.[ch] ****PARTLY DONE****
-============================
-
- o IV Included flag support, UDP transport support (***TESTING NEEDED)
-
- o SILC_PACKET_FLAG_ACK support.
-
-
-lib/silccore/silcid.[ch] ****DONE****
-========================
-
- o Add silc_id_str2id to accept the destination buffer as argument
- and thus not require any memory allocation. Same will happen
- with silc_id_payload_* functions. (***DONE)
-
- o silc_id_str2id, silc_id2str to non-allocating routines. (***DONE)
-
-
-lib/silccore
-============
-
- o All payload encoding routines should take SilcStack as argument.
-
- o All payload test routines into lib/silccore/tests/.
-
-
-lib/silcskr
-===========
-
- o Removing key from the repository is not possible currently. It should
- be.
-
- o Add fingerprint as search constraint.
-
-
-lib/silcske/silcske.[ch] ****DONE****
-========================
-
- o IV Included flag support in SKE (***DONE)
-
- o UDP transport changes; retransmission support by using exponential
- backoff algorithm. (***DONE)
-
- o SilcConnAuth header file documentation. (***DONE)
-
-
-lib/silccrypt ****PARTLY DONE****
-=============
-
- o Implement SILC Public Key Version 2 handling in sign/verify. Implement
- Version (V) identifier (***DONE)
-
- o Add fingerprint to SilcSILCPublicKey and retrieval to silcpk.h.
-
- o Implement PKCS #1 sign/verify with hash OID. (***TESTING NEEDED)
-
- o Implement the defined SilcDH API. The definition is in
- lib/silccrypt/silcdh.h.
-
- o SSH2 public keys support, allowing the use of SSH2 public keys in
- SILC.
-
- o OpenPGP certificate support, allowing the use of PGP public keys
- in SILC.
-
- o SILC PKCS (silcpkcs.h) reorganizing when other PK supports added.
- Move the SILC Public Key routines away from the crypto library into
- the core library (silccore). silc_pkcs_public/private_key_* routines
- to silc_public/private_key_* routines. The silc_public_key_* routines
- should also automatically handle SILC Public Keys, and other keys
- and certificates as well. Add fe. silcpk.h into silccore. It should
- also include the Public Key Payload encoding and decoding routines.
- (***DONE)
-
- o Add DSS support.
-
- o Assembler AES (***DONE)
-
- o ECDSA and ECDH.
-
-
-lib/silcutil ****PARTLY DONE****
-============
-
- o The regex code from lib/contrib might compile fine on all platforms.
- No need to make it silcutil/unix/ specific. Add them to generic
- silcutil.c.
-
- o Fix universal time decoding (doesn't accept all forms) in silctime.c.
-
- o silc_stringprep to non-allocating version.
-
- o Compression routines are missing. The protocol supports packet
- compression thus it must be implemented. SILC Zip API must be
- defined.
-
- o Add builtin SOCKS and HTTP Proxy support, well the SOCKS at least.
- SILC currently supports SOCKS4 and SOCKS5 but it needs to be compiled
- in separately.
-
- o bool -> SilcBool (***DONE)
-
- o Silc FD Stream to WIN32 (lib/silcutil/silcfdstream.h)
-
-lib/silcutil/silcbuffer.h ****DONE****
-=========================
-
- o Remove the `truelen' field from SilcBuffer as it is entirely
- redundant since we can get the true length of the buffer by
- doing buffer->end - buffer->header. Add silc_buffer_truelen
- macro instead. Consider also removing `len' field too since
- it effectively is buffer->tail - buffer->data, and adding
- silc_buffer_len macro can do the same. These would save
- totally 8 bytes of memory per buffer. (***DONE)
-
-
-lib/silcutil/silcbuffmt.[ch] ****DONE****
-============================
-
- o SilcStack aware silc_buffer_unformat (***DONE)
-
- o SilcStack aware silc_buffer_format (***DONE)
-
- o silc_buffer_format reallocates automatically (***DONE)
-
- o SILC_STR_OFFSET (***DONE)
-
-
-lib/silcutil/silcstack.[ch] ****DONE****
-===========================
-
- o Data stack implementation (***DONE)
-
-
-lib/silcutil/silcstream.[ch] ****DONE****
-============================
-
- o Add abstract SilcStream. (***DONE)
-
-
-lib/silcutil/silcsocketstream.[ch] ****PARTY DONE****
-==================================
-
- o Add SilcSocketStream (***DONE)
-
- o Add SilcSocketStream for WIN32
-
- o Handle EOS sending to upper layer properly
-
- o Test QoS after the changes made to socket stream
-
-
-lib/silcutil/silcschedule*.[ch] ****PARTLY DONE****
+TODO for SILC Client 1.0 branch
===============================
- o Scheduler can be optimized for FD tasks by changing the fd_queue
- to SilcHashTable instead of using linked list. We need to do
- one-to-one mapping of FD to task and hash table is more efficient
- for this usage.
+ o Bugs reported on the mailing list that will be fixed eventually.
+ The numbers are arbitrary and assigned by me (c0ffee), bugs in
+ parentheses are fixed.
- Also redefine the silc_select to perhaps return a separate
- structure of the events that actually occurred, instead of
- returning the events in the fd_list which is then traversed
- in the generic code to find the changed events. This can be
- made faster by having own struct which includes only the
- changed events, thus the tarversing is faster since the whole
- fd_list is not traversed anymore (it is still traversed in the
- silc_select but at least it removes one extra tarversing later
- for the same list).
+ (#1 Ignore ALL doesn't ignore target using /me)
+ #2 specification of the silc network
+ (#3 expired private key dialogue doesn't work)
+ #4 silc client allows setting non-utf8 topics
+ #5 SILC-client displaying wrong totals with /names
- Other task queues should be changed to use SilcList. (***DONE)
- o Add SILC scheduler's internal routines into a table of implementation
- function pointers, that the generic code then takes as extern from
- implementation. These are the silc_schedule_internal_* routines.
- (***DONE)
-
- o Change SILC_TASK_CALLBACK to non-static, and remove the macro
- SILC_TASK_CALLBACK_GLOBAL. (***DONE)
+TODO for SILC Server 1.0
+========================
- o SILC Schedule API changes to WIN32.
+ o BUG: silc_idlist_del_client had been called but sock->user_data remained
+ and pointed to invalid pointer. Where it was called is not known.
+ o Basic UTF-8 stringprep profile that makes sure UTF-8 strings are
+ as defined in spec-08 section 3.13.
-lib/silcutil/silcasync.[ch] ****DONE****
-===========================
+ o Server sometimes connects more than once to router and keeps
+ connecting even though connection exists.
- o Add SilcAsyncOperation to utility library. Any function that takes
- callback as an argument must/should return SilcAsyncOperation.
- (***DONE)
+ o Testing
-lib/silcutil/silctime.[ch] ****DONE****
+TODO/bugs In SILC Libraries
===========================
- o SilcTime. (***DONE)
-
- o system time, universal, generalized. (***DONE)
-
-
-lib/silcutil/silcfsm.[ch] ****DONE****
-=========================
-
- o SILC Finite State Machine API. Replaces SILC Protocol API (***DONE)
-
-
-lib/silcutil/silcnet*, lib/silcutil/*/silc*net* ****PARTLY DONE****
-===============================================
-
- o Add UDP interface (***DONE)
-
- o Add UDP interface for WIN32
-
- o New network interfaces (***DONE)
-
-
-lib/silcmath
-============
-
- o Import TFM. Talk to Tom to add the missing functions. Use TFM in
- client and client library, but TMA in server, due to the significantly
- increased memory consumption with TFM, and the rare need for public
- key operations in server.
-
- o Change LTM and TFM function names when importing to SILC tree to avoid
- rare linking problems on system that has same named symbols already in
- the system.
-
- o The SILC MP API function must start returning indication of success
- and failure of the operation.
-
- o Do SilcStack support for silc_mp_init, silc_mp_init_size and other
- any other MP function (including utility ones) that may allocate
- memory.
-
- o Test on x86_64.
-
- o All utility functions should be made non-allocating ones.
-
-
-lib/silcutil/symbian/ ****PARTLY DONE****
-=====================
-
- o lib/silcutil/symbian routines missing or not completed.
- (****TESTING NEEDED)
-
- o Something needs to be thought to the logging globals as well,
- like silc_debug etc. They won't work on EPOC. Perhaps logging
- and debugging is to be disabled on EPOC.
-
-
-lib/silcasn1 ****PARTLY DONE****
-============
-
- o ASN.1 library (***DONE)
-
- o Header documentation missing. (***DONE)
-
- o Some string encodings missing (copy/paste matter). (***DONE)
-
- o Negative integer encoding
-
-
-lib/silcpkix
-============
-
- o PKIX implementation
-
-
-lib/silcserver
-==============
-
- o (Re)write commands/command replys.
-
- o (Re)write notify handling.
-
- o The SERVER_SIGNOFF notify handing is not optimal, because it'll
- cause sending of multiple SIGNOFF notify's instead of the one
- SERVER_SIGNOFF notify that the server received. This should be
- optimized so that the only SERVER_SIGNOFF is sent and not
- SIGNOFF of notify at all (using SIGNOFF takes the idea about
- SERVER_SIGNOFF away entirely).
-
- o Another SERVER_SIGNOFF opt/bugfix: Currently the signoff is
- sent to a client if it is on same channel as the client that
- signoffed. However, the entire SERVER_SIGNOFF list is sent to
- the client, ie. it may receive clients that was not on the
- same channel. This is actually against the specs. It must be
- done per channel. It shouldn't receive the whole list just
- because one client happened to be on same channel.
-
- o MAYBE: The SilcChannelClientEntry can be:
- SilcUInt32 address;
- SilcUInt32 mode;
+ o Test cases for all payload encoding and decoding routins in lib/silccore/
- where address is SilcClientEntry address XOR SilcChannelEntry.
- You can get SilcClientEntry by doing client = chl->address XOR channel,
- and SilcChannelEntry by doing channel = chl->address XOR client.
- As long as the other pointer is always available when accessing the
- structure this can be done.
+ o Test cases for math library routines in lib/silcmath/
- o Add reference counters to all Silc*Entry structures
+ o Implement new version of SFTP protocol (missing versions 4 and 5, we
+ have version 3).
- o SERVICEs support (plugin, SIM)
- o If client's public key is saved in the server (and doing public key
- authentication) then the hostname and the username information could
- be taken from the public key. Should be a configuration option!
+TODO in Toolkit Documentation
+=============================
- o Add a timeout to handling incoming JOIN commands. It should be
- enforced that JOIN command is executed only once in a second or two
- seconds. Now it is possible to accept n incoming JOIN commands
- and process them without any timeouts. THis must be employed because
- each JOIN command will create and distribute the new channel key
- to everybody on the channel (Fix this to 0.9.x).
+Stuff that needs to be done in order to complete the Toolkit Reference
+Manual (Do these 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 Write "Programming with Toolkit" document, describing how to build
+ Toolkit, how the build system works, where is everything, how
+ new (external) projects can be glued into Toolkit (use irssi as an
+ example), and how external projects can use Toolkit without gluing into
+ it (how to link etc), debugging, architecture, types, etc.
- o The CMODE cipher & hmac change problem (#101).
+ o Searching of predefined keywords, exact and partial matches (would be
+ nice).
--- /dev/null
+TODO for 1.1 And Beyond
+=======================
+
+lib/silccrypt
+=============
+
+ o Implement the defined SilcDH API. The definition is in
+ lib/silccrypt/silcdh.h.
+
+ o SSH2 public keys support, allowing the use of SSH2 public keys in
+ SILC.
+
+ o OpenPGP certificate support, allowing the use of PGP public keys
+ in SILC.
+
+ o SILC PKCS (silcpkcs.h) reorganizing when other PK supports added.
+ Move the SILC Public Key routines away from the crypto library into
+ the core library (silccore). silc_pkcs_public/private_key_* routines
+ to silc_public/private_key_* routines. The silc_public_key_* routines
+ should also automatically handle SILC Public Keys, and other keys
+ and certificates as well. Add fe. silcpk.h into silccore. It should
+ also include the Public Key Payload encoding and decoding routines.
+
+ o Add DSS support.
+
+ o Cipher optimizations (asm, that this) at least for i386 would be nice.
+
+ o ECDSA and ECDH.
+
+
+lib/silccore/silcpacket.[ch] ****PARTLY DONE****
+============================
+
+ o SilcPacketEngine.
+
+ o New SILC Packet API.
+
+
+lib/silccore/silcid.[ch]
+========================
+
+ o Add silc_id_str2id to accept the destination buffer as argument
+ and thus not require any memory allocation. Same will happen
+ with silc_id_payload_* functions.
+
+ o silc_id_str2id, silc_id2str to non-allocating routines.
+
+
+lib/silcutil
+============
+
+ o Compression routines are missing. The protocol supports packet
+ compression thus it must be implemented. SILC Zip API must be
+ defined.
+
+ o Add builtin SOCKS and HTTP Proxy support, well the SOCKS at least.
+ SILC currently supports SOCKS4 and SOCKS5 but it needs to be compiled
+ in separately.
+
+ o bool -> SilcBool
+
+ o SilcBit, bit field:
+
+ #define SilcBit(b) unsigned int b : 1
+
+
+lib/silcutil/silcbuffer.h ****DONE****
+=========================
+
+ o Remove the `truelen' field from SilcBuffer as it is entirely
+ redundant since we can get the true length of the buffer by
+ doing buffer->end - buffer->header. Add silc_buffer_truelen
+ macro instead. Consider also removing `len' field too since
+ it effectively is buffer->tail - buffer->data, and adding
+ silc_buffer_len macro can do the same. These would save
+ totally 8 bytes of memory per buffer.
+
+
+lib/silcutil/silcbuffmt.[ch] ****PARTY DONE****
+============================
+
+ o SILC_STR_APPEND, _APPEND_TAIL.
+
+ o SILC_STR_OFFSET
+
+
+lib/silcutil/silcstack.[ch] ****DONE****
+===========================
+
+ o Data stack implementation
+
+
+lib/silcutil/silcstream.[ch] ****DONE****
+============================
+
+ o Add abstract SilcStream.
+
+
+lib/silcutil/silcsocketstream.[ch] ****PARTY DONE****
+==================================
+
+ o Add SilcSocketStream.
+
+
+lib/silcutil/epoc/*
+===================
+
+ o lib/silcutil/epoc routines missing or not completed.
+
+ o The PKCS#1 also calls global RNG (even though it is not used
+ currently in SILC, the interface allows its use).
+
+ o Something needs to be thought to the logging globals as well,
+ like silc_debug etc. They won't work on EPOC. Perhaps logging
+ and debugging is to be disabled on EPOC.
+
+
+lib/silcutil/silcschedule*.[ch]
+===============================
+
+ o Scheduler can be optimized for FD tasks by changing the fd_queue
+ to SilcHashTable instead of using linked list. We need to do
+ one-to-one mapping of FD to task and hash table is more efficient
+ for this usage.
+
+ Also redefine the silc_select to perhaps return a separate
+ structure of the events that actually occurred, instead of
+ returning the events in the fd_list which is then traversed
+ in the generic code to find the changed events. This can be
+ made faster by having own struct which includes only the
+ changed events, thus the tarversing is faster since the whole
+ fd_list is not traversed anymore (it is still traversed in the
+ silc_select but at least it removes one extra tarversing later
+ for the same list).
+
+ Other task queues should be changed to use SilcList.
+
+ o Add SILC scheduler's internal routines into a table of implementation
+ function pointers, that the generic code then takes as extern from
+ implementation. These are the silc_schedule_internal_* routines.
+
+ o Change SILC_TASK_CALLBACK to non-static, and remove the macro
+ SILC_TASK_CALLBACK_GLOBAL.
+
+
+lib/silcutil/silcasync.[ch] ****DONE****
+===========================
+
+ o Add SilcAsyncOperation to utility library. Any function that takes
+ callback as an argument must/should return SilcAsyncOperation.
+
+
+lib/silcutil/silctime.[ch] ****DONE****
+===========================
+
+ o SilcTime.
+
+ o system time, universal, generalized.
+
+
+lib/silcmath
+============
+
+ o The SILC MP API function must start returning indication of success
+ and failure of the operation.
+
+ o Do SilcStack support for silc_mp_init, silc_mp_init_size and other
+ any other MP function (including utility ones) that may allocate
+ memory.
+
+ o All utility functions should be made non-allocating ones.
+
+
+lib/silcasn1 ****PARTLY DONE****
+============
+
+ o ASN.1 library
+
+ o Header documentation missing.
+
+ o Some string encodings missing (copy/paste matter).
+
+
+lib/silcpkix
+============
+
+ o PKIX implementation
+
+
+lib/silcutil/silcfsm.[ch]
+=========================
+
+ o SILC Finite State Machine API. Replaces SILC Protocol API,
+ (see ~silcfsm or ask Pekka).
+
+
+lib/silcutil/silcnet*, lib/silcutil/*/silc*net*
+===============================================
+
+ o Add UDP interface
+
+ o New network interfaces
+
+tyepdef enum {
+ SILC_NET_OK,
+ SILC_NET_UNKNOWN_IP,
+ SILC_NET_UNKNOWN_HOST,
+ SILC_NET_HOST_UNREACHABLE,
+ SILC_NET_CONNECTION_REFUSED,
+ SILC_NET_CONNECTION_TIMEOUT,
+ SILC_NET_NO_MEMORY,
+ SILC_NET_ERROR,
+} SilcNetStatus;
+
+/* A callback function of this type is returned by silc_net_create_server
+ and silc_net_create_connection_async. For silc_net_create_server this
+ callback means that new incoming connection was accepted, and the
+ `stream' is the socket stream representing the socket connection. For
+ silc_net_create_connection_async this means that we have connected to
+ the remote host and the `stream' is the socket stream for the socket
+ connection. */
+typedef void (*SilcNetCallback)(SilcNetStatus status,
+ SilcStream stream, void *context);
+
+typedef SilcNetServerStruct *SilcNetServer;
+
+struct SilcNetServerStruct {
+ SilcNetCallback callback;
+ void *context;
+ int sock;
+ bool require_fqdn;
+};
+
+/* This function creates server or daemon or listener or what ever. This
+ does not fork a new process, it must be done by the caller if caller
+ wants to create a child process. This is used to create network
+ listener for incoming connections, and `callback' will be called
+ everytime new connection is received. If `local_ip_addr' is NULL
+ any address is used. If provided it can be used bind the server to
+ `local_ip_count' many IP addresses provided in `local_ip_addr' table.
+ On success returns the SilcNetServer context, or NULL on error. If
+ `require_fqdn' is TRUE the server will require that the incoming
+ connection has FQDN to be able to connect. */
+SilcNetServer
+silc_net_create_server(const char **local_ip_addr, SilcUInt32 local_ip_count,
+ int port, bool require_fqdn, SilcSchedule schedule,
+ SilcNetCallback callback, void *context);
+
+/* Closes the server indicated by the `server'. */
+silc_net_close_server(SilcNetServer server);
+
+/* Creates TCP/IP connection to the remote host indicated by `remote_host'
+ which may be hostname or IP address, on the port indicated by `remote_port'.
+ If the `local_ip_addr' is provided the local host is bound to that address
+ before creating the connection. This is synchronous call, and the
+ `callback' is called before this function returns. The `callback'
+ delivers the SilcStream for the created connection. */
+SilcNetStatus
+silc_net_create_connection(const char *local_ip_addr,
+ const char *remote_host, int remote_port,
+ SilcNetCallback callback, void *context);
+
+/* Creates TCP/IP connection to the remote host indicated by `remote_host'
+ which may be hostname or IP address, on the port indicated by `remote_port'.
+ If the `local_ip_addr' is provided the local host is bound to that address
+ before creating the connection. This is asynchronous call, and this
+ function returns before the connection is actually established. The
+ `callback' will be called after the connection is created to deliver the
+ SilcStream for the created connection. */
+SilcAsyncOperation
+silc_net_create_connection_async(const char *local_ip_addr,
+ const char *remote_ip_addr, int remote_port,
+ SilcNetCallback callback, void *context);
+
+
+ o Other functions should remain as they are since these new functions have
+ to use them. This way we also provide them for applications that want
+ 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.
+
+ o The SERVER_SIGNOFF notify handing is not optimal, because it'll
+ cause sending of multiple SIGNOFF notify's instead of the one
+ SERVER_SIGNOFF notify that the server received. This should be
+ optimized so that the only SERVER_SIGNOFF is sent and not
+ SIGNOFF of notify at all (using SIGNOFF takes the idea about
+ SERVER_SIGNOFF away entirely).
+
+ o Another SERVER_SIGNOFF opt/bugfix: Currently the signoff is
+ sent to a client if it is on same channel as the client that
+ signoffed. However, the entire SERVER_SIGNOFF list is sent to
+ the client, ie. it may receive clients that was not on the
+ same channel. This is actually against the specs. It must be
+ done per channel. It shouldn't receive the whole list just
+ because one client happened to be on same channel.
+
+ o MAYBE: The SilcChannelClientEntry can be:
+ SilcUInt32 address;
+ SilcUInt32 mode;
+
+ where address is SilcClientEntry address XOR SilcChannelEntry.
+ You can get SilcClientEntry by doing client = chl->address XOR channel,
+ and SilcChannelEntry by doing channel = chl->address XOR client.
+ As long as the other pointer is always available when accessing the
+ structure this can be done.
+
+ o Add reference counters to all Silc*Entry structures
+
+ o SERVICEs support (plugin, SIM)
+
+ o If client's public key is saved in the server (and doing public key
+ authentication) then the hostname and the username information could
+ be taken from the public key. Should be a configuration option!
+
+ o Add a timeout to handling incoming JOIN commands. It should be
+ enforced that JOIN command is executed only once in a second or two
+ seconds. Now it is possible to accept n incoming JOIN commands
+ and process them without any timeouts. THis must be employed because
+ each JOIN command will create and distribute the new channel key
+ to everybody on the channel (Fix this to 0.9.x).
+
+ o The CMODE cipher & hmac change problem (#101).
-Wed Feb 21 15:45:50 EET 2007 Pekka Riikonen <priikone@silcnet.org>
+Wed Nov 16 17:53:55 EET 2005 Pekka Riikonen <priikone@silcnet.org>
- * Autodist 1.3.1.
-
-Sat Jun 24 23:38:24 EEST 2006 Pekka Riikonen <priikone@silcnet.org>
-
- * Match distdef names exactly (/^foo$/ instead of /^foo/).
+ * Don't try to log with -s option.
Wed May 4 10:58:24 EEST 2005 Pekka Riikonen <priikone@silcnet.org>
# This also handles the #ifdef's #else (ie. #ifndef) branch.
if test x$found = xfalse; then
ad_debug "ifdef $d will be excluded (it is NOT defined)"
- echo "/^#ifdef $d$/,/^#else !$d$|^#endif $d$/ { next; }" >> $f
+ echo "/^#ifdef $d/,/^#else !$d|^#endif $d/ { next; }" >> $f
else
- echo "/^#else !$d$/,/^#endif $d$/ { next; }" >> $f
+ echo "/^#else !$d/,/^#endif $d/ { next; }" >> $f
fi
done
# This also handles the #ifndef's #else (ie. #ifdef) branch.
if test x$found = xtrue; then
ad_debug "ifndef $d will be excluded (it IS defined)"
- echo "/^#ifndef $d$/,/^#else $d$|^#endif $d$/ { next; }" >> $f
+ echo "/^#ifndef $d/,/^#else $d|^#endif $d/ { next; }" >> $f
else
- echo "/^#else $d$/,/^#endif $d$/ { next; }" >> $f
+ echo "/^#else $d/,/^#endif $d/ { next; }" >> $f
fi
done
# This also handles the #ifdef's #else (ie. #ifndef) branch.
if test x$found = xfalse; then
ad_debug "ifdef $d will be excluded (it is NOT defined)"
- echo "/^#ifdef $d$/,/^#else \/\* \!$d |^#endif \/\* $d / { next; }" >> $f
+ echo "/^#ifdef $d/,/^#else \/\* \!$d|^#endif \/\* $d/ { next; }" >> $f
else
- echo "/^#else \/\* \!$d /,/^#endif \/\* $d / { next; }" >> $f
+ echo "/^#else \/\* \!$d/,/^#endif \/\* $d/ { next; }" >> $f
fi
done
# This also handles the #ifndef's #else (ie. #ifdef) branch.
if test x$found = xtrue; then
ad_debug "ifndef $d will be excluded (it IS defined)"
- echo "/^#ifndef $d$/,/^#else \/\* $d |^#endif \/\* $d / { next; }" >> $f
+ echo "/^#ifndef $d/,/^#else \/\* $d|^#endif \/\* $d/ { next; }" >> $f
else
- echo "/^#else \/\* $d /,/^#endif \/\* $d / { next; }" >> $f
+ echo "/^#else \/\* $d/,/^#endif \/\* $d/ { next; }" >> $f
fi
done
-s | --distdefs)
shift;
+ nolog=true
if test $# -eq 0; then
ad_parse_distribution $distribution false
echo "Distribution: ${distribution}" 1>&2;
-Original code:
-
- Timo Sirainen <cras@irssi.org>
-
-Irssi staff (current maintainers) <staff@irssi.org>:
-
- Valentin Batz (senneth, vb)
- Wouter Coekaerts (coekie)
- Jochen Eisinger (c0ffee)
- Geert Hauwaerts
- Emanuele Giaquinta (exg)
-
-Large feature patches by:
-
- David Leadbeater (dg, dgl) : isupport
- vjt@users.sf.net : SSL support
- Joel Eriksson : SSL certs
- Heikki Orsila : DCC SEND queueing
- Mark Trumbull : DCC SERVER
- Francesco Fracassi : Passive DCC
-
-Other patches (grep for "patch" in ChangeLog) by:
-
- Toby Peterson
- Soren Jacobsen
- Kuang-che Wu
- Joost Vunderink (Garion)
- Wang WenRui
- Jean-Yves Lefort (decadix)
- Joel Eriksson
- Maarten van der Zwaart
- Noah Levitt
- Krzysztof Kowalik (Borys)
- Peder Stray
- mls@suse.de
- nix@suhs.nu
- Marcin Kowalczyk (Qrczak)
- Petr Baudis
- Bjoern Krombholz (fuchs)
- aldem-irssi@aldem.net,
- BC-bd
- Juerd
- Han
- pv2b
- Tommi Komulainen (tommik)
- mike@po.cs.msu.su
- zinx@magenet.net
- yathen@web.de
- paul@raade.org
- Leszek Matok
- tygrys@moo.pl
- manoj@io.com
- cph@cph.demon.co.uk
- ganesh@earth.li
- Jakub Jankowski (shasta)
- vanilla@freebsd.org
- Tinuk
- Mark Glines
- Kjetil Ødegaard
- Chris Moore
- ComradeP
- Jilles Tjoelker
- Lauri Nurmi
- Mikko Rauhala
- loafier
- Nicolas Collignon
- Daniel Koning
+Timo Sirainen <cras@irssi.org>
-v0.8.11 200x-xx-xx The Irssi team <staff@irssi.org>
- + Send /QUOTE immediately if server didn't send the 001 event yet
- + If dcc_own_ip contains IPv4 address, listen only in IPv4
- + Negative scroll_page_count scrolls screensize-n lines
- (Patch by Chris Moore)
- + Sort nicks with custom prefix by the order defined in isupport in /NAMES
- + New perl command send_raw_first, patch by ComradeP (Bug 413)
- + Let the module loader also check for fe_common_$protocol files
- + Don't wait for all /NAMES replies before syncing if we can't combine
- queries anyways (Patch by jilles)
- + Renamed irc.efnet.net to irc.efnet.org
- + Add support for utf8 to Irssi::settings_get_str and
- Irssi::TextUI::Line::get_text
- + /SCROLLBACK CLEAR accepts the same arguments as /CLEAR
- + Check if binary exists and can be executed before /UPGRADE
- + Change default value of override_coredump_limit to OFF
- + UPTIME command by Lauri Nurmi with some modifications (Bug 458)
- + Remove CR and LF from Perl commands, to make it harder to introduce a
- security bug
- - Fixed segfault on quit introduced in 0.8.10
- - Fixed a bug where tab-complete didn't worked with utf8/big5 properly
- - Ignore joins without a nick from broken servers
- - Fix whois_hide_safe_channel_id: only look at the beginning of a channel
- name, not in the middle
- - Don't assume that 7bit ascii strings are encoded in UTF-8, only
- validate the strings when they contain octest with highest bit set
- (patch by Mikko Rauhala)
- - Make random really random when resolving
- - Don't get confused by a join command with too many arguments, keys
- can't have spaces in them (Bug 437)
- - Don't crash on /QUIT with scripts causing and catching signals on UNLOAD
- - Fix off-by-one error in gui_entry_draw_from
- - Fix %k and %K mappings in curses frontend
- - Fix bold on monochrome terminals in terminfo frontend
- - Fixed colors with TERM=xterm-{88,256}color in terminfo frontend
- - Fix building with srcdir != builddir
- - Don't get confused and keep saying "Netsplit over" on every join for
- user that only rejoined some channels
- - Fix crash with one line high terminal
- - Fix crash in /EXEC (Bug 439)
- - Fix format string in printtext_dest call from Perl, patch by loafier
- - Fix memory leaks in expandos_deinit by Nicolas Collignon (Bug 419)
- - Detect off_t size using AC_CHECK_SIZEOF because it works also when
- cross-compiling in autoconf-2.50 and higher
- - Fix failed assertion when the config file is unreadable, patch by
- Daniel Koning (Bug 164)
-
-v0.8.10 2005-12-11 The Irssi team <staff@irssi.org>
-
- * Long delayed release, with lots of changes. Most important ones:
- + Recode support, by decadix and senneth
- + isupport (005 numeric), by David Leadbeater
- + Passive DCC support, by Francesco Fracassi
- - Many memleak fixes, by Toby Peterson
-
- + Moved to subversion
- + /SET paste_join_multiline ON - When paste detection is enabled and
- you paste lines which look like they're being copy&pasted from irssi
- itself, it attempts to merge lines said originally in a single line.
-
- How this really works is that all indented lines must have the same
- amount of indentation. Indented lines are merged to last
- unindented line. If line gets longer than 400 characters, it's split.
- + /SET whois_hide_safe_channel_id ON - Hides the channel ID prefix
- of !channels in WHOIS replies
- + When reconnecting to server, say that it can be aborted with
- /RMRECONNS
- + /WHOIS -<server tag> is supported now
- + /SET whois_hide_safe_channel_id - removes the ugly IDs for !channels
- in /WHOIS (default)
- + If we can't connect to server using given own IP, show the IP to
- user in the error message. Should help figuring out wrong
- /SET hostname or /SERVER -host settings.
- + If channel has more nicks than /SET channel_max_who_sync, don't ask
- /WHO list to avoid getting kicked out of server (Max SendQ exceeded).
- + /LOAD script.pl loads the perl script
- + /IGNORE -network ignores only on specified network
- + /SET use_status_window and /SET use_msgs_window make the effects
- immediately
- + Changed the confusing "ircnet" to "network" everywhere
- + Don't autoget files sent to channels, unless dcc_autoget_masks is set
- + Added a default "*" target which matches everything on the server,
- including NULL items associated with it, by jimmy
- + /UPGRADE now saves server->version
- + If available, send who set topic and when to irssi-proxy clients
- + Cleaned up network list: removed smaller networks, added QuakeNet
- + New default aliases: MANUAL-WINDOWS, EXEMPTLIST and ATAG
- + Recode support: /RECODE for manipulation of the conversion database.
- Setting "term_type" has been renamed to "term_charset".
- /SET recode OFF to disable recode completely.
- /SET recode_out_default_charset <charset> to specify the default
- outgoing charset.
- /SET recode_fallback <charset> to specify a charset that will be
- used when the normal conversion is failing.
- /SET recode_transliterate ON to enable character transliteration,
- so unavailable characters will be transliterated into something
- readable
- <charset> can be almost everything listed by 'iconv -l'
- + Added transpose_words, capitalize_word, downcase_word, upcase_word
- key bindings
- + Avoid accidentaly /VER in a channel, by requiring parameter
- - Pasted lines weren't added to command history. Some other paste
- detection fixes
- - Fixed /BIND escape_char
- - Fixes for Chinese multibyte characters handling and cursor movement
- by Wang WenRui
- - Pasting multibyte chars was buggy, patch by Kuang-che Wu
- - Fixed handling WHOIS printing once and for all. Everything unknown
- between "beginning of whois" and "end of whois" events is now printed
- as whois_special. Removed whois_registered and whois_help, they're
- printed with whois_special as well.
- - Don't replace channel key when receiving channel mode numeric. It
- could be a fake key there.
- - Don't crash if dcc chated user changes nick
- - Help files are always lowercased. Make sure /HELP COMMAND works too.
- - /EXEC crashed with 64bit systems. Patch by Soren Jacobsen
- - Handle 432 numeric (errorneus nickname) as "nick in use". Fixes
- problems with ircnet 2.11 ircd when irssi tries to reconnect using
- UID as nick. Patch by Petr Baudis
- - /SET -default fixes
- - /DCC SEND didn't actually use /SET dcc_upload_path
- - Fixed /WHOIS -yes (Bug 67)
- - Make /JOIN -tag #channel and /JOIN #channel<space> switch to that
- channel (Bugs 13 and 93)
- - Fixed readded (changed) hilights being in config twice, resulted in
- duplicate hilights or removed hilights coming back (Bug 39)
- - Fixed messages to @#channel showed *your* nickmode, not the one of
- the sender (part of Bug 80)
- - Fixed /KNOCK support
- - Fixed own nick changes in irssi-proxy
- - Fixed /HILIGHT -actcolor -mask (Bug 131)
- - Recognise a param of signal_emit/continue in perl script if it's int
- - Fixed bug 120 where proxy doesn't set the server_rec->away_reason
- - Fixed /join -invite -window bug if there is no invite
- - Fixed bug with time settings where hours actually returned 60*hours
- - Fix multiple entries for local IP in /etc/hosts prevents connecting,
- patch by eridius (Bug 167)
- - Fixed a bug with /me, use the right arguments for
- "message irc own_action"
- - Update our own nickrec->gone flag on /away <reason> or on /away
- - Fixed output of /hilight (add a space after -levels if any)
- - Add libtool's -module flag to get built properly on all platforms,
- by Toby Peterson (Bug 212)
- - Don't apply emphasis on _foo_^ if it's a nick (Bug 52)
- - Fix displaying of ctcp userinfo and clientinfo (Bug 222)
- - Remember alternate_nick and max_whois on reconnect (Bug 181)
- - Fix tr_TR locale problem for glib2 (still a bug with glib1.2)
- by David Pashley
- - Fixed pasting not using the character translation (Bug 151)
- - Fixed a bug where the channel list to join/rejoin on reconnect
- gets too long, not all channels will be joined. (Bug 108)
- - Print glib errors nicely, by David Pashley
- - Handle ^Z better, by David Pashley
- - Fixed /eval recursion crashing, by David Pashley
- - Fix notify with more nicks than max_whois_in_cmd (Bug 257),
- based on patch by Krzysztof Kowalik (Borys)
- - Fixed irssiproxy sometimes missing (parts of) lines
- - Fixed remote /WHOWAS
- - Parse negative time setting values, makes it possible again to do
- /SET server_reconnect_time -1 to disable reconnecting
- - Compile with gcc4
- - Compile with readonly srcdir
- - Fixed crash if receiving broken privmsg without source
- (which bitlbee can send if you msg yourself)
- - Fixed crash with invalid TERM and termcap
- - When looking up IP addresses, return random IP instead of the first one
-
-v0.8.9 2003-12-11 Timo Sirainen <tss@iki.fi>
-
- * Fixes a remote crash with:
- a) non-x86 hardware (one requiring memory alignmentation)
- b) script using "gui print text" signal (with x86 hardware too)
-
- + /SET auto_whowas OFF allows now disabling automatic /whowas when
- /whois doesn't find a nick (by Borys)
- - If pasted line starts with command char, treat it as command always.
- Paste detection can go on too easily with lagged connections.
-
-v0.8.8 2003-11-23 Timo Sirainen <tss@iki.fi>
-
- - Just a few fixes to converting old settings automatically
-
-v0.8.7 2003-11-23 Timo Sirainen <tss@iki.fi>
-
- * Settings changes - we have now "time", "size" and "level" setting
- types.
- - Level settings should work the same as before.
- - Time settings can have units: days, hours, mins, secs,
- milliseconds (or msecs). The units can be combined and written
- in shorter form as well, for example "5d 30m 10ms"
- - Size settings can have units: gbytes, mbytes, kbytes, bytes.
- They can be written in shorter form as well, eg. "gb" or "g".
-
- Your existing settings should be converted automatically.
-
- + Pasting detection. All keys except CR and LF are pasted as-is into
- prompt in pasting mode.
-
- /SET paste_detect_time controls how closely each others characters
- must occur for it to be considered pasting. Paste mode goes on when
- first pasted CR/LF is found.
-
- The first line may also contain some command characters. They are
- executed, but their action in entry line is reverted once pasting
- is detected.
-
- What this means in practise is that even if you have TABs (assuming
- TAB is completion key) in the first pasted line, they get pasted as
- TABs.
-
- This detection isn't perfect, so if it annoys you it can be disabled
- with /SET paste_detect_time 0
- + If pasting more lines than /SET paste_verify_line_count, irssi asks
- if you actually want to do that. This should be useful to prevent
- accidental copy&paste mistakes. Setting it to 0 disables this
- entirely.
- + Support for sending SSL certificate to server and optionally verify
- server's certificate. See the -ssl_* options for /SERVER and
- /SERVER ADD. Patch by Joel Eriksson.
- + DCC SERVER support by Mark Trumbull
- + Support for DCC sending larger files than 2GB if supported by
- operating system (ie. 64bit file support). Receiving has always
- been possible, but the statistics were wrong with >4GB files
- if 64bit support isn't enabled.
- + Better displaying of DCC file transfer statistics.
- - Several other minor fixes and enhancements, see ChangeLog
-
-v0.8.6 2002-11-17 Timo Sirainen <tss@iki.fi>
-
- * Tons of changes, here's only the largest that come to my mind now:
-
- + SSL support by vjt@users.sf.net
- + DCC send queues by Heikki Orsila
- + Better support for !channels
-
v0.8.4 2002-03-13 Timo Sirainen <tss@iki.fi>
* Continuing to fix my stupid mistakes...
- - /whowas server nick doesn't work
-01:18 <@darix> cras: /foreach server /disconnect $tag n8 <-- doesnt work
- - /hilight -priority is broken
-19:36 [IRCNet] [muzzy] lisää bugeja irssissä, ilmeisesti
- uusin versio: foo splittaa ulos, bar joinaa sisään, bar vaihtaa
- nicknamen fooksi, foo splittaa uudestaan ulos -> tulee Glib warning
- "is already in split list (how?)" .. :)
-
-04:35 [OPN] [slug] was just wondering if you
- had Irssi::keyboard_entry_redirect() on your TODO somewhere near the
- top, I'd love the feature
-04:35 [OPN] [slug] or someway to clear the
- command buffer, either way is acceptable, just my connection is a
- little less than reliable, so I've built myself a script that stores
- blowfish passes, all encrypted by one value
-04:36 [OPN] [slug] then I set a single
- decryption key, and it keeps it for the irssi session (lost on
- /upgrade though), unfortunatly it stays in the command buffer 8]
-
- - ^I in topicbar breaks things
-14:17 <@darix> cras: this doesnt work: /exec - -o uname -a
-
- - "setup changed", or "setup reread" seems to cause crashes.. (with darix)
-02:46 <@fuchs> cras, /server foonet.foo.xy and (recognizing it doesn't connect
- fast enough), and so doing /server barnet.foo.xy (both in the
- same chatnet) makes irssi joining the net but not rejoining the
- channels
-
-
-14:59 <@c0ffee> cras, bug report, mode change compression appears not to work:
- 13:58 -!- mode/#*cut* [-b+ *cut*] by *cut* (i think it was -b+b)
-21:55 <@L> 17:04.11 <L> /eval /last quit;/clear;/sb goto 10:00;/last -clear;/sb end
-21:55 <@L> 17:04.27 <L> wait after it scrolls and press page up :)
-21:55 <@L> 17:04.48 <L> oh, you can make Irssi behave correctly with /clear
- again
-
- - /msg nick@server or nick%host is fully treated as nickname (log, query)
- - max_whois won't stay with reconnects?
- - support passive DCC
- - separate format for privmsg/notice massmessages (anything non-yournick)
-20:45 < Juerd> 19:44 -!- Irssi: critical file channels.c: line 122
- (channel_find): assertion
-20:45 < Juerd> `name != NULL' failed.
-20:45 < Juerd> this happens three times
-20:46 < Juerd> and it happens in a _query_
-20:47 <@Juerd> cras: for some reason irssi doesn't know this happens in a
- query, and displays "< Juerd:> foo" in the status window
- - set TOS field for all connections (DCC especially)
-22:51 [IRCNet] [zhafte] irssi muuten taitaa bugaa jos
- pistää ACT oikeaan reunaan, vai onkohan se vain mun terminaali?
-22:52 [IRCNet] [zhafte] menevät välillä päällekkäin
- numerot
- - when using -w password command line parameter, hide the password so it
- won't show with ps.
-07.06.2002 08:37 #irssi: <@Qrczak> cras: A bug. After /upgrade when being away
- the awaylog is not being written to.
-21:37 < life> Then you connect. The problem is that irssi connects to the proxy
- server and directly afterwards send "USER ..."
-21:37 < life> It has to wait for "HTTP 200 ok" *first*
-04.06.2002 08:54 #irssi: <@Garion> cras: i've seen it several times now - a
- line of 79 or 80 chars (my win is 80 wide)
- which has an empty line below it, and that
- line is not refreshed when I switch to the
- window with that line in it, thus keeping 1
- line from the old window in the current
- window. Very confusing
-21:43 [IRCNet] [HiroP-(~HiroP@p508035EC.dip.t-dialin.net)] Hi there. I just
- wanted to tell you that there seems to be a problem when joining
- large channels (500+ people) while a regexp ignore is active. I had
- one to ignore all server ads
-21:43 [IRCNet] [HiroP-(~HiroP@p508035EC.dip.t-dialin.net)] 1 *: ALL -regexp
- -pattern .*erver.*nline.*
-21:43 [IRCNet] [HiroP-(~HiroP@p508035EC.dip.t-dialin.net)] After joining, I
- could see the nicklist and 1 or 2 lines of what people were saying.
- Then irssi either core-dumped, got disconnected or just sat there
- apparently without receiving any more data (lag-counter going up to
- several minutes).
-
- - %n%_ ei näy lastlogissa
- - darixin se pingiredirectijuttu
-21:28 < Samus_Aran> cras: /log also shows #Linuux ... which I typod a couple
- days ago
-21:30 < Samus_Aran> it doesnt show any of the queries which i closed, though,
- jush #channels
-
- - "show statusbar in empty windows" flag?
- - statusbar_item_redraw() should just set the size as dirty and calculate
- it only when really needed.
- - possible to cache sbar_item->size when nothing else has changed in sbar?
- ie. mostly when redrawing.
- - use_status_window, use_msgs_window sais toimia heti
- - /msg @#chan<tab>
-
- - hilight -priority
- - tab completio jos lisää utf8 juttuja niin ei oikein toimi?
-16:39 <@Qrczak> cras: I'm not sure how exactly to reproduce it but it happens
- often. When I jump to the window with a query using Alt-a
- (after the other person said something), and close the window
- (being brought to the last used window), and don't switch
- windows, and then that person says something again, I'm brought
- to the new query window automatically (that's of course bad).
-
-21.04.2002 11:59 [immy(immy@beanus.org)] GLib warning: signal_free(script
- destroyed) : signal still has 3 references:
- - jos kickataan nopeasti ja joinaa takas nopeasti chansyncci kaataa
-/WHOssa.. kts. qrczak logi
- - /set show_server_tags tjsp että näyttäis aina (yhdistä hide_server_tagsin
- kanssa?)
-17:35 <@peder> cras: why isnt 'topic = " {sb_topic $topic}"' in the default
- - /SBAR topic placement bottom ei toimi??
- - /SB GOTO -<days> <ts>
- - /query -immortal so autoclose_queries wouldn't touch them
- - /SET hiascii_control_chars if 128..128+32 should be treated as control chars
-
-...
-
- - /exec -out kanavalla ei pelaa silcissä
- - write about %[-s] etc. to default.theme
- - away handling is a bit buggy. you do /away;/away reason, irssi remembers
- the away reason only until it receives "you're no longer away" from the
- first command.. setting it back to away has then lost the reason.
- - crash: /exec -msg safari perl -e 'print "A"x600000'"
- - nick_ nick- _nick nick2 nick3 ...
-17.03.2002 22:25 #irssi.fi: <@Ion> cras: Jos sanon dcc chatissa että /exec -
- -out cat iso_tiedosto, niin miksi
- iso_tiedosto jää kesken? :)
- - /op * valitus vois olla joku parempi kuin "not a good idea"..
- - mitenkäs tabcompletio completoi taas omaakin nickkiä..?
- - /hilight -level "public -actions" or something so it wouldn't match
- actions.
- - vanhan irssin /upgrades uuteen ennen sitä vaihtoi /set autolog_path:iin
- $1 ja kaatui?..
- - /win hide vois pelata vaikka oliskin stickyjä siinä ikkunassa
- - /SAVE -all?
-14.03.2002 19:10 #irssi: <@fantazja> cras: autoclose_query is also closing (and
- finishing) dcc chats :/
- - /window server -sticky:tetyt ikkunat ei aina meinaa tajuta kun serveri
- yhdistyy?
- - utf8-tekstitykset bugailee statusbarissa (promptissa)
- - jos /set reuse_unused_windows off, ja ikkuna näyttäis täysin tyhjälle
- ja niitä olis vaan 1, niin sen vois kyllä käyttää silti (?)
- - /set beep_msg_level hilight ei toimi jos on /hilight -word
-
- - /STATUSBAR xx ENABLE|DISABLE recreates all statusbars which is a bit
- annoying because some scripts want to do it and input line is cleared
- because of this..
- - move /SET hilight_*color to theme
- - /SET disconnect_timeout - default 2min, 0 = immediately
- - reconnecting messages are a bit confusing. it prints "removed reconnection"
- to the server which it's connecting to next.. maybe the whole reconnecting
- thing should work so that the record stays there until it's connected
- successfully.
- - /ignore, /hilight and /lastlog could complain immediately if used
- regexp is broken. /hilight list could show also if it's broken like
- /ignore does.
-
- /UPGRADE:
- support DCCs
+ - topic time/nick isn't transferred
- rewrite to work by fork()ing a new process and transfer file handles
with unix sockets. this would allow the scrollback buffers to be
transferred with them as well.
- but DCC chats shouldn't be closed until the chat itself is closed
- which we can't know really currently, since they don't need
to be in queries
- - channels should be closed when they're left (they are now, but)
+ - channels should be closed when they're left
- /WINDOW CLOSE shouldn't close it immediately, since we'll still
receive at least the PART message
- so, log items should know more about what they are exactly, and when
- support for using strftime() formats (and $tag etc). only problem with
this is that all the different awaylogs would need to be tracked and
/CATed when setting yourself unaway
- - /AWAYLOG could show the current awaylog and optionally reset it
- - The channel name should be optional there
- Window item placing:
- !channel vs. !12345channel. it's layout saved with full name, but joined
the query window with the dcc chat window.
- closed DCC chats should add temporary window bind to the dcc chat so
future chats for same nick would use the same window
- - /JOIN #foo could *optionally* move the channel to active window
- (default off, it confuses people)
- - /JOIN -ircnet #foo doesn't jump to #foo like /JOIN #foo does.
- DCC
- /DCC SEND wildcard support
- /DCC CLOSE #, /DCC would print the IDs
- /SET dcc_use_proxy to use IRC proxy for DCC connects as well
- support for special vars in /SET dcc_download_path, so $N could be used
- - No way to autoclose dcc chat windows which have been closed by another
- side.
- Generic chat commands:
- /MSG /CTCP /ACTION =dcc_chat,#channel
maybe some multipeople query support? :) /query nick1,nick2 and sending
text there would send it to both. Seems to work already but receiving
messages from either nick1 or nick2 don't go to that window..
+ - /^MSG nick creates query with /SET qutocreate_own_query YES
+ - /WHOIS -servertag
- /BAN: setting of what netmask to use for banning with IPv6 addresses
- Netsplits
- Irssi proxy:
- doesn't propagate your own nickchanges to other clients
- - list sessions, kill them
- - /set irssi_proxy_ips <allow connections only from specified IPs>
+ - better support for CTCP replies / DCC
- Misc IRC related things:
+ - better support for !channels (don't log the ID, show nicer in whois,
+ layout save doesn't work, /win item move !channel)
- support for mode +q in dancer - also same as +b %xxx modes..
- properly support RFC-1459 charset (ircnet specific option), eg.
/QUERY p[ and msgs from p{ aren't placed there.
- /BAN -ip, -time [<time>] (/ALIAS knockout?)
- /KICKBAN to support same options than /BAN (would /ALIAS kickban work?)
- ban list prints "x seconds ago" .. should be x days, mins, hours, ..
+ - /WALL could maybe check if server supports /WALLCHOPS or @#channel?
+ maybe too much trouble figuring out if it can or not.
- Windows:
- /WINDOW SIZE -sticky, so f.e. /WINDOW BALANCE wouldn't affect it.
- /BIND -deletes should be saved in config
- ^W (and some others) don't update cut buffer.
- default binds: M-d, M-y
+ - capitalize-word (meta-c), downcase-word (meta-l),
+ transpose-words (meta-t), upcase-word (meta-u)
+ - UTF-8 support
- /PASSWORD command that asks you to type the password to entry line and
would hide it with asterisks, good if people spy on you :)
- ^R-like history search
- - Key to execute the command, but not place it in history
- - Key to remove active entry from command history
- - Optionally save command history between restarts
- Notify list:
- showing who's online and who's offline doesn't work properly.
user comes to irc.
- "Should we check people in notify list when you're away" option
- use /WATCH instead of /ISON in servers that support it
- - Show when the nick was last seen
- Ignores:
- /IGNORE -ircnet or -tag
not hide the text.
- The nick cache stuff just made it slower. Remove it or figure out how
it could be faster.
- - combined ignore/hilight thingy, see hilights
- Hilights:
- /HILIGHT list doesn't print several options. Maybe some generic
- automatic nick hilighting at beginning of line should be optional,
like some people would want -word hilighting in it..
- exceptions
- - Merged ignores/hilights thingy and maybe even something others ..
- some first-match-wins table where you could easily add/move stuff.
- Scrollback:
- Optionally show a "bookmark" (line mark actually, a line full of '-'
- Fix the flood protection to be aware of max. input buffer, which is
1024 bytes by default (/STATS d, CF). Now irssi may excess flood when
sending lots of lines longer than ~200 chars.
- - IRCNET: Flood protection doesn't count the extra penalty for MODEs
- and KICKs, also extra penalty should be given in messages (all
- commands?) for each 100 chars.
+ - Flood protection doesn't count the extra penalty for MODEs and KICKs
+ in ircnet.
- Text buffer:
- support for printing ALL characters in text buffer, including ^B, ^C,
- /STATUSBAR prompt DISABLE hangs irssi because there's no input line.
Add some check to not allow this.
- /STATUSBAR could list also disabled bars
- - command to list all available statusbar items
- Server connecting:
- More verbose connecting
- bash-style (or whatever it should be called) tab-completion
- key for reverse completion
- /MSG <tab> completion shouldn't include queried nick there (optional)
+ - nick completion shouldn't try completing nicks everywhere,
+ like /SET <tab>
- File completion could guess when it's wanted, word beginning with /
(not at start of line of course, unless / isn't in cmdchars)
or ~/ or ./
- filename completion doesn't work properly if path has spaces
- - /FORMAT xx <tab>
- - don't add useless completions to list. eg /RUN nick<tab> shouldn't
- work
- - Priorities to completions. And at least command completion could use
- it so it'd put last the commands that require chanops/ircops.
- Requires support in command_bind().
- - /DCC commands could complete nicks (/dcc close, /dcc get, ..)
- - check the TODO about nick completion scripts..
- Modules:
- Figure out module vs. plugin wording, what is what ;)
irssi .. at least remove the crashing!
- Irssi::signal_remove() could accept hashes
- /command parameter parser so it'd be easier to handle -options etc.
+ - when reloading scripts, Irssi::settings_add_int() prints glib errors,
+ while settings_add_str() doesn't
- Try to get the Makefiles generated so that compiling with GCC would
always work even if the perl wasn't compiled with GCC..
- - Irssi::Timeout_add() and input_add()'s data option could be optional
- and maybe allow multiple parameters
- Bigger code changes:
- Restructure code tree so that non-IRC chat protocols would be in
now crash irssi. Also if setting wasn't expected type can cause
crashes so add proper error checkings everywhere. And is_node_list()
etc. should be in uppercase..
+ - Would this work..? : command_bind() could specify the parameters
+ it uses, then some generic command parser could parse the commands
+ and options and if all is ok, send the parsed parameters directly with
+ signal_emit() .. I'm just thinking some type checking problems but
+ if all commands would be in format SERVER_REC, WI_ITEM_REC,
+ GHashTable *options, char ** (NULL terminated parameters list) .. ?
+ - support for multiple subcommands in the command parser, like
+ /window name foo level msgs.
- Channel syncing is evil. Make it optional, and use /USERHOST when
needed if host isn't known. /BAN at least should do this, and while
- at it, we could make /IGNORE as well to ignore based on mask. Also,
- if /USERHOST doesn't find anything, use /WHOWAS info.
+ at it, we could make /IGNORE as well to ignore based on mask.
- Irssi saves some setting strings to static const char * variables in
several places.. this works pretty well usually, except when /RELOADing
config and some "setup changed" signal handler goes and calls some
them everywhere or figure out something better..
- Better priority specifying for signals, probably should add
int priority without limited range.
- - fix server redirections to handle remote events correctly: very unlikely,
- but its possible that replies to two remote whoises are received exactly
- at the same time overlapping each others
-
- - Commands:
- - try to get the 0.9 command parser to work..
- - user definable parameter definitions and how they're handled, like
- cmsg <target> <colorized-msg> - then there'd be some function called to
- colorize the third parameter. same for tab completion.
- - support for multiple subcommands in the command parser, like
- /window name foo level msgs.
- - A way to disable some command entirely? eg. not show in completion
- list or /HELP or anywhere..
- - Read server capabilities from 005 numeric
- extra spaces after commands don't always work, eg /wii nick, /help xx
- hide channel key in statusbar. This would require a $cmode_nokey or
something..
- fe-none doesn't compile with --with-perl-staticlib because it doesn't find
the ui/textui stuff..
- we should probably print timestamp even if level contains MSGLEVEL_NEVER,
- as long as it's not the only level.. Except when /CATing awaylog we don't
- want to do that.
+ as long as it's not the only level..
- If /SET print_active_channel is ON, actions still don't show the channel
- nick's user/host can't be printed for public messages
- /HELP <alias> should work
for example could hide/show them. add mouse support for it.
- try profiling the code with /cat filewith10000lines
+ - /JOIN #foo could *optionally* move the channel to active window
+ (default off, it confuses people)
- /SERVER ADD -ircnet foonet bar 6000 pass1,
/SERVER ADD -ircnet barnet bar 6000 pass2
dircproxy identifies ircnets based on password
#undef HAVE_CURSES_RESIZETERM
#undef HAVE_CURSES_WRESIZE
+/* terminfo/termcap */
+#undef HAVE_TERMINFO
+
/* nls */
#undef ENABLE_NLS
#undef HAVE_CATGETS
#undef HAVE_GETTEXT
#undef HAVE_LC_MESSAGES
#undef HAVE_STPCPY
-
-/* terminfo/termcap */
-#undef HAVE_TERMINFO
-
-/* If set to 64, enables 64bit off_t for some systems (eg. Linux, Solaris) */
-#undef _FILE_OFFSET_BITS
-
-/* What type should be used for uoff_t */
-#undef UOFF_T_INT
-#undef UOFF_T_LONG
-#undef UOFF_T_LONG_LONG
-
-/* printf()-format for uoff_t, eg. "u" or "lu" or "llu" */
-#undef PRIuUOFF_T
-
# for getting irssi specific stuff to top configure script with Autodist
# without polluting the top configure.ad file with these stuff.
-IRSSI_SUBDIR=
-
#ifdef SILC_DIST_TOOLKIT
if test x$without_irssi = xfalse; then
#endif SILC_DIST_TOOLKIT
-IRSSI_SUBDIR=irssi
-
# help directory
#
HELPDIR="$silc_prefix/help"
#ifdef SILC_DIST_TOOLKIT
fi # without_irssi = false
#endif SILC_DIST_TOOLKIT
-
-AC_SUBST(IRSSI_SUBDIR)
#endif SILC_DIST_CLIENT
fi
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(SILC-Client, 0.8.11+)
+AM_INIT_AUTOMAKE(SILC-Client, 0.8.6+)
AM_MAINTAINER_MODE
AC_PROG_CC
AC_PROG_CPP
AC_STDC_HEADERS
+AC_ARG_PROGRAM
AM_PROG_LIBTOOL
AC_PATH_PROG(sedpath, sed)
AC_CHECK_HEADERS(string.h stdlib.h unistd.h dirent.h sys/ioctl.h sys/resource.h)
# check posix headers..
-AC_CHECK_HEADERS(sys/time.h sys/utsname.h)
+AC_CHECK_HEADERS(sys/time.h sys/utsname.h regex.h)
AC_ARG_WITH(socks,
[ --with-socks Build with socks support],
fi,
want_terminfo=yes)
-AC_ARG_WITH(cuix,
-[ --with-cuix Use curses ui extended],
- if test x$withval = xyes; then
- want_terminfo=no
- want_cuix=yes
- fi, want_cuix=no)
-
AC_ARG_WITH(modules,
[ --with-modules Specify what modules to build in binary],
if test x$withval != xyes -a x$withval != xno; then
perl_prefix_note=yes
fi
-AC_ARG_WITH(glib1,
-[ --with-glib1 Use GLIB 1.2 instead of 2.0 if both exist],
- if test x$withval = xyes; then
- want_glib1=yes
- else
- if test "x$withval" = xno; then
- want_glib1=no
- else
- want_glib1=yes
- fi
- fi,
- want_glib1=no)
+AC_ARG_WITH(with-glib2,
+[ --with-glib2 Use GLIB 2.0 instead of 1.2],
+ if test x$withval = xyes; then
+ want_glib2=yes
+ else
+ if test "x$withval" = xno; then
+ want_glib2=no
+ else
+ want_glib2=yes
+ fi
+ fi,
+ want_glib2=yes)
AC_ARG_WITH(perl-staticlib,
[ --with-perl-staticlib Specify that we want to link perl libraries
fi
AC_MSG_RESULT($irssi_cv_type_socklen_t)
-dnl * off_t checks, try to make it 64bit
-AC_DEFINE_UNQUOTED(_FILE_OFFSET_BITS, $preferred_off_t_bits)
-
-AC_CHECK_SIZEOF(int)
-AC_CHECK_SIZEOF(long)
-AC_CHECK_SIZEOF(long long)
-AC_CHECK_SIZEOF(off_t)
-
-if test $ac_cv_sizeof_off_t = 8; then
- offt_64bit=yes
-else
- offt_64bit=no
-fi
-
-if test x$ac_cv_sizeof_off_t = x$ac_cv_sizeof_long; then
- # try to use unsigned long always first
- AC_DEFINE_UNQUOTED(PRIuUOFF_T, "lu")
- AC_DEFINE(UOFF_T_LONG, [], [UOFF_T_LONG])
-elif test x$ac_cv_sizeof_off_t = x$ac_cv_sizeof_int; then
- # next try int
- AC_DEFINE_UNQUOTED(PRIuUOFF_T, "u")
- AC_DEFINE(UOFF_T_INT, [], [UOFF_T_INT])
-elif test x$ac_cv_sizeof_off_t = x$ac_cv_sizeof_long_long; then
- # and finally long long
- AC_DEFINE_UNQUOTED(PRIuUOFF_T, "llu")
- AC_DEFINE(UOFF_T_LONG_LONG, [], [UOFF_T_LONG_LONG])
-else
- AC_ERROR([Couldn't find integer type for off_t])
-fi
-
dnl **
dnl ** check for socks
dnl **
])
fi
-if test "x$want_cuix" = "xyes"; then
- AC_DEFINE([HAVE_CUIX], [1] ,[Enable cuix support])
-fi
-
dnl **
dnl ** fe-text checks
dnl **
AC_CHECK_GLIBDIR
if test -z "$GLIB_DIR"; then
- if test "x$want_glib1" = "xyes"; then
- dnl * check only for glib1
- checks="1 2"
+ if test "x$with_glib2" = "xyes"; then
+ dnl * check only for glib2
+ checks="3 4"
else
- dnl * check glib2 then glib1
- checks="3 4 1 2"
+ dnl * check glib1 then glib2
+ checks="1 2 3 4"
fi
for try in $checks; do
glib_modules=
fi
if test $try = 1 -o $try = 2; then
- AM_PATH_GLIB(1.2.0,,, $glib_modules)
+ glib_version=1.2.0
else
- AM_PATH_GLIB_2_0(2.0.0,,, $glib_modules)
+ glib_version=2.0.0
fi
+ AM_PATH_GLIB($glib_version,[],[], [$glib_modules])
if test "$GLIB_LIBS"; then
if test $glib_modules = gmodule; then
AC_DEFINE(HAVE_GMODULE)
echo "*** Irssi will automatically compile and use it."
echo
- glib_url=ftp://ftp.gtk.org/pub/gtk/v2.8/
- glib_file=glib-2.8.3.tar.gz
+ dnl * I think it's pretty safe to assume GLib 1.2.9 since the next
+ dnl * will be 2.0 (or 1.4?) and it's not sure if irssi compiles
+ dnl * with it (yea, just a few weeks after I put this text for 1.2.8
+ dnl * the 1.2.9 came :) .. and then .10
+ glib_file=glib-1.2.10.tar.gz
dlcmd=
- if test -n "`wget --version 2>/dev/null|grep -i wget`"; then
- dlcmd="wget -c $glib_url$glib_file"
- elif test -n "`ncftpget --version 2>/dev/null|grep -i ncftp`"; then
- dlcmd="ncftpget -z $glib_url$glib_file"
- elif test -n "`lynx --version 2>/dev/null|grep -i lynx`"; then
- dlcmd="lynx --source $glib_url$glib_file > $glib_file"
- elif test -n "`curl --version 2>/dev/null|grep -i curl`"; then
- dlcmd="curl -C - $glib_url$glib_file"
+ if test -n "`ncftpget 2>/dev/null|grep -i ncftp`"; then
+ dlcmd="ncftpget ftp://ftp.gtk.org/pub/gtk/v1.2/$glib_file"
+ fi
+ if test -n "`wget 2>/dev/null|grep -i wget`"; then
+ dlcmd="wget http://irssi.org/files/$glib_file"
fi
if test -n "$dlcmd"; then
echo "*** I can download GLib for you now. If you don't want to, press CTRL-C now."
read answer
eval $dlcmd
if `gunzip $glib_file`; then
- glib_file=`echo $glib_file|$sedpath s/\.gz$//`
- if `tar xf $glib_file`; then
- rm -f $glib_file
- AC_CHECK_GLIBDIR
- fi
+ glib_file=`echo $glib_file|$sedpath s/\.gz$//`
+ if `tar xf $glib_file`; then
+ rm -f $glib_file
+ AC_CHECK_GLIBDIR
+ fi
fi
fi
LIBS="$LIBS $GLIB_LIBS"
-dnl **
-dnl ** Recode
-dnl **
-AC_MSG_CHECKING([if we can use recode, requires GLIB2])
-if test "$glib_config_major_version" = "2"; then
- AC_DEFINE([HAVE_GLIB2], [], ["HAVE_GLIB2"])
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no, using glib1])
-fi
-
dnl **
dnl ** check if we can link dynamic libraries to modules
dnl ** also checks if libraries are built to .libs dir
PERL_CFLAGS=`$perlpath -MExtUtils::Embed -e ccopts 2>/dev/null`
fi
- if test "x$ac_cv_prog_gcc" = "xyes" -a -z "`echo $host_os|grep 'bsd\|linux'`"; then
- dnl * several systems have Perl compiled with native compiler
- dnl * but irssi is being compiled with GCC. Here we try to
- dnl * fix those command line options a bit so GCC won't
- dnl * complain about them. Normally there's only few options
- dnl * that we want to keep:
- dnl * -Ddefine -Uundef -I/path -fopt -mopt
- PERL_CFLAGS=`echo $PERL_CFLAGS | $perlpath -pe 's/^(.* )?-[^DUIfm][^ ]+/\1/g; s/^(.* )?\+[^ ]+/\1/g'`
-
- PERL_EXTRA_OPTS="CCCDLFLAGS=\"-fPIC\""
- AC_SUBST(PERL_EXTRA_OPTS)
- fi
-
if test -z "$PERL_CFLAGS"; then
if test -n "$perl_check_error"; then
perl_check_error="Error getting perl CFLAGS"
AM_CONDITIONAL(NEED_TPARM, test "$need_tparm" = "yes")
AM_CONDITIONAL(USE_CURSES, test "$want_terminfo" != "yes" -a "$want_termcap" != "yes")
AM_CONDITIONAL(BUILD_SERVERTEST, false)
-AM_CONDITIONAL(USE_CUIX, test "$want_cuix" = "yes")
# move LIBS to PROG_LIBS so they're not tried to be used when linking eg. perl libraries
PROG_LIBS=$LIBS
src/perl/textui/Makefile.PL
src/perl/silc/Makefile.PL
scripts/Makefile
-scripts/examples/Makefile
docs/Makefile
docs/help/Makefile
docs/help/in/Makefile
How to submit a good bug report?
-Send them to bug reporting system in http://bugs.irssi.org/
+Send them to bugs@irssi.org.
First you should give the following information:
- irssi version, if CVS (or devel. tarball) then which day?
+++ /dev/null
-<h2>FAQ</h2>
-
-<h3>Q: Why doesn't irssi display colors even when ircii etc. displays them?</h3>
-
-<p>A: They force ANSI colors even if terminal doesn't support them. By
-default, irssi uses colors only if terminfo/termcap so says. The correct
-way to fix this would be to change your TERM environment to a value where
-colors work, like xterm-color or color_xterm (eg. <code>TERM=xterm-color
-irssi</code>). If this doesn't help, then use the evil way of <code>/SET
-term_force_colors ON</code>.</p>
-
-
-<h3>Q: How do I easily write text to channel that starts with '/' character?</h3>
-
-<p>A: <code>/ /text</code></p>
-
-
-<h3>Q: Why doesn't irssi update my realname (or whatever) after I change it
-with <code>/SET realname</code> and reconnect with <code>/RECONNECT</code>
-or <code>/SERVER</code>?</h3>
-
-<p>A: Irssi is trying to be too smart. This will be fixed in future, but for
-now you should use <code>/DISCONNECT</code> and <code>/CONNECT</code>.</p>
-
-
-<h3>Q: I connected to some server which isn't responding but now irssi tries
-to connect back to it all the time! How can I stop it?</h3>
-
-<p>A: Two ways. The "good way" to do it is with <code>/DISCONNECT</code>.
-Check the server tags first with <code>/SERVER</code> without giving it any
-parameters, reconnections are those that have tag starting with "recon"
-text. So most probably you're going to do <code>/DISCONNECT recon-1</code>.
-The other way is to remove all the reconnections with
-<code>/RMRECONNS</code>, easier but may remove some connections you actually
-wanted to reconnect (if you used multiple servers..).</p>
-
-
-<h3>Q: How do I add seconds to timestamp?</h3>
-
-<p>A: <code>/FORMAT timestamp {timestamp %%H:%%M:%%S}</code> - and remember
-to add the trailing space :)</p>
-
-
-<h3>Q: Why does irssi say "Irssi: Channel not fully synchronized yet, try
-again after a while" when I try to use /BAN etc?</h3>
-
-<p>A: Possibly a bug in irssi, or ircd you're using does something that
-irssi didn't really notice. The new code should make this happen far less
-often than before, but one known reason for this is when irssi doesn't
-notice that you were unable to join some channel. Currently however I don't
-know of any such events irssi doesn't know about.</p>
-
-<p>Anyway, if this does happen, do <code>/RAWLOG SAVE ~/rawlog</code> soon
-after joining to channel, and either try to figure out yourself why irssi
-didn't get reply to WHO request, or send the whole log to cras@irssi.org. Note
-that the rawlog is by default only 200 lines and it may not be enough to
-show all needed information, so you might want to do <code>/SET rawlog_lines
-1000</code> or so.</p>
-
-<p><code>MODE +b</code> still works fine though.</p>
-
-
-<h3>Q: Where's the GUI version?</h3>
-
-<p>A: Read
-<a href="http://irssi.org/?page=about">http://irssi.org/?page=about</a></p>
-
-
-<h3>Q: How do I autorejoin channels after being kicked?</h3>
-
-<p>A: That's evil and you shouldn't do it. If you get kicked, you should stay
-out, at least until the channel forgot you existed :) Most channels I've
-joined just ban you if you autorejoin after kick. If you're joined to
-channels who kick people for fun, try changing channels or something.</p>
-
-<p>Anyway, if you REALLY want to do that, and you understand that you're doing
-evilness, you can use the autorejoin.pl script that comes with irssi. You'll
-still need to specify the channels you wish to rejoin with <code>/SET
-autorejoin_channels #chan1 #chan2 ...</code></p>
-
-
-<h3>Q: How do I announce that I'm away/back in all channels I've joined? Or
-how do I change my nick when setting myself away/back?</h3>
-
-<p>A: That's even worse than autorejoin. Who could possibly care every time
-you come and go? Many channels will kick you for using this, and I for example
-have added several ignores so I'd never need to see these messages. Learn to
-use <code>/AWAY</code> command properly and tell its existence to people
-who don't know about it. <code>/WII yournick</code> shows your away reason
-much better for people who actually want to know if you're there or not.</p>
-
-
-<h3>Q: Why does irssi autojoin on invite by default?</h3>
-
-<p>A: The setting is /SET join_auto_chans_on_invite - it's not the same
-as regular autojoin-on-invite, which irssi doesn't even have. The only
-channels that are joined on invite, are the ones you've added to config
-with /CHANNEL ADD -auto. This is very useful with +i channels when you
-need to first send an invite request to bot, or if you get accidentally
-kicked from channel, the kicker can invite you back immediately.</p>
-
-<p>I don't see any bad side effects with this feature, so it's ON by
-default. I guess someone could start kicking/inviting you all the time
-but server connection shouldn't drop because of that, and you shouldn't
-join channels whose operators are that evil.</p>
-
-
-<h3>Q: How to make UTF-8 support work with irssi?</h3>
-
-<p>A: Make sure your terminal supports UTF-8 (for example, <code>xterm -u8</code>).
-If you use screen, you may have to do <code>screen -U</code>. And in Irssi do
-<code>/SET term_charset utf-8</code>. (for 0.8.9 and older: <code>/SET term_type utf-8</code>)</p>
-
-
-<h3>Q: Will there be /DETACH-like feature?</h3>
-
-<p>A: Maybe. Detach code already is there, attach is just missing :) But I
-don't have much interest in coding it,
-<a href="http://www.gnu.org/software/screen/screen.html">screen</a> and
-<a href="http://dtach.sf.net/">dtach</a> can be used to do it just fine.</p>
-
-
-<h3>Q: How do I run scripts automatically at startup?</h3>
-
-<p>A: Put them into <code>~/.irssi/scripts/autorun/</code> directory. Or
-better would be if you placed them in <code>~/.irssi/scripts/</code> and
-created symlinks to autorun directory (eg. <code>cd
-~/.irssi/scripts/autorun/ ; ln -s ../script.pl .</code>)</p>
-
-
-<h3>Q: How do I execute commands automatically at startup?</h3>
-
-<p>A: Put them into <code>~/.irssi/startup</code> file, each command on its
-own line. The preceding slash (/) is not necessary.</p>
-
-
-<h3>Q: How do I easily edit existing topic?</h3>
-
-<p>A: /TOPIC <tab></p>
-
-<h3>Q: How can I have /WHOIS replies to active window?</h3>
-
-<p>A: You can disable the status window, or do <code>/WINDOW LEVEL
--CRAP</code> in it which would also make several other messages show up in
-active window. You can also use a
-<a href="http://dgl.cx/irssi/hack-whois-in-current-window.pl">script</a>.</p>
-
-<h3>Q: How do I add the active network to the statusbar</h3>
-
-<p>A: Modify the window-line in statusbar section in config file to
-<code>window = "{sb $winref:$tag/$T{sbmode $M}}";</code></p>
-
# Makefile.am is autogenerated by autogen.sh from Makefile.am.gen
-helpdir = $(datadir)/irssi/help
+include $(top_srcdir)/Makefile.defines.in
+
+helpdir = $(silc_helpdir)
help_DATA = \
@HELPFILES@
The following modes are available:
p Set/unset channel as private channel
- s Set/unset channel as secret channel. Secret
- channel are not shown in user's channel list
- or with /LIST command.
+ s Set/unset channel as secret channel
k Enable/disable channel private key usage (*)
i Set/unset channel as invite only channel
t Set/unset that only channel operator or
If the <local IP> is provided then the key exchange
protocol listener will be bound to that address. If
- <local port> is defined it is bound to that port.
+ <local port> is defined it is bound to that port.
If they are not defined then the local IP address
of your machine is used to bind the listener.
the point of connect. This is usefull when the sender
is behind NAT device.
- If the <local IP> and <local port> are ommitted and the
- -no-listener option is not given, the boolean variable
- use_auto_addr will be examined. If it is set the value
- of auto_bind_ip will be used as the IP address to bound
- the listener, the value of auto_public_ip will be the IP
- address sent to the remote client, and the auto_bind_port
- will be the port value to be bound to and sent to the remote
- client. If auto_public_ip is unset, but auto_bind_ip is
- set, SILC client will send the auto_bind_ip variable's
- value to the remote client.
-
ACCEPT [<nickname>]
Accepts the file transfer request and starts the file
Closes the file transfer session, or rejects
file transfer request. If this command is given
during the file transfer process it will be cancelled.
+
Commands:
- set [<key> [<cipher>] [<hmac>]]
+ set [<key> [<cipher>] [<hmac>]] [-responder]
- Set the key into use. The <key> is a pre-shared-key,
- passphrase or similar shared secret string. Setting
- the key without first receiving a request from the
- remote user, this command will send the request to the
- remote user. The actual key is not sent to network.
+ Set the key into use. If the <key> is provided it is used
+ as the key material. If the <key> is not provided the
+ negotiated key material is used. If the negotiation has not
+ been performed this command has no effect.
- Optionally, the <cipher> and <hmac> may also be set.
+ If the type is MSG and the <key> is `*' then random key
+ will be generated automatically. The -responder option
+ may be used ONLY with MSG type. One of the clients must
+ be the responder side. The one being the responder must
+ use this option. The clients setting the key must agree
+ on which one is the responder.
unset [<number>]
next key is changed to current channel private key. By default
this command is also bound to Meta-K (Alt+Shift+k) key.
- agreement [<hostname> [<port>] [<TCP|UDP>]]
+ agreement [<hostname> [<port>]]
Send key agreement request to remote client. If the
<hostname> is provided it is sent in the request. The
not provided then the receiver will never initiate the key
agreement. In this case you may start the key agreement
after receiving the reply to the request, by giving the
- negotiate command. By default the key agreement connection
- is TCP connection. UDP connection may also be defined.
- (Note that, older SILC clients (1.0.x) does not support UDP).
+ negotiate command.
This command may be used to send reply to the remote client.
When receiving empty key agreement you can reply to the
auto_bind_ip is set, silc client will send the auto_bind_ip
variable's value to the remote client.
- negotiate [<hostname> [<port>] [<TCP|UDP>]]
+ negotiate [<hostname> [<port>]]
This may be called to start the key agreement with <nickname>.
This command has effect only if the <nickname> has replied to
your key agreement request. You will see a notify on the
screen when the reply arrives. The <hostname> and <port> is the
hostname and port of the remote client's key agreement server.
- The request tells the connection protocol used, usually TCP.
- If UDP was requested it must be provided.
Examples:
/KEY CHANNEL * set very_secret_key_this_is
/KEY CHANNEL * list
-
- Set private message key with a friend:
-
- foobar: /KEY MSG friend set secretkey
- friend: /KEY MSG foobar set secretkey
-
- Perform key agreement:
-
- bar: /KEY MSG foo agreement 10.2.1.7 5000
- foo: /KEY MSG bar negotiate 10.2.1.7 5000
-
- bar: /KEY MSG foo agreement 10.2.1.7 5000 UDP
- foo: /KEY MSG bar negotiate 10.2.1.7 5000 UDP
+ /KEY MSG nickname set secretkey
+ /KEY MSG nick set secretkey -responder
+ /KEY MSG foo agreement 10.2.1.7 5000
+ /KEY MSG bar negotiate 10.2.1.7 5000
See also: WHOIS, CHANNEL, GETKEY
+++ /dev/null
-
-@SYNTAX:recode@
-
-RECODE
- %|List the conversion database
-
-RECODE ADD %|[<tag>]|[[<tag>/]<target>] <charset>
- %|Add an entry to the conversion database (if tag or target is
- omitted, the current channel or query will be used). You can specify
- the <tag> to have different charsets for the same <target> for
- different networks. You can omit the target, and specify only the tag
- if you want to add an entry for the network.
-
-RECODE REMOVE %|[<tag>|<target>]
- %|Remove an entry from the conversion database (if tag or target is
- omitted, the current channel or query will be used)
-
-To specify your local charset you have to set term_charset
-
-Example:
-
-/SET term_charset <charset>
-
-To see the recode settings: /SET recode
-
-You can change them with /SET
-
-Examples:
-
-/SET recode OFF
-to turn off recode completely
-
-/SET recode_fallback <charset>
-to set the fallback charset for incoming events
-
-This charset is used if your term_charset is UTF-8
-and the conversion for the target is not set and
-the text is not UTF-8.
-
-/SET recode_out_default_charset <charset>
-to set the global outgoing charset
-
-When it's set to a charset it will be used
-if no conversion for the target is set.
-
-/SET recode_transliterate ON
-to enable the global transliteration.
-
-The transliteration is based on your locale settings,
-if it doesn't work properly your locale settings may be wrong.
-You can enable it per target by adding //TRANSLIT to the <charset>
-
-/SET recode_autodetect_utf8 OFF
-to turn automatic UTF-8 detection off.
-
-Hint: <charset> can be almost everything listed by 'iconv -l'
-
-See also: NETWORK
-
Servers are referenced by a "server tag". If the server is known
to belong to some IRC network, the tag is the IRC network's name,
- like "IRCnet". If the IRC network is unknown, the tag is created
+ like "ircnet". If the IRC network is unknown, the tag is created
from the server's name, like irc.funet.fi -> funet. If the tag
already exists, a number is added to the end of it and raised until
unused tag is found.
or the safe defaults will be used. The default configuration file
contains the settings for the biggest IRC networks.
- /NETWORK ADD [-kicks <count>] [-msgs <count>] [-modes <count>]
+ /IRCNET ADD [-kicks <count>] [-msgs <count>] [-modes <count>]
[-whois <count>] [-cmdspeed <ms>] [-cmdmax <count>]
[-nick <nick>] [-user <user>] [-realname <name>]
[-host <host>] [-autosendcmd <cmd>] <name>
-autosendcmd: Command to send after connecting to a server
With -autosendcmd argument you can automatically run any commands
- after connecting to the network. This is useful for automatically
+ after connecting to ircnet. This is useful for automatically
identifying yourself to NickServ, for example
- /NETWORK ADD -autosendcmd "/msg NickServ identify secret" freenode
+ /IRCNET ADD -autosendcmd "/msg NickServ identify secret" freenode
- /NETWORK REMOVE <name>
+ /IRCNET REMOVE <name>
5.3 Manually connecting and disconnecting
To connect to a new server, use:
- /CONNECT [-network <network>] [-host <hostname>] <address>|<network>
+ /CONNECT [-ircnet <ircnet>] [-host <hostname>] <address>|<ircnet>
[<port> [<password> [<nick>]]]
If there's no password, set it to -. You can directly connect to
5.4 Server settings
- /SERVER ADD [-auto | -noauto] [-network <network>] [-host <hostname>]
+ /SERVER ADD [-auto | -noauto] [-ircnet <ircnet>] [-host <hostname>]
[-cmdspeed <ms>] [-cmdmax <count>] [-port <port>]
<address> [<port> [<password>]]
-auto: Automatically connect to server at startup
-noauto: Don't connect to server at startup (default)
- -network: Specify what IRC network this server belongs to
- -ircnet: Same as -network. Deprecated. Do not use.
+ -ircnet: Specify what IRC network this server belongs to
-host: Specify what host name to use, if you have multiple
-cmdspeed: Same as /SET cmd_queue_speed, see section 3.1
-cmdmax: Same as /SET cmd_max_at_once, see section 3.1
manually joining to channel without specifying the password.
/CHANNEL ADD [-auto | -noauto] [-bots <masks>] [-botcmd <command>]
- <channel> <network> [<password>]
+ <channel> <ircnet> [<password>]
With -bots and -botcmd arguments you can automatically send
commands to someone in channel. This is useful for automatically
can be removed by setting it to - (or actually, "" works too).
You can remove the channels with
- /CHANNEL REMOVE <channel> <network>
+ /CHANNEL REMOVE <channel> <ircnet>
/CHANNEL LIST displays list of channels with settings.
/CHANNEL without any arguments displays list of channels you have
are in IRC all the time. So I made a bit more featureful notify
list:
- /NOTIFY [-list] [-away] [-idle [minutes]] <mask> [network [network...]]
+ /NOTIFY [-list] [-away] [-idle [minutes]] <mask> [ircnet [ircnet...]]
-away: Notifies about away-status changes
-idle: Notifies if idle time is first larger than <minutes>
settings_get_str(key)
settings_get_int(key)
settings_get_bool(key)
-settings_get_time(key)
-settings_get_level(key)
-settings_get_size(key)
Return value for setting.
-settings_set_str(key, value)
-settings_set_int(key, value)
-settings_set_bool(key, value)
-settings_set_time(key, value)
-settings_set_level(key, value)
-settings_set_size(key, value)
- Set value for setting.
- If you change the settings of another module/script with one of these, you
- must emit a "setup changed" signal afterwards.
-
settings_add_str(section, key, def)
settings_add_int(section, key, def)
settings_add_bool(section, key, def)
-settings_add_time(section, key, def)
-settings_add_level(section, key, def)
-settings_add_size(section, key, def)
Create new setting.
settings_remove(key)
Call `func' every `msecs' milliseconds (1000 = 1 second) with
parameter `data'. Returns tag which can be used to stop the timeout.
-timeout_add_once(msecs, func, data);
- Call 'func' once after `msecs' milliseconds (1000 = 1 second)
- with parameter `data'. Returns tag which can be used to stop the timeout.
-
timeout_remove(tag)
Remove timeout with tag.
Channel::nick_find_mask(mask)
Find nick mask from nicklist, wildcards allowed.
-Channel::nicks()
+Channel::nicks(channel)
Return a list of all nicks in channel.
Server::nicks_get_same(nick)
is the full raw command to be sent to server, like
"NOTICE nick :\001VERSION irssi\001"
-Server::isupport(name)
- Returns the value of the named item in the ISUPPORT (005) numeric to the
- script. If the item is not present returns undef, if the item has no value
- then "" is returned use defined $server->isupport("name") if you need to
- check whether a property is present.
- See http://www.ietf.org/internet-drafts/draft-brocklesby-irc-isupport-01.txt
- for more information on the ISUPPORT numeric.
*** IRC channels
"server connect failed", SERVER_REC
"server disconnected", SERVER_REC
"server quit", SERVER_REC, char *msg
- "server sendmsg", SERVER_REC, char *target, char *msg, int target_type
settings.c:
"setup changed"
"setup reread", char *fname
"setup saved", char *fname, int autosaved
+signal.c:
+
+ "signal", char *name, ...
+ "last signal", char *name, ...
IRC core
--------
"server event", SERVER_REC, char *data, char *sender_nick, char *sender_address
"event "<cmd>, SERVER_REC, char *args, char *sender_nick, char *sender_address
"default event", SERVER_REC, char *data, char *sender_nick, char *sender_address
- "whois default event", SERVER_REC, char *args, char *sender_nick, char *sender_address
"server incoming", SERVER_REC, char *data
mode-lists.c:
"ban new", CHANNEL_REC, BAN_REC
- "ban remove", CHANNEL_REC, BAN_REC, char *setby
+ "ban remove", CHANNEL_REC, BAN_REC
modes.c:
"channel mode changed", CHANNEL_REC, char *setby
gui-printtext.c:
"beep"
-Perl
-----
+SILC
+---
+
+silc-channels.c:
+ "mime", SERVER_REC, WI_ITEM_REC, char *blob, char *nick, int verified
-"script error", PERL_SCRIPT_REC, char *errormsg
+silc-servers.c:
+ "mime-send", SERVER_REC, int is_channel, char *to, char *blob, int sign
$Z time of day (hh:mm, can be changed with /SET timestamp_format)
$$ a literal '$'
- $versiontime prints time of the irssi version in HHMM format
+ $versiontim prints time of the irssi version in HHMM format
$sysname system name (eg. Linux)
$sysrelease system release (eg. 2.2.18)
$sysarch system architecture (eg. i686)
+++ /dev/null
- <h2>Startup HOWTO</h2>
-
- <h3>îÏ×ÉÞËÁÍ × Irssi (Á ÎÅ IRC ..)</h3>
-
- <p>© 2000-2002 by Timo Sirainen, ÒÁÓÐÒÏÓÔÒÁÎÑÅÔÓÑ ÐÏÄ ÌÉÃÅÎÚÉÅÊ
- <a href="http://www.gnu.org/licenses/fdl.html">GNU FDL</a> 1.1.<br/>
- îÁ ÒÕÓÓËÉÊ ÑÚÙË ÐÅÒÅ×ÅÄÅÎÏ NiXoiD'ÏÍ (#xakep @ irc.wenet.ru)
- </p>
-
-
-<p>ïÇÌÁ×ÌÅÎÉÅ Ó ÎÅËÏÔÏÒÙÍÉ ×ÏÐÒÏÓÁÍÉ ÉÚ FAQ, ÎÁ ËÏÔÏÒÙÅ ÄÁÅÔÓÑ ÏÔ×ÅÔ × ÐÁÒÁÇÒÁÆÁÈ:</p>
-
-<ol>
-<li><a href="#c1">äÌÑ ÌÅÎÉ×ÙÈ</a>
- <ul>
- <li>õÐÒÁ×ÌÅÎÉÅ ÏËÎÁÍÉ, ÁÎÁÌÏÇÉÞÎÏÅ ircII</li>
- </ul></li>
-<li><a href="#c2">ïÓÎÏ×Ù ÐÏÌØÚÏ×ÁÔÅÌØÓËÏÇÏ ÉÎÔÅÒÆÅÊÓÁ</a>
- <ul>
- <li>òÁÂÏÔÁ Ó "ÒÁÚÄÅÌÅÎÎÙÍÉ" ÏËÎÁÍÉ (Ñ ÔÁË ÐÅÒÅ×£Ì "split windows")</li>
- <li>ëÁË Ñ ÍÏÇÕ ÌÅÇËÏ ÐÅÒÅËÌÀÞÁÔØÓÑ ÍÅÖÄÕ ÏËÎÁÍÉ?</li>
- <li>îÏ alt-1 É.Ô.Ä. ÎÅ ÒÁÂÏÔÁÅÔ!</li>
- </ul></li>
-<li><a href="#c3">á×ÔÏÚÁÈÏÄ ÎÁ ËÁÎÁÌÙ É ÓÅÒ×ÅÒÙ</a>
- <ul>
- <li>ëÁË Á×ÔÏÍÁÔÉÞÅÓËÉ ÐÏÄËÌÀÞÁÔØÓÑ Ë ÓÅÒ×ÅÒÁÍ ÐÒÉ ÚÁÐÕÓËÅ?</li>
- <li>ëÁË Á×ÔÏÍÁÔÉÞÅÓËÉ ÚÁÈÏÄÉÔØ ÎÁ ËÁÎÁÌÙ?</li>
- <li>ëÁË Á×ÔÏÍÁÔÉÞÅÓËÉ ×ÙÐÏÌÎÑÔØ ËÏÍÁÎÄÙ ÐÒÉ ÐÏÄËÌÀÞÅÎÉÉ?</li>
- </ul></li>
-<li><a href="#c4">îÁÓÔÒÏÊËÁ ÏËÏÎ É Á×ÔÏÍÁÔÉÞÅÓËÏÅ ×ÏÓÓÔÁÎÏ×ÌÅÎÉÅ ÉÈ ÐÒÉ ÚÁÐÕÓËÅ</a></li>
-<li><a href="#c5">ïËÎÁ status É msgs & ÕÒÏ×ÎÉ ÓÏÏÂÝÅÎÉÊ</a>
- <ul>
- <li>ñ ÈÏÞÕ ÞÔÏÂÙ ÏÔ×ÅÔ ÎÁ /WHOIS ×Ù×ÏÄÉÌÓÑ × ÔÅËÕÝÅÅ ÏËÎÏ</li>
- <li>ñ ÈÏÞÕ ÞÔÏÂÙ ×ÓÅ ÓÏÏÂÝÅÎÉÑ ×Ù×ÏÄÉÌÉÓØ × ÏÄÎÏÍ ÏËÎÅ</li>
- </ul></li>
-<li><a href="#c6">ëÁË × irssi ÒÁÂÏÔÁÅÔ ÍÎÏÇÏÓÅÒ×ÅÒÎÁÑ ÐÏÄÄÅÒÖËÁ</a>
- <ul>
- <li>ñ ÐÏÄËÌÀÞÉÌÓÑ Ë ÓÅÒ×ÅÒÕ, ËÏÔÏÒÙÊ ÎÅ ÏÔ×ÅÞÁÅÔ É ÔÅÐÅÒØ irssi ÐÙÔÁÅÔÓÑ ÐÏÄËÌÀÞÉÔØÓÑ Ë ÎÅÍÕ ÓÎÏ×Á É ÓÎÏ×Á. ëÁË ÍÎÅ ÏÓÔÁÎÏ×ÉÔØ ÜÔÏ??</li>
- <li>ñ ÈÏÞÕ ÏÔÄÅÌØÎÏÅ ÏËÎÏ ÓÔÁÔÕÓÁ É ÓÏÏÂÝÅÎÉÊ ÄÌÑ ËÁÖÄÏÇÏ ÓÅÒ×ÅÒÁ</li>
- </ul></li>
-<li><a href="#c7">ëÏÍÁÎÄÁ /LASTLOG É ÐÒÏËÒÕÔËÁ ÏËÏÎ</a>
- <ul>
- <li>ëÁË ÓÏÈÒÁÎÉÔØ ×ÅÓØ ÔÅËÓÔ ÉÚ ÏËÎÁ × ÆÁÊÌ?</li>
- </ul></li>
-<li><a href="#c8">÷ÅÄÅÎÉÅ ÌÏÇÏ×</a></li>
-<li><a href="#c9">éÚÍÅÎÅÎÉÅ ËÌÁ×ÉÁÔÕÒÎÙÈ óÏÞÅÔÁÎÉÊ</a>
- <ul>
- <li>ëÁË Ñ ÍÏÇÕ ÚÁÓÔÁ×ÉÔØ F1 ÄÅÌÁÔØ ÞÔÏ-ÔÏ?</li>
- </ul></li>
-<li><a href="#c10">ðÒÏËÓÉ É ÂÏÕÎÓÅÒÙ</a>
- <ul>
- <li>þÔÏ ÔÁËÏÅ irssi-proxy?</li>
- </ul></li>
-<li><a href="#c11">îÁÓÔÒÏÊËÉ Irssi</a></li>
-<li><a href="#c12">óÔÁÔÕÓÂÁÒ</a>
- <ul>
- <li>ñ ÚÁÇÒÕÚÉÌ ÓËÒÉÐÔ ÄÌÑ ÓÔÁÔÕÓÂÁÒÁ, ÎÏ ÅÇÏ ÎÉÇÄÅ ÎÅ ×ÉÄÎÏ!</li>
- </ul></li>
-</ol>
-
-<h3><a id="c1">1. äÌÑ ÌÅÎÉ×ÙÈ</a></h3>
-
-<p>îÅÓËÏÌØËÏ ÐÏÌÅÚÎÙÈ ÎÁÓÔÒÏÅË ÐÏ ÕÍÏÌÞÁÎÉÀ:</p>
-
-<p>åÓÌÉ ÎÅ ÒÁÂÏÔÁÀÔ Ã×ÅÔÁ É ×Ù ÎÅ ÓÏÂÉÒÁÅÔÅÓØ ÉÓÐÏÌØÚÏ×ÁÔØ VT-ÎÅÓÏ×ÍÅÓÔÉÍÙÊ ÔÅÒÍÉÎÁÌ, ÔÏ ÐÒÏÓÔÏ ××ÅÄÉÔÅ:</p>
-
-<pre>
-/SET term_force_colors ON
-</pre>
-
-<p>åÓÌÉ ×Ù ÈÏÔÉÔÅ ÞÔÏÂÙ ×ÓÅ ÓÏÏÂÝÅÎÉÑ ×Ù×ÏÄÉÌÉÓØ × ÏÄÎÏÍ ÏËÎÅ:</p>
-
-<pre>
-/SET autocreate_own_query OFF
-/SET autocreate_query_level DCCMSGS
-/SET use_status_window OFF
-/SET use_msgs_window ON
-</pre>
-
-<p>þÔÏÂÙ ÏËÎÁ Á×ÔÏÍÁÔÉÞÅÓËÉ ÎÅ ÚÁËÒÙ×ÁÌÉÓØ ËÏÇÄÁ ×Ù ÐÏËÉÄÁÅÔÅ ËÁÎÁÌ(<code>/PART</code>)ÉÌÉ ÐÒÉ×ÁÔ
-(<code>/UNQUERY</code>):</p>
-
-<pre>
-/SET autoclose_windows OFF
-/SET reuse_unused_windows ON
-</pre>
-
-<p>þÔÏÂÙ ÕÐÒÁ×ÌÅÎÉÅ ÏËÎÁÍÉ × irssi ÂÙÌÏ ÐÏÈÏÖÅ ÎÁ ircII ××ÅÄÉÔÅ ÜÔÉ ËÏÍÁÎÄÙ:</p>
-
-<pre>
-/SET autocreate_own_query OFF
-/SET autocreate_query_level NONE
-/SET use_status_window OFF
-/SET use_msgs_window OFF
-/SET reuse_unused_windows ON
-/SET windows_auto_renumber OFF
-
-/SET autostick_split_windows OFF
-/SET autoclose_windows OFF
-/SET print_active_channel ON
-</pre>
-
-<p>÷ÏÔ ÐÒÉÍÅÒ ÄÏÂÁ×ÌÅÎÉÑ ÓÅÒ×ÅÒÏ×:</p>
-
-<p>(ÓÅÔØ OFTC, ÉÄÅÎÔÉÆÉÃÉÒÏ×ÁÔØÓÑ ÞÅÒÅÚ nickserv É ÖÄÁÔØ 2 ÓÅËÕÎÄÙ ÐÅÒÅÄ ÚÁÈÏÄÏÍ ÎÁ ËÁÎÁÌÙ)</p>
-
-<pre>
-/IRCNET ADD -autosendcmd "/^msg nickserv ident pass;wait 2000" OFTC
-</pre>
-
-<p>ôÅÐÅÒØ ÄÏÂÁ×ÌÅÎÉÅ ÎÅÓËÏÌØËÉÈ ÓÅÒ×ÅÒÏ× Ë ÒÁÚÎÙÍ ÓÅÔÑÍ (IRC-ÓÅÔØ ÄÌÑ ÎÉÈ ÕÖÅ ÕÓÔÁÎÏ×ÌÅÎÁ),
- irc.kpnqwest.fi ÉÓÐÏÌØÚÕÅÔÓÑ ÐÏ ÄÅÆÏÌÔÕ ÄÌÑ IRCNet ÎÏ ÅÓÌÉ ÏÎ ÎÅ ÄÏÓÔÕÐÅÎ, ÔÏ irssi ÂÕÄÅÔ ÐÙÔÁÔØÓÑ ÐÏÄËÌÀÞÉÔØÓÑ Ë
-irc.funet.fi:</p>
-
-<pre>
-/SERVER ADD -auto -ircnet ircnet irc.kpnqwest.fi 6667
-/SERVER ADD -ircnet ircnet irc.funet.fi 6667
-/SERVER ADD -auto -ircnet efnet efnet.cs.hut.fi 6667
-</pre>
-
-<p>á×ÔÏÚÁÈÏÄ ÎÁ ËÁÎÁÌÙ ÐÒÉ ÐÏÄËÌÀÞÅÎÉÉ Ë ÓÅÒ×ÅÒÕ É ÏÐ-ÚÁÐÒÏÓ ÂÏÔÁ ÐÒÉ ÚÁÈÏÄÅ ÎÁ efnet/#irssi:</p>
-
-<pre>
-/CHANNEL ADD -auto #irssi ircnet
-/CHANNEL ADD -auto -bots *!*bot@host.org -botcmd "/^msg $0 op pass" #irssi efnet
-</pre>
-
-þÔÏÂÙ ÓÔÒÏËÉ, ÓÏÄÅÒÖÁÝÉÅ ÷ÁÛ ÎÉË ÐÏÄÓ×ÅÞÉ×ÁÌÉÓØ:
-
-<pre>
-/HILIGHT ×ÁÛ_ÎÉË
-</pre>
-
-<h3><a id="c2">2. ïÓÎÏ×Ù ÐÏÌØÚÏ×ÁÔÅÌØÓËÏÇÏ ÉÎÔÅÒÆÅÊÓÁ</a></h3>
-
-<p>äÌÑ ÓËÒÏÌÌÉÎÇÁ ÓÏÄÅÒÖÉÍÏÇÏ ÏËÏÎ ÉÓÐÏÌØÚÕÊÔÅ PgUp É PgDown. åÓÌÉ ÏÎÉ ÎÅ ÒÁÂÏÔÁÀÔ, ÉÓÐÏÌØÚÕÊÔÅ ËÎÏÐËÉ Meta-p É Meta-n.
- þÔÏÂÙ ÐÅÒÅÓËÏÞÉÔØ × ÎÁÞÁÌÏ ÉÌÉ ËÏÎÅÃ ÂÕÆÅÒÁ ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÙ <code>/SB HOME</code> É <code>/SB END</code>.</p>
-
-<p>ðÏ ÕÍÏÌÞÁÎÉÀ irssi ÉÓÐÏÌØÚÕÅÔ ÄÌÑ ×ÓÅÇÏ "ÓËÒÙÔÙÅ ÏËÎÁ". óËÒÙÔÏÅ ÏËÎÏ ÓÏÚÄÁÅÔÓÑ ËÁÖÄÙÊ ÒÁÚ ËÏÇÄÁ ×Ù ÚÁÈÏÄÉÔÅ(<code>/JOIN</code>) ÎÁ ËÁÎÁÌ ÉÌÉ ÓÏÚÄÁÅÔÅ ÐÒÉ×ÁÔ(<code>/QUERY</code>)
-Ó ËÅÍ-ÔÏ. åÓÔØ ÎÅÓËÏÌØËÏ ÓÐÏÓÏÂÏ× ÐÅÒÅËÌÀÞÅÎÉÑ ÍÅÖÄÕ ÜÔÉÍÉ ÏËÎÁÍÉ:</p>
-
-<pre>
-Meta-1, Meta-2, .. Meta-0 - ðÅÒÅËÌÀÞÅÎÉÅ ÍÅÖÄÕ ÏËÎÁÍÉ 1-10
-Meta-q .. Meta-o - ðÅÒÅËÌÀÞÅÎÉÅ ÍÅÖÄÕ ÏËÎÁÍÉ 11-19
-/WINDOW <ÎÏÍÅÒ> - ðÅÒÅËÌÀÞÅÎÉÅ ÎÁ ÏËÎÏ Ó ÚÁÄÁÎÎÙÍ ÎÏÍÅÒÏÍ
-Ctrl-P, Ctrl-N - ðÅÒÅËÌÀÞÅÎÉÅ Ë ÐÒÅÄÙÄÕÝÅÍÕ/ÓÌÅÄÕÀÝÅÍÕ ÏËÎÕ
-</pre>
-
-<p>ðÒÏÓÔÅÊÛÉÊ ÓÐÏÓÏÂ ÐÅÒÅËÌÀÞÅÎÉÑ - ÜÔÏ Meta-ÎÏÍÅÒ. þÔÏ ÔÁËÏÅ Meta?
-äÌÑ ÎÅËÏÔÏÒÙÈ ÔÅÒÍÉÎÁÌÏ× ÜÔÏ ALT. åÓÌÉ Õ ×ÁÓ windows-ÓÏ×ÍÅÓÔÉÍÁÑ ËÌÁ×ÉÁÔÕÒÁ, ÔÏ ÜÔÏ ÔÁË-ÖÅ ÍÏÖÅÔ ÂÙÔØ ÌÅ×ÁÑ ËÎÏÐËÁ windows. åÓÌÉ ÏÎÉ ÎÅ ÒÁÂÏÔÁÀÔ, ÔÏ ×ÁÍ ÐÒÉÄÅÔÓÑ ÎÁÓÔÒÏÉÔØ ÎÅËÏÔÏÒÙÅ X-ÒÅÓÕÒÓÙ
-(ÜÔÏ ÒÁÂÏÔÁÅÔ ËÁË × xterm ÔÁË É × rxvt):</p>
-
-<pre>
-XTerm*eightBitInput: false
-XTerm*metaSendsEscape: true
-</pre>
-
-<p>÷ rxvt ×Ù ÔÁË-ÖÅ ÍÏÖÅÔÅ ÕËÁÚÁÔØ ËÁËÁÑ ËÎÏÐËÁ ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ËÎÏÐËÅ meta, ÔÁË ÞÔÏ ÅÓÌÉ ×Ù ÈÏÔÉÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ Alt ×ÍÅÓÔÏ Win ÄÏÐÉÛÉÔÅ ÜÔÏ × ÆÁÊÌ Ó ÒÅÓÕÒÓÁÍÉ:</p>
-
-<pre>
-rxvt*modifier: alt
-</pre>
-
-<p>÷Ù ÔÁË-ÖÅ ÍÏÖÅÔÅ ÓÄÅÌÁÔØ ÜÔÏ ÐÒÉ ÐÏÍÏÝÉ xmodmap:</p>
-
-<pre>
-xmodmap -e "keysym Alt_L = Meta_L Alt_L"
-</pre>
-
-<p>ôÁË ËÁË-ÖÅ ÕÓÔÁÎÏ×ÉÔØ ÜÔÉ X-ÒÅÓÕÒÓÙ? äÌÑ Debian'Á, ÜÔÏ ÆÁÊÌ
-<code>/etc/X11/Xresources/xterm</code>, × ËÏÔÏÒÙÊ ×Ù ÍÏÖÅÔÅ ÉÈ ÚÁÓÕÎÕÔØ É ÏÎÉ ÂÕÄÕÔ Á×ÔÏÍÁÔÉÞÅÓËÉ ÞÉÔÁÔØÓÑ ÐÒÉ ÓÔÁÒÔÅ ÉËÓÏ×. æÁÊÌÙ <code>~/.Xresources</code> É
-<code>~/.Xdefaults</code> ÔÁË-ÖÅ ÄÏÌÖÎÙ ÒÁÂÏÔÁÔØ. åÓÌÉ ÎÉÞÅÇÏ ÉÚ ×ÙÛÅÐÅÒÅÞÉÓÌÅÎÎÏÇÏ ÎÅ ÒÁÂÏÔÁÅÔ, ÔÏ ÐÒÏÓÔÏ ÓËÏÐÉÒÕÊÔÅ ÉÈ × <code>~/.Xresources</code>
-É ÚÁÇÒÕÚÉÔÅ ËÏÍÁÎÄÏÊ <code>xrdb -merge ~/.Xresources</code>.
-éÚÍÅÎÅÎÉÑ ÎÁÞÉÎÁÀÔ ÄÅÊÓÔ×Ï×ÁÔØ ÔÏÌØËÏ × ÚÁÎÏ×Ï ÚÁÐÕÝÅÎÎÏÍ ÔÅÒÍÉÎÁÌÅ.</p>
-
-<p>íÎÏÇÉÅ SSH ËÌÉÅÎÔÙ ÐÏÄ Windows ÔÁË ÖÅ ÎÅ ÒÁÚÒÅÛÁÀÔ ÉÓÐÏÌØÚÏ×ÁÔØ ËÎÏÐËÕ ALT. ðÒÅËÒÁÓÎÙÊ ËÌÉÅÎÔ, ËÏÔÏÒÙÊ ÐÏÚ×ÏÌÑÅÔ ÄÅÌÁÔØ ÜÔÏ - putty, ×Ù ÍÏÖÅÔÅ ÓËÁÞÁÔØ ÅÇÏ Ó
-<a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">
-http://www.chiark.greenend.org.uk/~sgtatham/putty/</a>.</p>
-
-<p>ôÁË-ÖÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÒÁÚÄÅÌÅÎÉÅ ÏËÏÎ. ÷ÏÔ ËÏÍÁÎÄÙ, ËÏÔÏÒÙÅ ÐÏÚ×ÏÌÑÀÔ ÜÔÏ ÓÄÅÌÁÔØ:</p>
-
-<pre>
-/WINDOW NEW - óÏÚÄÁÔØ ÎÏ×ÏÅ ÒÁÚÄÅÌÅÎÎÏÅ ÏËÎÏ
-/WINDOW NEW HIDE - óÏÚÄÁÔØ ÎÏ×ÏÅ ÓËÒÙÔÏÅ ÏËÎÏ
-/WINDOW CLOSE - úÁËÒÙÔØ ÒÁÚÄÅÌÅÎÎÏÅ ÉÌÉ ÓËÒÙÔÏÅ ÏËÎÏ
-
-/WINDOW HIDE [<number>|<name>] - óÄÅÌÁÔØ ÒÁÚÄÅÌÅÎÎÏÅ ÏËÎÏ ÓËÒÙÔÙÍ
-/WINDOW SHOW <number>|<name> - óÄÅÌÁÔØ ÓËÒÙÔÏÅ ÏËÎÏ ÒÁÚÄÅÌÅÎÎÙÍ
-
-/WINDOW SHRINK [<lines>] - õÍÅÎØÛÉÔØ ÁËÔÉ×ÎÏÅ ÏËÎÏ
-/WINDOW GROW [<lines>] - õ×ÅÌÉÞÉÔØ ÁËÔÉ×ÎÏÅ ÏËÎÏ
-/WINDOW BALANCE - óÂÁÌÁÎÓÉÒÏ×ÁÔØ ÒÁÚÍÅÒÙ ×ÓÅÈ ÒÁÚÄÅÌÅÎÎÙÈ ÏËÏÎ
-</pre>
-
-<p>ðÏ ÕÍÏÌÞÁÎÉÀ Irssi ÉÓÐÏÌØÚÕÅÔ "ÐÒÉËÌÅÉ×ÁÎÉÅ ÏËÏÎ". üÔÏ ÐÏÄÒÁÚÕÍÅ×ÁÅÔ, ÞÔÏ ÏËÎÏ, ÓÏÚÄÁÎÎÏÅ ×ÎÕÔÒÉ ÒÁÚÄÅÌÅÎÎÏÇÏ ÏËÎÁ ÎÅ ÍÏÖÅÔ ÂÙÔØ ÐÅÒÅÍÅÝÅÎÏ ÂÅÚ ÎÅËÏÔÏÒÏÇÏ ÇÅÍÏÒÁ :). îÁÐÒÉÍÅÒ Õ ×ÁÓ ÍÏÖÅÔ ÂÙÔØ ÓÌÅÄÕÀÝÅÅ ÒÁÓÐÏÌÏÖÅÎÉÅ ÏËÏÎ:</p>
-
-<pre>
-Split window 1: win#1 - Status window, win#2 - ïËÎÏ ÓÏÏÂÝÅÎÉÊ
-Split window 2: win#3 - ircnet/#channel1, win#4 - ircnet/#channel2
-Split window 3: win#5 - efnet/#channel1, win#6 - efnet/#channel2
-</pre>
-
-<p>ëÏÇÄÁ ×Ù × ÏËÎÅ win#1 ÎÁÖÉÍÁÅÔÅ ALT-6, irssi ÐÅÒÅËÌÀÞÁÅÔÓÑ ÎÁ ÒÁÚÄÅÌÅÎÎÏÅ ÏËÎÏ
-#3 É ÐÅÒÅÍÅÝÁÅÔ ËÁÎÁÌ efnet/#channel2 × ÁËÔÉ×ÎÏÅ ÏËÎÏ.</p>
-
-<p>ðÒÉ "ÎÅÚÁËÒÅÐÌ£ÎÎÏÍ" ×ÁÒÉÁÎÔÅ ÏËÎÁ ÎÅ ÉÍÅÀÔ ÎÉËÁËÏÊ Ó×ÑÚÉ Ó ÒÁÚÄÅÌÅÎÎÙÍÉ ÏËÎÁÍÉ
-É ÎÁÖÁÔÉÅ ALT-6 × ÏËÎÅ win#1 ÐÅÒÅÍÅÝÁÅÔ ÏËÎÏ win#6 × ÒÁÚÄÅÌÅÎÎÏÅ ÏËÎÏ 1
-É ÄÅÌÁÅÔ ÅÇÏ ÁËÔÉ×ÎÙÍ, ÉÓËÌÀÞÅÎÉÅ ÍÏÖÅÔ ÂÙÔØ ËÏÇÄÁ ÏËÎÏ win#6 ÕÖÅ ×ÉÄÉÍÏ × ËÁËÏÍ-ÔÏ ÄÒÕÇÏÍ
-ÒÁÚÄÅÌÅÎÎÏÍ ÏËÎÅ, irssi ÐÒÏÓÔÏ ÐÅÒÅËÌÀÞÁÅÔÓÑ Ë ÜÔÏÍÕ ÒÁÚÄÅÌÅÎÎÏÍÕ ÏËÎÕ. ôÁËÏÊ ÍÅÔÏÄ ÐÅÒÅËÌÀÞÅÎÉÑ ÍÅÖÄÕ ÏËÎÁÍÉ ÐÒÉÍÅÎÑÅÔÓÑ × ircII É ÅÓÌÉ ÏÎ ×ÁÍ ÐÏÎÒÁ×ÉÌÓÑ ÔÏ ×Ù ÍÏÖÅÔÅ ÁËÔÉ×ÉÚÉÒÏ×ÁÔØ ÅÇÏ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄÙ</p>
-
-<pre>
-/SET autostick_split_windows OFF
-</pre>
-
-<p>ëÁÖÄÏÅ ÏËÎÏ ×ÎÕÔÒÉ ÓÅÂÑ ÍÏÖÅÔ ÓÏÄÅÒÖÁÔØ ÍÎÏÇÏ ËÁÎÁÌÏ×, ÐÒÉ×ÁÔÏ× É ÄÒÕÇÉÈ "×ÅÝÅÊ". åÓÌÉ ×Ù ×ÏÏÂÝÅ ÎÅ ÌÀÂÉÔÅ ÏËÎÁ, ÔÏ ×Ù ÍÏÖÅÔÅ ÏÔÍÅÎÉÔØ ÉÈ ËÏÍÁÎÄÏÊ</p>
-
-<pre>
-/SET autocreate_windows OFF [format c: ÎÁÄ£ÖÎÅÅ ;) - ÐÒÉÍ. ÐÅÒÅ×.]
-</pre>
-
-<p>é ÅÓÌÉ ×Ù ÄÅÒÖÉÔÅ ×ÓÅ ËÁÎÁÌÙ × ÏÄÎÏÍ ÏËÎÅ, ÔÏ ×ÁÍ ÎÁ×ÅÒÎÏÅ ÚÁÈÏÞÅÔÓÑ ÞÔÏÂÙ ÉÍÑ ËÁÎÁÌÁ ×Ù×ÏÄÉÌÏÓØ × ËÁÖÄÏÍ ÓÏÏÂÝÅÎÉÉ:</p>
-
-<pre>
-/SET print_active_channel ON
-</pre>
-
-<p>åÓÌÉ ×Ù ÈÏÔÉÔÅ ÓÇÒÕÐÐÉÒÏ×ÁÔØ × ËÁËÏÅ-ÔÏ ÏËÎÏ ÔÏÌØËÏ ÎÅËÏÔÏÒÙÅ ËÁÎÁÌÙ ÉÌÉ ÐÒÉ×ÁÔÙ, ÔÏ ÉÓÐÏÌØÚÕÊÔÅ ÜÔÉ ËÏÍÁÎÄÙ:</p>
-
-<pre>
-/JOIN -window #channel
-/QUERY -window nick
-</pre>
-
-<h3><a id="c3">3. á×ÔÏÚÁÈÏÄ ÎÁ ËÁÎÁÌÙ É ÓÅÒ×ÅÒÙ</a></h3>
-
-<p>÷ Irssi ÍÎÏÇÏÓÅÒ×ÅÒÎÁÑ ÐÏÄÄÅÒÖËÁ éíèï ÏÞÅÎØ ÈÏÒÏÛÁÑ :). äÁÖÅ ÅÓÌÉ ×Ù ÈÏÔÉÔÅ ÏÂÝÁÔØÓÑ ÔÏÌØËÏ × ÏÄÎÏÊ ÓÅÔÉ, ÔÏ ÏÞÅÎØ ÕÄÏÂÎÏ ÓÇÒÕÐÐÉÒÏ×ÁÔØ ×ÓÅ ÓÅÒ×ÅÒÙ ÜÔÏÊ ÓÅÔÉ × ÏÄÎÕ ÇÒÕÐÐÕ Ô.Ë. ÜÔÏ ÐÏÍÏÇÁÅÔ × ÓÌÕÞÁÅ ÎÅ×ÏÚÍÏÖÎÏÓÔÉ ÓÏÅÄÉÎÅÎÉÑ Ó ÇÌÁ×ÎÙÍ ÓÅÒ×ÅÒÏÍ É × ÎÅËÏÔÏÒÙÈ ÄÒÕÇÉÈ ÓÌÕÞÁÑÈ :).
-äÏÐÏÌÎÉÔÅÌØÎÕÀ ÉÎÆÏÒÍÁÃÉÀ Ï ÜÆÆÅËÔÉ×ÎÏÍ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÍÎÏÇÏÓÅÒ×ÅÒÎÏÊ ÐÏÄÄÅÒÖËÉ ÓÍÏÔÒÉÔÅ × ÇÌÁ×Å 6.</p>
-
-<p>äÌÑ ÎÁÞÁÌÁ ×ÁÍ ÎÕÖÎÏ ÕÓÔÁÎÏ×ÉÔØ Ó×ÏÀ IRC-ÓÅÔØ, ÄÌÑ ÜÔÏÇÏ ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ <code>/IRCNET</code>,
-ÞÔÏÂÙ ÕÂÅÄÉÔÓÑ, ÞÔÏ ÏÎÁ ÅÝ£ ÎÅ ÕÓÔÁÎÏ×ÌÅÎÁ. åÓÌÉ ÏÎÁ ÎÅ ÕÓÔÁÎÏ×ÌÅÎÁ, ÔÏ ××ÅÄÉÔÅ <code>/IRCNET ADD
-ÉÍÑ_ÓÅÔÉ</code>. åÓÌÉ ×Ù ÈÏÔÉÔÅ, ÞÔÏÂÙ ËÁËÉÅ-ÔÏ ËÏÍÁÎÄÙ Á×ÔÏÍÁÔÉÞÅÓËÉ ×ÙÐÏÌÎÑÌÉÓØ ÐÒÉ ÐÏÄËÌÀÞÅÎÉÉ Ë ÜÔÏÊ ÓÅÔÉ, ÔÏ ×ÏÓÐÏÌØÚÕÊÔÅÓØ ÏÐÃÉÅÊ <code>-autosendcmd</code>.
-÷ÏÔ ÎÅËÏÔÏÒÙÅ ÐÒÉÍÅÒÙ:</p>
-
-<pre>
-/IRCNET ADD -autosendcmd '^msg bot invite' ircnet
-/IRCNET ADD -autosendcmd "/^msg nickserv ident pass;wait 2000" OFTC
-</pre>
-
-<p>ðÏÓÌÅ ÜÔÏÇÏ ×Ù ÄÏÌÖÎÙ ÄÏÂÁ×ÉÔØ Ë ÜÔÏÊ ÓÅÔÉ ÓÅÒ×ÅÒÙ. îÁÐÒÉÍÅÒ:</p>
-
-<pre>
-/SERVER ADD -auto -ircnet ircnet irc.kpnqwest.fi 6667
-/SERVER ADD -auto -ircnet worknet irc.mycompany.com 6667 ÐÁÒÏÌØ
-</pre>
-
-<p>ïÐÃÉÑ <code>-auto</code> ÕËÁÚÙ×ÁÅÔ, ÞÔÏ Ë ÜÔÏÍÕ ÓÅÒ×ÅÒÕ ÎÕÖÎÏ Á×ÔÏÍÁÔÉÞÅÓËÉ ÐÏÄËÌÀÞÁÔØÓÑ ÐÒÉ ÚÁÐÕÓËÅ.
-÷Ù ÎÅ ÄÏÌÖÎÙ ÐÏÍÅÞÁÔØ ÄÒÕÇÉÅ ÓÅÒ×ÅÒÙ ÔÏÊ-ÖÅ ÓÅÔÉ ÏÐÃÉÅÊ <code>-auto</code> - Irssi Á×ÔÏÍÁÔÉÞÅÓËÉ Ë ÎÉÍ ÐÏÄËÌÀÞÉÔÓÑ, ÅÓÌÉ ÓÅÒ×ÅÒ ÐÏÍÅÞÅÎÎÙÊ <code>-auto</code> ÎÅÄÏÓÔÕÐÅÎ.</p>
-
-<p>é ÎÁËÏÎÅÃ ËÁÎÁÌÙ:</p>
-
-<pre>
-/CHANNEL ADD -auto -bots *!*bot@host.org -botcmd "/^msg $0 op pass" #irssi efnet
-/CHANNEL ADD -auto #secret ircnet password
-</pre>
-
-<p>ïÐÃÉÉ <code>-bots</code> É <code>-botcmd</code> ÔÒÅÂÕÀÔ ÎÅÂÏÌØÛÏÇÏ ÐÏÑÓÎÅÎÉÑ.
-ïÎÉ ÉÓÐÏÌØÚÕÀÔÓÑ ÄÌÑ ÔÏÇÏ, ÞÔÏÂÙ Á×ÔÏÍÁÔÉÞÅÓËÉ ÄÁ×ÁÔØ ËÏÍÁÎÄÙ ÂÏÔÕ ÐÒÉ ÚÁÈÏÄÅ ÎÁ ËÁÎÁÌ,
-ÏÂÙÞÎÏ ÄÌÑ Á×ÔÏÍÁÔÉÞÅÓËÏÇÏ ÐÏÌÕÞÅÎÉÑ ÏÐÁ. ÷Ù ÍÏÖÅÔÅ ÚÁÄÁÔØ ÍÎÏÇÏ ÍÁÓÏË ÂÏÔÏ× ÐÒÉ ÐÏÍÏÝÉ ÏÐÃÉÉ
-<code>-bots</code>, ÒÁÚÄÅÌÅÎÎÏÊ ÐÒÏÂÅÌÁÍÉ (ÎÅ ÚÁÂÕÄØÔÅ ×ÚÑÔØ ÜÔÕ ÓÔÒÏËÕ × ËÁ×ÙÞÅË). ðÅÒÅÍÅÎÎÁÑ $0 × ÏÐÃÉÉ
-<code>-botcmd</code> ÕËÁÚÙ×ÁÅÔ ÎÁ ÐÅÒ×ÏÇÏ ÂÏÔÁ × ÓÐÉÓËÅ ÎÁÊÄÅÎÎÙÈ. åÓÌÉ ×Ù ÎÅ ÈÏÔÉÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ÍÁÓËÉ ÄÌÑ ÂÏÔÏ× (ÎÁÐÒÉÍÅÒ ÅÓÌÉ ÂÏÔ ×ÓÅÇÄÁ ÓÉÄÉÔ ÐÏÄ ÏÄÎÉÍ ÎÉËÏÍ)
-×Ù ÍÏÖÅÔÅ ÕËÁÚÁÔØ ÔÏÌØËÏ ÏÐÃÉÀ <code>-botcmd</code> É ËÏÍÁÎÄÕ.</p>
-
-<h3><a id="c4">4. îÁÓÔÒÏÊËÁ ÏËÏÎ É Á×ÔÏÍÁÔÉÞÅÓËÏÅ ×ÏÓÓÔÁÎÏ×ÌÅÎÉÅ ÐÒÉ ÚÁÐÕÓËÅ</a></h3>
-
-<p>äÌÑ ÎÁÞÁÌÁ ÓÏÚÄÁÊÔÅ ÎÕÖÎÙÅ ÏËÎÁ(ÐÏÄËÌÀÞÉÔÅÓØ Ë ÎÕÖÎÙÍ ÓÅÒ×ÅÒÁÍ, ËÁÎÁÌÁÍ É.Ô.Ä.).
-äÌÑ ÐÅÒÅÍÅÝÅÎÉÑ ÏËÏÎ ÉÓÐÏÌØÚÕÊÔÅ ÓÌÅÄÕÀÝÉÅ ËÏÍÁÎÄÙ:</p>
-
-<pre>
-/WINDOW MOVE LEFT/RIGHT/ÎÏÍÅÒ - ÐÅÒÅÍÅÓÔÉÔØ ÏËÎÏ ×ÌÅ×Ï, ×ÐÒÁ×Ï ÉÌÉ ÎÁ ÕËÁÚÁÎÎÙÊ ÎÏÍÅÒ
-/WINDOW ITEM MOVE <ÎÏÍÅÒ>|<ÉÍÑ> - ÐÅÒÅÍÅÓÔÉÔØ ËÁÎÁÌ ÉÌÉ ÐÒÉ×ÁÔ × ÄÒÕÇÏÅ ÏËÎÏ
-</pre>
-
-<p>ëÏÇÄÁ ×Ó£ ×ÙÇÌÑÄÉÔ ÔÁË, ËÁË ×Ù ÈÏÔÉÔÅ, ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ <code>/LAYOUT SAVE</code>
- (É <code>/SAVE</code>, ÅÓÌÉ ÎÅ ×ËÌÀÞÅÎÏ Á×ÔÏÓÏÈÒÁÎÅÎÉÅ) É ËÏÇÄÁ ×Ù × ÓÌÅÄÕÀÝÉÊ ÒÁÚ ÚÁÐÕÓÔÉÔÅ irssi, ÔÏ ÏÎ ×ÓÐÏÍÎÉÔ ÐÏÚÉÃÉÉ ÓÏÈÒÁÎÅÎÎÙÈ ÏËÏÎ.
- üÔÏ "ÚÁÐÏÍÉÎÁÎÉÅ" ÎÅ ÏÚÎÁÞÁÅÔ, ÞÔÏ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ËÏÍÁÎÄÙ <code>/LAYOUT SAVE</code> ÂÕÄÅÔ ÐÒÉ×ÏÄÉÔØ Ë Á×ÔÏÍÁÔÉÞÅÓËÏÍÕ ÐÏÄËÌÀÞÅÎÉÀ Ë ÓÅÒ×ÅÒÁÍ É ÚÁÈÏÄÕ ÎÁ ËÁÎÁÌÙ,
- ÄÌÑ ÜÔÏÇÏ ×Ù ÄÏÌÖÎÙ ÉÓÐÏÌØÚÏ×ÁÔØ ËÏÍÁÎÄÙ <code>/SERVER ADD -auto</code> É <code>/CHANNEL ADD -auto</code>.</p>
-
-<p>þÔÏÂÙ ÉÚÍÅÎÉÔØ ÓÏÈÒÁÎÅÎÎÙÅ ÎÁÓÔÒÏÊËÉ ÏËÏÎ, ÒÁÓÓÔÁ×ØÔÅ ÉÈ × ÎÕÖÎÙÅ ÐÏÚÉÃÉÉ É ÚÁÎÏ×Ï ××ÅÄÉÔÅ ËÏÍÁÎÄÕ <code>/LAYOUT SAVE</code>.
-þÔÏÂÙ ÏÂÎÕÌÉÔØ ÎÁÓÔÒÏÊËÉ ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ <code>/LAYOUT RESET.</code></p>
-
-
-<h3><a id="c5">5. ïËÎÁ status É msgs & ÕÒÏ×ÎÉ ÓÏÏÂÝÅÎÉÊ</a></h3>
-
-<p>ðÏ ÕÍÏÌÞÁÎÉÀ "ÄÏÐÏÌÎÉÔÅÌØÎÙÅ ÓÏÏÂÝÅÎÉÑ" ×Ù×ÏÄÑÔÓÑ × ÏËÎÏ ÓÔÁÔÕÓÁ. ðÏÄ ÄÏÐÏÌÎÉÔÅÌØÎÙÍÉ ÐÏÄÒÁÚÕÍÅ×ÁÀÔÓÑ ÓÏÏÂÝÅÎÉÑ, ËÏÔÏÒÙÅ ÎÅ ÐÒÉÎÁÄÌÅÖÁÔ ÎÉ Ë ÏÄÎÏÍÕ ËÁÎÁÌÕ ÉÌÉ ÐÒÉ×ÁÔÕ(ÎÁÐÒÉÍÅÒ ctcp-ÚÁÐÒÏÓÙ).
-îÅËÏÔÏÒÙÈ ÌÀÄÅÊ ÏÎÉ ÒÁÚÄÒÁÖÁÀÔ, ÔÁË ÞÔÏ ÅÓÌÉ ×Ù ÈÏÔÉÔÅ ÉÈ ÓËÒÙÔØ, ÔÏ ××ÅÄÉÔÅ</p>
-
-<pre>
-/SET use_status_window OFF
-</pre>
-
-<p>üÔÏÔ ÐÁÒÁÍÅÔÒ ÚÁÒÁÂÏÔÁÅÔ ÔÏÌØËÏ ÐÏÓÌÅ ÐÅÒÅÚÁÐÕÓËÁ irssi. åÓÌÉ ×Ù ÈÏÔÉÔÅ ÕÄÁÌÉÔØ ÉÈ ÎÅÍÅÄÌÅÎÎÏ, ÔÏ ÐÒÏÓÔÏ ÚÁËÒÏÊÔÅ ÏËÎÏ(<code>/WINDOW CLOSE</code>).</p>
-
-<p>äÒÕÇÏÅ ÏÓÎÏ×ÎÏÅ ÏËÎÏ - ÜÔÏ "ÏËÎÏ ÓÏÏÂÝÅÎÉÊ", ËÕÄÁ ÉÄÕÔ ×ÓÅ ÓÏÏÂÝÅÎÉÑ ÐÒÉ×ÁÔÁ.
-ðÏ ÕÍÏÌÞÁÎÉÀ ÏÎÏ ÏÔËÌÀÞÅÎÏ É ×ÍÅÓÔÏ ÜÔÏÇÏ ÄÌÑ ËÁÖÄÏÇÏ ÐÒÉ×ÁÔÁ ÓÏÚÄÁÅÔÓÑ ÎÏ×ÏÅ ÏËÎÏ. þÔÏÂÙ ×ÓÅ ÓÏÏÂÝÅÎÉÑ ÐÒÉ×ÁÔÁ ÛÌÉ × ÏÄÎÏ ÏËÎÏ ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ:</p>
-
-<pre>
-/SET use_msgs_window ON
-/SET autocreate_query_level DCCMSGS (ÉÌÉ ÅÓÌÉ ×Ù ÔÁË-ÖÅ ÎÅ ÈÏÔÉÔÅ
- ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÅ ÏËÎÁ ÄÌÑ DCC-ÞÁÔÁ ÎÁÐÉÛÉÔÅ NONE)
-</pre>
-
-<p>üÔÏÔ ÐÁÒÁÍÅÔÒ ÔÁË-ÖÅ ÎÅ ÂÕÄÅÔ ÚÁÄÅÊÓÔ×Ï×ÁÎ ÄÏ ÐÅÒÅÚÁÐÕÓËÁ irssi. þÔÏÂÙ ÐÒÉÍÅÎÉÔØ ÅÇÏ ÎÅÍÅÄÌÅÎÎÏ ××ÅÄÉÔÅ:</p>
-
-<pre>
-/WINDOW NEW HIDE - ÓÏÚÄÁÔØ ÏËÎÏ
-/WINDOW NAME (msgs) - ÐÅÒÅÉÍÅÎÏ×ÁÔØ ÅÇÏ × "(msgs)"
-/WINDOW LEVEL MSGS - ÐÅÒÅÎÁÐÒÁ×ÉÔØ ×ÓÅ ÐÒÉ×ÁÔÎÙÅ ÓÏÏÂÝÅÎÉÑ × ÜÔÏ ÏËÎÏ
-/WINDOW MOVE 1 - ÓÄÅÌÁÔØ ÜÔÏ ÏËÎÏ ÐÅÒ×ÙÍ × ÓÐÉÓËÅ
-</pre>
-
-<p>õÞÔÉÔÅ, ÞÔÏ ÎÉ use_msgs_window, ÎÉ use_status_window ÎÅ ÂÕÄÕÔ ÒÁÂÏÔÁÔØ ÅÓÌÉ ÉÓÐÏÌØÚÏ×ÁÎÁ ËÏÍÁÎÄÁ <code>/LAYOUT SAVE</code>.</p>
-
-<p>ôÅÐÅÒØ ÍÙ ÐÏÄÏÛÌÉ Ë ÕÒÏ×ÎÑÍ ÓÏÏÂÝÅÎÉÊ.. þÔÏ ÜÔÏ? ÷ÓÅ ÓÏÏÂÝÅÎÉÑ, ËÏÔÏÒÙÅ ×Ù×ÏÄÉÔ irssi ÉÍÅÀÔ ÏÄÉÎ ÉÌÉ ÂÏÌØÛÅ
-"ÕÒÏ×ÅÎØ ÓÏÏÂÝÅÎÉÊ". ÷ÏÔ ÏÓÎÏ×ÎÙÅ ÕÒÏ×ÎÉ: PUBLIC - ÄÌÑ ÓÏÏÂÝÅÎÉÊ ÎÁ ËÁÎÁÌÁÈ,
-MSGS - ÄÌÑ ÐÒÉ×ÁÔÎÙÈ ÓÏÏÂÝÅÎÉÊ É CRAP ÄÌÑ ÏÓÔÁÌØÎÙÈ ÓÏÏÂÝÅÎÉÊ, ËÏÔÏÒÙÅ ÎÅÌØÚÑ ËÌÁÓÓÉÆÉÃÉÒÏ×ÁÔØ. ÷Ù ÍÏÖÅÔÅ ÐÏÌÕÞÉÔØ ÐÏÌÎÙÊ ÓÐÉÓÏË ÕÒÏ×ÎÅÊ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄÙ</p>
-
-<pre>
-/HELP levels
-</pre>
-
-<p>ïËÎÕ ÓÔÁÔÕÓÁ ÐÒÉÓ×ÏÅÎ ÕÒÏ×ÅÎØ <code>ALL -MSGS</code>, ËÏÔÏÒÙÊ ÐÏÄÒÁÚÕÍÅ×ÁÅÔ, ÞÔÏ ×ÓÅ ÓÏÏÂÝÅÎÉÑ,
-ÉÓËÌÀÞÁÑ ÐÒÉ×ÁÔÎÙÅ, ÄÌÑ ËÏÔÏÒÙÈ ÎÅ ÎÁÚÎÁÞÅÎÏ ÄÒÕÇÏÅ ÍÅÓÔÏ ÉÄÕÔ × ÜÔÏ ÏËÎÏ. âÌÁÇÏÄÁÒÑ ÏÐÃÉÉ <code>-MSGS</code> ÏÎÏ ÎÅ ËÏÎÆÌÉËÔÕÅÔ Ó ÏËÎÏÍ ÓÏÏÂÝÅÎÉÊ.</p>
-
-
-<h3><a id="c6">6. ëÁË × irssi ÒÁÂÏÔÁÅÔ ÍÎÏÇÏÓÅÒ×ÅÒÎÁÑ ÐÏÄÄÅÒÖËÁ</a></h3>
-
-<p>÷ ircII É ÎÅËÏÔÏÒÙÈ ÄÒÕÇÉÈ IRC-ËÌÉÅÎÔÁÈ ÍÎÏÇÏÓÅÒ×ÅÒÎÁÑ ÐÏÄÄÅÒÖËÁ ÒÅÁÌÉÚÏ×ÁÎÁ × ×ÉÄÅ ÐÏÍÅÝÅÎÉÑ ×ËÌÁÄËÉ Ó ÓÅÒ×ÅÒÏÍ × ÓÐÉÓÏË ÏËÏÎ
-. ÷ IRSSI îåô. îÅÔ ÎÉËÁËÏÊ Ó×ÑÚÉ ÍÅÖÄÕ ÏËÎÏÍ É ÓÅÒ×ÅÒÏÍ. ÷Ù ÍÏÖÅÔÅ ÐÏÄËÌÀÞÉÔØÓÑ Ë ÄÅÓÑÔÉ ÓÅÒ×ÅÒÁÍ ÏÄÎÏ×ÒÅÍÅÎÎÏ É ÕÐÒÁ×ÌÑÔØ ÉÍÉ ×ÓÅÍÉ ÉÚ ÏÄÎÏÇÏ ÏËÎÁ, ÉÌÉ ÚÁÈÏÄÉÔØ ÎÁ ËÁÎÁÌÙ ÎÁ ËÁÖÄÏÍ ÉÚ ÎÉÈ
-× ÏÄÎÏÍ ÏËÎÅ, ÅÓÌÉ ×Ù ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÜÔÏÇÏ ÈÏÔÉÔÅ. ëÁË ÂÙÌÏ ÓËÁÚÁÎÏ ×Ù ÍÏÖÅÔÅ ÐÏÄËÌÀÞÉÔØÓÑ Ë ÎÏ×ÏÍÕ ÓÅÒ×ÅÒÕ, ÎÅ ÚÁËÒÙ×ÁÑ ÔÅËÕÝÅÇÏ ÓÏÅÄÉÎÅÎÉÑ:</p>
-
-<pre>
-/CONNECT irc.server.org
-</pre>
-
-<p>÷ÍÅÓÔÏ ËÏÍÁÎÄÙ <code>/SERVER</code>, ËÏÔÏÒÁÑ ÚÁËÒÙ×ÁÅÔ ÓÕÝÅÓÔ×ÕÀÝÅÅ
-ÓÏÅÄÉÎÅÎÉÅ. þÔÏÂÙ ÐÏÓÍÏÔÒÅÔØ ÓÐÉÓÏË ÏÓÕÝÅÓÔ×ÌÅÎÎÙÈ ÓÏÅÄÉÎÅÎÉÊ ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ <code>/SERVER</code>
-ÂÅÚ ÐÁÒÁÍÅÔÒÏ×. ÷Ù Õ×ÉÄÉÔÅ ÐÒÉÍÅÒÎÏ ÓÌÅÄÕÀÝÅÅ:</p>
-
-<pre>
--!- IRCNet: irc.song.fi:6667 (IRCNet)
--!- OFTC: irc.oftc.net:6667 (OFTC)
--!- RECON-1: 192.168.0.1:6667 () (02:59 left before reconnecting)
-</pre>
-
-<p>úÄÅÓØ ×ÉÄÎÏ, ÞÔÏ ÍÙ ÐÏÄËÌÀÞÅÎÙ Ë ÓÅÔÑÍ IRCNet É OFTC.
-îÁÄÐÉÓØ IRCNet × ÎÁÞÁÌÅ Ñ×ÌÑÅÔÓÑ "ÍÅÔËÏÊ ÓÅÒ×ÅÒÁ" Á
-(IRCnet) × ËÏÎÃÅ ÐÏËÁÚÙ×ÁÅÔ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÕÀ IRC-ÓÅÔØ. íÅÔËÁ ÓÅÒ×ÅÒÁ ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÕÎÉËÁÌØÎÏÍÕ ÉÍÅÎÉ, ËÏÔÏÒÏÅ ÏÂÙÞÎÏ ÓÏ×ÐÁÄÁÅÔ Ó ÎÁÚ×ÁÎÉÅÍ ÓÅÔÉ.
-ëÏÇÄÁ IRC-ÓÅÔØ ÎÅ ÉÚ×ÅÓÔÎÁ ÜÔÏ ËÁËÁÑ-ÔÏ ÞÁÓÔØ ÉÍÅÎÉ ÓÅÒ×ÅÒÁ.
-ëÏÇÄÁ ÏÓÕÝÅÓÔ×ÌÅÎÙ ÎÅÓËÏÌØËÏ ÓÏÅÄÉÎÅÎÉÊ Ó ÏÄÎÏÊ ÓÅÔØÀ ÉÌÉ ÓÅÒ×ÅÒÏÍ, irssi
-ÄÏÂÁ×ÌÑÅÔ ÃÉÆÒÕ ÐÏÓÌÅ ÍÅÔËÉ, ÔÁË ÞÔÏ ÜÔÏ ÍÏÖÅÔ ÂÙÔØ ircnet, ircnet2, ircnet3
-É.Ô.Ä.</p>
-
-<p>íÅÔËÁ ÓÅÒ×ÅÒÁ, ÎÁÞÉÎÁÀÝÁÑÓÑ Ó <code>RECON-</code> ÏÂÏÚÎÁÞÁÅÔ ÐÅÒÅÐÏÄËÌÀÞÅÎÉÅ.
-÷ ×ÙÛÅÐÒÉ×ÅÄÅÎÎÏÍ ÐÒÉÍÅÒÅ ÍÙ ×ÉÄÉÍ, ÞÔÏ ÐÏÄËÌÀÞÅÎÉÅ Ë ÓÅÒ×ÅÒÕ 192.168.0.1 ÂÙÌÏ ÎÅÕÄÁÞÎÙÍ É
-irssi ÐÏÐÒÏÂÕÅÔ ÐÏÄËÌÀÞÉÔØÓÑ ÚÁÎÏ×Ï ÞÅÒÅÚ 3 ÍÉÎÕÔÙ.</p>
-
-<p>þÔÏÂÙ ÏÔËÌÀÞÉÔØÓÑ ÏÔ ÓÅÒ×ÅÒÁ ÉÓÐÏÌØÚÕÊÔÅ ÓÌÅÄÕÀÝÉÅ ËÏÍÁÎÄÙ:</p>
-
-<pre>
-/DISCONNECT ircnet - ÏÔËÌÀÞÉÔØÓÑ ÏÔ ÓÅÒ×ÅÒÁ Ó ÍÅÔËÏÊ "ircnet"
-/DISCONNECT recon-1 - ÏÓÔÁÎÏ×ÉÔØ ÐÏÐÙÔËÉ ÐÅÒÅÐÏÄËÌÀÞÅÎÉÑ Ë ÓÅÒ×ÅÒÕ RECON-1
-/RMRECONNS - ÏÓÔÁÎÏ×ÉÔØ ×ÓÅ ÐÏÐÙÔËÉ ÐÅÒÅÐÏÄËÌÀÞÅÎÉÑ
-
-/RECONNECT recon-1 - ÎÅÍÅÄÌÅÎÎÏ ÐÏÐÒÏÂÏ×ÁÔØ ÐÅÒÅÐÏÄËÌÀÞÉÔØÓÑ Ë RECON-1
-/RECONNECT ALL - ÎÅÍÅÄÌÅÎÎÏ ÐÏÐÒÏÂÏ×ÁÔØ ÐÅÒÅÐÏÄËÌÀÞÉÔØÓÑ ËÏ ×ÓÅÍ ÓÅÒ×ÅÒÁÍ
- × ÏÞÅÒÅÄÉ ÎÁ ÐÏÄËÌÀÞÅÎÉÅ
-</pre>
-
-<p>ôÅÐÅÒØ, ËÏÇÄÁ ×Ù ÐÏÄËÌÀÞÅÎÙ ËÏ ×ÓÅÍ ÓÅÒ×ÅÒÁÍ ×Ù ÄÏÌÖÎÙ ÚÎÁÔØ ËÁË ÕËÁÚÁÔØ ËÁËÏÊ ÉÚ ÎÉÈ ×Ù ÈÏÔÉÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ.
-åÄÉÎÓÔ×ÅÎÎÙÊ ÓÐÏÓÏ - ÜÔÏ ÉÍÅÔØ ÐÕÓÔÏÅ ÏËÎÏ ÎÁÐÏÄÏÂÅ ÏËÎÁ ÓÔÁÔÕÓÁ. ÷ ÎÅÍ ×Ù ÍÏÖÅÔÅ ×ÙÂÒÁÔØ ËÁËÏÊ ÓÅÒ×ÅÒ ÈÏÔÉÔÅ ÓÄÅÌÁÔØ ÁËÔÉ×ÎÙÍ</p>
-
-<pre>
-/WINDOW SERVER tag - ÓÄÅÌÁÔØ ÓÅÒ×ÅÒ Ó ÍÅÔËÏÊ "tag" ÁËÔÉ×ÎÙÍ
-Ctrl-X - óÄÅÌÁÔØ ÓÌÅÄÕÀÝÉÊ × ÓÐÉÓËÅ ÓÅÒ×ÅÒ ÁËÔÉ×ÎÙÍ
-</pre>
-
-<p>ëÏÇÄÁ ÓÅÒ×ÅÒ ÁËÔÉ×ÎÙÊ ×Ù ÍÏÖÅÔÅ ÎÏÒÍÁÌØÎÏ ÅÇÏ ÉÓÐÏÌØÚÏ×ÁÔØ. ëÏÇÄÁ ×Ù ÐÏÄËÌÀÞÅÎÙ Ë ÎÅÓËÏÌØËÉÍ ÓÅÒ×ÅÒÁÍ, irssi ÄÏÂÁ×ÌÑÅÔ ÐÒÅÆÉËÓ [ÍÅÔËÁ_ÓÅÒ×ÅÒÁ]
-ËÏ ×ÓÅÍ ÓÏÏÂÝÅÎÉÑÍ, ÎÅ ÏÔÎÏÓÑÝÉÍÓÑ Ë ËÁÎÁÌÕ ÉÌÉ ÐÒÉ×ÁÔÕ ÔÁË ÞÔÏ ×Ù ÍÏÖÅÔÅ ÚÎÁÔØ Ó ËÁËÏÇÏ ÓÅÒ×ÅÒÁ ÏÎÏ ÐÒÉÛÌÏ.</p>
-
-<p>îÅËÏÔÏÒÙÅ ËÏÍÁÎÄÙ ÔÁË-ÖÅ ÐÏÚ×ÏÌÑÀÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÏÐÃÉÀ <code>-ÍÅÔËÁ_ÓÅÒ×ÅÒÁ</code>
-ÞÔÏÂÙ ÕËÁÚÁÔØ ÄÌÑ ËÁËÏÇÏ ÓÅÒ×ÅÒÁ ×Ù ÈÏÔÉÔŠţ ÉÓÐÏÌØÚÏ×ÁÔØ:</p>
-
-<pre>
-/MSG -ÍÅÔËÁ ÎÉË ÓÏÏÂÝÅÎÉÅ
-/JOIN -ÍÅÔËÁ #ËÁÎÁÌ
-/QUERY -ÍÅÔËÁ ÎÉË
-</pre>
-
-<p>á×ÔÏÄÏÐÏÌÎÅÎÉÅ ËÏÍÁÎÄÙ <code>/MSG</code> ÔÁË-ÖÅ Á×ÔÏÍÁÔÉÞÅÓËÉ ÄÏÂÁ×ÌÑÅÔ ÍÅÔËÕ ÓÅÒ×ÅÒÁ
- ËÏÇÄÁ ÎÉË ÎÅ ÎÁ ÁËÔÉ×ÎÏÍ ÓÅÒ×ÅÒÅ.</p>
-
-<p>ïËÎÏ ÓÅÒ×ÅÒÁ ÍÏÖÎÏ ÓÄÅÌÁÔØ ÚÁËÒÅÐÌ£ÎÎÙÍ. ëÏÇÄÁ ÏÎÏ ÚÁËÒÅÐÌÅÎÏ, ÔÏ ÏÎÏ ÎÉËÏÇÄÁ Á×ÔÏÍÁÔÉÞÅÓËÉ ÎÅ ÐÅÒÅËÌÀÞÉÔÓÑ ÎÁ ËÁËÏÅ-ÔÏ ÄÒÕÇÏÅ, É ÅÓÌÉ ÐÒÏÉÚÏÛÌÏ ÏÔËÌÀÞÅÎÉÅ ÏÔ ÓÅÒ×ÅÒÁ,
-ÔÏ ÏÎÏ ÎÅ ÂÕÄÅÔ ÉÍÅÔØ ÁËÔÉ×ÎÏÇÏ ÓÅÒ×ÅÒÁ. ëÏÇÄÁ Ë ÓÅÒ×ÅÒÕ ÓÎÏ×Á ÐÒÏÉÚ×ÅÄÅÎÏ ÐÏÄËÌÀÞÅÎÉÅ,
-ÔÏ ÏÎ Á×ÔÏÍÁÔÉÞÅÓËÉ ÓÔÁÎÏ×ÉÔÓÑ ÁËÔÉ×ÎÙÍ × ÜÔÏÍ ÏËÎÅ. þÔÏÂÙ ÚÁËÒÅÐÉÔØ ÏËÎÏ ÓÅÒ×ÅÒÁ ÉÓÐÏÌØÚÕÊÔÅ ÓÌÅÄÕÀÝÕÀ ËÏÍÁÎÄÕ:</p>
-
-<pre>
-/WINDOW SERVER -sticky tag
-</pre>
-
-<p>üÔÏ ÐÏÌÅÚÎÏ ÅÓÌÉ ×Ù ÈÏÔÉÔÅ ÉÍÅÔØ ÏÔÄÅÌØÎÙÅ ÏËÎÁ ÓÔÁÔÕÓÁ É ÓÏÏÂÝÅÎÉÊ ÄÌÑ ËÁÖÄÏÇÏ ÓÅÒ×ÅÒÁ. ÷ÏÔ ËÁË ÜÔÏ ÍÏÖÎÏ ÓÄÅÌÁÔØ (ÐÏ×ÔÏÒÉÔÅ ÄÌÑ ËÁÖÄÏÇÏ ÓÅÒ×ÅÒÁ):</p>
-
-<pre>
-/WINDOW NEW HIDE
-/WINDOW NAME (status)
-/WINDOW LEVEL ALL -MSGS
-/WINDOW SERVER -sticky ircnet
-
-/WINDOW NEW HIDE
-/WINDOW NAME (msgs)
-/WINDOW LEVEL MSGS
-/WINDOW SERVER -sticky ircnet
-</pre>
-
-<h3><a id="c7">7. ëÏÍÁÎÄÁ /LASTLOG É ÐÒÏËÒÕÔËÁ ÏËÏÎ</a></h3>
-
-<p>ëÏÍÁÎÄÁ <code>/LASTLOG</code> ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎÁ ÄÌÑ ÐÏÉÓËÁ ÔÅËÓÔÁ × ÂÕÆÅÒÅ ÏËÎÁ. ÷ÏÔ ÐÒÏÓÔÅÊÛÉÅ ÐÒÉÍÅÒ٠ţ ÉÓÐÏÌØÚÏ×ÁÎÉÑ:</p>
-
-<pre>
-/LASTLOG ÓÌÏ×Ï - ×Ù×ÅÓÔÉ ×ÓÅ ÓÔÒÏËÉ, ÓÏÄÅÒÖÁÝÉÅ "ÓÌÏ×Ï"
-/LASTLOG word 10 - ×Ù×ÅÓÔÉ ÐÏÓÌÅÄÎÉÅ 10 ÓÔÒÏË, ÓÏÄÅÒÖÁÝÉÈ "word"
-/LASTLOG -topics - ×Ù×ÅÓÔÉ ×ÓÅ ÉÚÍÅÎÅÎÉÑ ÔÏÐÉËÁ
-</pre>
-
-<p>åÓÌÉ ÒÅÚÕÌØÔÁÔÏÍ ×Ù×ÏÄÁ ÄÏÌÖÎÙ ÓÔÁÔØ ÂÏÌÅÅ 1000 ÓÔÒÏË, ÔÏ irssi ÐÒÅÄÐÏÌÏÖÉÔ, ÞÔÏ ×Ù ÄÏÐÕÓÔÉÌÉ ÏÛÉÂËÕ É ×Ù×ÅÄÅÔ ÉÈ ÔÏÌØËÏ Ó ÏÐÃÉÅÊ <code>-force</code>.
-þÔÏÂÙ ÓÏÈÒÁÎÉÔØ ÓÏÄÅÒÖÉÍÏÅ ÂÕÆÅÒÁ ÏËÎÁ × ÆÁÊÌ, ÉÓÐÏÌØÚÕÊÔÅ ÓÌÅÄÕÀÝÕÀ ËÏÍÁÎÄÕ:</p>
-
-<pre>
-/LASTLOG -file ~/irc.log
-</pre>
-
-<p>ðÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÏÐÃÉÉ <code>-file</code> ÏÐÃÉÑ <code>-force</code>
-ÎÅ ÔÒÅÂÕÅÔÓÑ. õ ËÏÍÁÎÄÙ <code>/LASTLOG</code> ÅÓÔØ ÍÎÏÇÏ ÄÒÕÇÉÈ ÏÐÃÉÊ. þÔÏÂÙ ÐÏÌÕÞÉÔØ ÂÏÌÅÅ ÐÏÄÒÏÂÎÕÀ ÓÐÒÁ×ËÕ ÐÏ ÎÅÊ ÉÓÐÏÌØÚÕÊÔÅ <code>/HELP lastlog</code>.</p>
-
-<p>ëÏÇÄÁ ×Ù ÎÁÛÌÉ ÉÎÔÅÒÅÓÏ×Á×ÛÉÅ ×ÁÓ ÓÔÒÏËÉ, ×ÁÍ ÓËÏÒÅÅ ×ÓÅÇÏ ÚÁÈÏÞÅÔÓÑ ÐÏÓÍÏÔÒÅÔØ ÄÒÕÇÉÅ ÐÒÉÌÅÇÁÀÝÉÅ Ë ÎÉÍ ÓÏÏÂÝÅÎÉÑ. ÷ Irssi ÅÓÔØ ËÏÍÁÎÄÁ <code>/SCROLLBACK</code> (ÉÌÉ
-Å£ ÓÉÎÏÎÉÍ - <code>/SB</code>) ÄÌÑ ÐÅÒÅÍÅÝÅÎÉÑ ÐÏ ÂÕÆÅÒÕ ÏËÎÁ.
-ëÏÍÁÎÄÁ <code>/LASTLOG</code> ×Ù×ÏÄÉÔ ÏÒÉÇÉÎÁÌØÎÏÅ ×ÒÅÍÑ ÓÏÏÂÝÅÎÉÑ
- É ×Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ËÏÍÁÎÄÕ <code>/SB GOTO ÞÞ:ÍÍ</code> ÞÔÏÂÙ "ÐÅÒÅÐÒÙÇÎÕÔØ" Ë ÜÔÏÍÕ ÆÒÁÇÍÅÎÔÕ ÄÉÓËÕÓÓÉÉ.
- þÔÏÂÙ ÐÅÒÅÍÅÓÔÉÔØÓÑ ÏÂÒÁÔÎÏ ×ÎÉÚ ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ <code>/SB
-END</code>.</p>
-
-
-<h3><a id="c8">8. ÷ÅÄÅÎÉÅ ÌÏÇÏ×</a></h3>
-
-<p>Irssi ÍÏÖÅÔ Á×ÔÏÍÁÔÉÞÅÓËÉ ×ÅÓÔÉ ÌÏÇ ×ÓÅÈ ×ÁÖÎÙÈ ÓÏÏÂÝÅÎÉÊ ËÏÇÄÁ ×Ù × Ü×ÅÅ
-(<code>/AWAY ÐÒÉÞÉÎÁ</code>). ËÏÇÄÁ ×Ù ×ÙÛÌÉ ÉÚ Ü×ÅÑ
-(ÅÝ£ ÒÁÚ ××ÅÄÉÔÅ <code>/AWAY</code>), ÎÏ×ÙÅ ÓÏÏÂÝÅÎÉÑ × Ü×ÅÊ-ÌÏÇÅ ×Ù×ÏÄÑÔÓÑ ÎÁ ÜËÒÁÎ.
-÷Ù ÍÏÖÅÔÅ ÎÁÓÔÒÏÉÔØ ÅÇÏ ÐÒÉ ÐÏÍÏÝÉ ÓÌÅÄÕÀÝÉÈ ËÏÍÁÎÄ:</p>
-
-<pre>
-/SET awaylog_level MSGS HILIGHT - ÷ÙÂÉÒÁÅÔ ËÁËÏÅ ÓÏÏÂÝÅÎÉÑ ÎÁÄÏ ÚÁÐÉÓÙ×ÁÔØ × ÌÏÇ
-/SET awaylog_file ~/.irssi/away.log - ÷ÙÂÉÒÁÅÔ ÆÁÊÌ ÄÌÑ ÌÏÇÁ
-</pre>
-
-<p>ðÒÏÓÔÅÊÛÉÊ ÓÐÏÓÏ ×ÅÄÅÎÉÑ ÌÏÇÏ× ÐÒÉ ÐÏÍÏÝÉ Irssi - ×ËÌÀÞÅÎÉÅ Á×ÔÏÌÏÇÁ.
-Irssi ÂÕÄÅÔ ×ÅÓÔÉ ÌÏÇÉ ×ÓÅÈ ÓÏÏÂÝÅÎÉÊ × ÚÁÄÁÎÎÙÊ ËÁÔÁÌÏÇ.
-÷Ù ÍÏÖÅÔÅ ×ËÌÀÞÉÔØ ÅÇÏ ÐÒÉ ÐÏÍÏÝÉ ÓÌÅÄÕÀÝÅÊ ËÏÍÁÎÄÙ:</p>
-
-<pre>
-/SET autolog ON
-</pre>
-
-<p>ðÏ ÕÍÏÌÞÁÎÉÀ × ÌÏÇÉ ÚÁÐÉÓÙ×ÁÅÔÓÑ ÐÏÞÔÉ ×Ó£ ËÒÏÍÅ ÕÒÏ×ÎÅÊ CTCPS ÉÌÉ CRAP
-(<code>/WHOIS</code>-ÚÁÐÒÏÓÙ É.Ô.Ä.). ÷Ù ÍÏÖÅÔÅ ÚÁÄÁÔØ ÕÒÏ×ÎÉ ÓÏÏÂÝÅÎÉÊ, ËÏÔÏÒÙÅ ÎÁÄÏ ÐÉÓÁÔØ × ÌÏÇÉ ÓÌÅÄÕÀÝÅÊ ËÏÍÁÎÄÏÊ:</p>
-
-<pre>
-/SET autolog_level ALL -CRAP -CLIENTCRAP -CTCPS (this is the default)
-</pre>
-
-<p>ðÏ ÕÍÏÌÞÁÎÉÀ irssi ÐÉÛÅÔ ÌÏÇ × ~/irclogs/<ÍÅÔËÁ_ÓÅÒ×ÅÒÁ>/<ÃÅÌØ>.log.
-üÔÏ ÎÁÓÔÒÁÉ×ÁÅÔÓÑ ÓÌÅÄÕÀÝÅÊ ËÏÍÁÎÄÏÊ:</p>
-
-<pre>
-/SET autolog_path ~/irclogs/$tag/$0.log (×ÁÒÉÁÎÔ "ÐÏ ÕÍÏÌÞÁÎÉÀ")
-</pre>
-
-<p>åÓÌÉ ÚÁÄÁÎÎÙÊ ËÁÔÁÌÏÇ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ, ÔÏ ÏÎ Á×ÔÏÍÁÔÉÞÅÓËÉ ÓÏÚÄÁÅÔÓÑ. ÷ ÐÅÒÅÍÅÎÎÏÊ $0
-ÓÏÄÅÒÖÉÔÓÑ ÃÅÌØ(ËÁÎÁÌ ÉÌÉ ÎÉË). ÷Ù ÍÏÖÅÔÅ ÎÁÓÔÒÏÉÔØ Irssi ÔÁË, ÞÔÏÂÙ ÏÎ Á×ÔÏÍÁÔÉÞÅÓËÉ ÄÏÂÁ×ÌÑÌ ÄÁÔÕ/×ÒÅÍÑ Ë ÉÍÅÎÉ ÆÁÊÌÁ Ó ÌÏÇÏÍ.
-÷ÏÒÍÁÔ ÄÁÔÙ - "man strftime" :). ÷ÏÔ ÐÒÉÍÅÒ:</p>
-
-<pre>
-/SET autolog_path ~/irclogs/%Y/$tag/$0.%m-%d.log
-</pre>
-
-<p>þÔÏÂÙ ×ÅÓÔÉ ÌÏÇÉ ÔÏÌØËÏ ÐÏ ËÁËÉÍ-ÔÏ ÏÔÄÅÌØÎÙÍ ËÁÎÁÌÁÍ ÉÌÉ ÎÉËÁÍ ÓÍÏÔÒÉÔÅ <code>/HELP
-log</code></p>
-
-
-<h3><a id="c9">9. éÚÍÅÎÅÎÉÅ ËÌÁ×ÉÁÔÕÒÎÙÈ ÓÏÞÅÔÁÎÉÊ</a></h3>
-
-<p>÷Ù ÍÏÖÅÔÅ ÉÚÍÅÎÉÔØ ÌÀÂÏÅ ËÌÁ×ÉÁÔÕÒÎÏÅ ÓÏÞÅÔÁÎÉÅ, Ï ËÏÔÏÒÏÍ ÔÅÒÍÉÎÁÌ ÄÁ£Ô ÚÎÁÔØ irssi.
-ôÏ ÅÓÔØ irssi "×ÉÄÉÔ" ÎÅ ×ÓÅ ËÌÁ×ÉÁÔÕÒÎÙÅ ÓÏÞÅÔÁÎÉÑ, ÎÁÐÒÉÍÅÒ ÏÎ ÎÅ ÂÕÄÅÔ ÒÅÁÇÉÒÏ×ÁÔØ ÎÁ
-shift-backspace ÅÓÌÉ ×Ù ËÁË-ÔÏ ÎÅ ÏÔÒÅÄÁËÔÉÒÕÅÔÅ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÅ X-ÒÅÓÕÒÓÙ.</p>
-
-<p>ëÏÍÁÎÄÁ <code>/HELP bind</code> ÄÁ£Ô ÎÁÍÎÏÇÏ ÂÏÌØÛÅ ÉÎÆÏÒÍÁÃÉÉ Ï ËÌÁ×ÉÁÔÕÒÎÙÈ ÓÏÞÅÔÁÎÉÑÈ, ÞÅÍ ÐÒÉ×ÅÄÅÎÏ ÚÄÅÓØ.
-ïÂÙÞÎÏ ÐÒÏÂÌÅÍÍÏÊ Ñ×ÌÑÅÔÓÑ "ÚÁÂÉ×ÁÎÉÅ" ËÁËÉÈ-ÔÏ ÎÅ ÓÔÁÎÄÁÒÔÎÙÈ ËÌÁ×ÉÛ.
-ïÎÉ ÎÅÍÎÏÇÏ ÒÁÚÌÉÞÎÙ ÄÌÑ ËÁÖÄÏÇÏ ÔÅÒÍÉÎÁÌÁ, ÔÁË ÞÔÏ ×Ù ÄÏÌÖÎÙ ÂÕÄÅÔÅ ÕÚÎÁÔØ ÞÔÏ ÉÍÅÎÎÏ ÄÁ£Ô ÎÁÖÁÔÉÅ ÜÔÏÊ ËÌÁ×ÉÛÉ.
-ðÒÏÓÔÅÊÛÉÊ ÐÕÔØ ÕÚÎÁÔØ ÜÔÏ - ×ÙÐÏÌÎÉÔØ × ËÏÎÓÏÌÉ <code>cat</code> É ÐÏÓÍÏÔÒÅÔØ ÞÔÏ ÂÕÄÅÔ ×Ù×ÏÄÉÔÓÑ ÐÒÉ ÎÁÖÁÔÉÉ ÜÔÏÊ ËÌÁ×ÉÛÉ.
-÷ÏÔ ÐÒÉÍÅÒ ÎÁÖÁÔÉÑ ËÌÁ×ÉÛÉ F1:</p>
-
-<pre>
-[cras@hurina] ~% cat
-^[OP
-</pre>
-
-<p>ôÁË ÞÔÏ × irssi ÞÔÏÂÙ "ÚÁÂÉÔØ" ÞÔÏ-ÔÏ ÎÁ F1 ×Ù ÄÏÌÖÎÙ ÂÕÄÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ËÏÍÁÎÄÕ <code>/BIND ^[OP /ECHO ÎÁÖÁÔÁ ËÌÁ×ÉÛÁ F1</code>.
-åÓÌÉ ×Ù ÉÓÐÏÌØÚÕÅÔÅ ÒÁÚÎÙÅ ÔÅÒÍÉÎÁÌÙ, ËÏÔÏÒÙÅ ÐÏ ÒÁÚÎÏÍÕ ÒÁÓÐÏÚÎÁÀÔ ÎÁÖÁÔÉÅ ÏÄÎÏÊ É ÔÏÊ-ÖÅ ËÌÁ×ÉÛÉ, ÔÏ ×ÁÍ ÌÕÞÛÅ ÉÓÐÏÌØÚÏ×ÁÔØ ÞÔÏ-ÔÏ ×ÒÏÄÅ ÜÔÏÇÏ:</p>
-
-<pre>
-/BIND ^[OP key F1
-/BIND ^[11~ key F1
-/BIND F1 /ECHO ÎÁÖÁÔÁ ËÌÁ×ÉÛÁ F1.
-</pre>
-
-<h3><a id="c10">10. ðÒÏËÓÉ É ÂÏÕÎÓÅÒÙ</a></h3>
-
-<p>Irssi ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÄËÌÀÞÅÎÉÅ Ë IRC-ÓÅÒ×ÅÒÁÍ ÞÅÒÅÚ ÐÒÏËÓÉ. åÓÌÉ ×Ù ×Ó£ ÐÒÁ×ÉÌØÎÏ ÓÄÅÌÁÅÔÅ, ÔÏ ×ÓÅ ÐÏÄËÌÀÞÅÎÉÑ ÂÕÄÕÔ ÏÓÕÝÅÓÔ×ÌÑÔØÓÑ ÞÅÒÅÚ ÎÅÇÏ É ×ÁÍ ÎÅ ÎÁÄÏ ÂÕÄÅÔ ××ÏÄÉÔØ ÎÉËÁËÉÈ ÄÏÐÏÌÎÉÔÅÌØÎÙÈ ËÏÍÁÎÄ.</p>
-
-<p>÷ÏÔ ÐÒÉÍÅÒ: õ ×ÁÓ ÅÓÔØ ÂÏÕÎÓÅÒ, ×ÉÓÑÝÉÊ ÎÁ
-irc.bouncer.org 5000. ÷Ù ÈÏÔÉÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ÅÇÏ ÄÌÑ ÐÏÄËÌÀÞÅÎÉÑ Ë ÓÅÒ×ÅÒÁÍ irc.dal.net É irc.efnet.org. äÌÑ ÎÁÞÁÌÁ ×Ù ÄÏÌÖÎÙ ÂÕÄÅÔÅ ÎÁÓÔÒÏÉÔØ ÂÏÕÎÓÅÒ:</p>
-
-<pre>
-/SET use_proxy ON (×ËÌÀÞÉÔØ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÐÒÏËÓÉ)
-/SET proxy_address irc.bouncer.org
-/SET proxy_port 5000
-
-/SET proxy_password ÷áû_ðáòïìø
-/SET -clear proxy_string
-/SET proxy_string_after conn %s %d
-</pre>
-
-<p>ðÏÔÏÍ ×ÁÍ ÎÕÖÎÏ ÂÕÄÅÔ ÄÏÂÁ×ÉÔØ ÎÕÖÎÙÅ ÓÅÒ×ÅÒÙ. üÔÏ ÄÅÌÁÅÔÓÑ ÔÏÞÎÏ ÔÁË-ÖÅ, ËÁË ÅÓÌÉ ÂÙ ×Ù ÈÏÔÅÌÉ ÐÏÄËÌÀÞÉÔØÓÑ Ë ÎÉÍ ÎÁÐÒÑÍÕÀ:</p>
-
-<pre>
-/SERVER ADD -auto -ircnet dalnet irc.dal.net
-/SERVER ADD -auto -ircnet efnet irc.efnet.org
-</pre>
-
-<p>ðÏÓÌÅ ÔÏÇÏ, ËÁË ×Ù ÓÄÅÌÁÌÉ ×ÙÛÅÐÅÒÅÞÉÓÌÅÎÎÙÅ ÎÁÓÔÒÏÊËÉ ×ÓÅ ÓÏÅÄÉÎÅÎÉÑ irssi ÂÕÄÅÔ ÐÒÏÉÚ×ÏÄÉÔØ ÞÅÒÅÚ ÐÒÏËÓÀ.</p>
-
-<p>åÓÌÉ ×Ù ÎÅ ÈÏÔÉÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ÐÒÏËÓÀ ÄÌÑ ËÁËÏÇÏ-ÔÏ ÓÅÒ×ÅÒÁ, ÔÏ ÐÒÉ ÅÇÏ ÄÏÂÁ×ÌÅÎÉÉ ÕËÁÖÉÔÅ ÏÐÃÉÀ
-<code>-noproxy</code>.</p>
-
-<p><strong>óÐÅÃÉÆÉÞÎÙÅ ÎÁÓÔÒÏÊËÉ ÄÌÑ ÒÁÚÎÙÈ ÔÉÐÏ× ÐÒÏËÓÉ:</strong></p>
-
-<p>ïÂÙÞÎÙÅ ÎÁÓÔÒÏÊËÉ:</p>
-
-<pre>
-/SET use_proxy ON
-/SET proxy_address <áÄÒÅÓ ÐÒÏËÓÉ>
-/SET proxy_port <ðÏÒÔ>
-</pre>
-
-<p><strong>HTTP proxy</strong></p>
-
-<p>éÓÐÏÌØÚÕÊÔÅ ÜÔÉ ÎÁÓÔÒÏÊËÉ ÄÌÑ HTTP-ÐÒÏËÓÉ:</p>
-
-<pre>
-/SET -clear proxy_password
-/EVAL SET proxy_string CONNECT %s:%d\n\n
-</pre>
-
-<p><strong>BNC</strong></p>
-
-<pre>
-/SET proxy_password ×ÁÛ_ÐÁÒÏÌØ
-/SET -clear proxy_string
-/SET proxy_string_after conn %s %d
-</pre>
-
-<p><strong>dircproxy</strong></p>
-
-<p>dircproxy ÐÒÏÉÚ×ÏÄÉÔ ÐÏÄËÌÀÞÅÎÉÑ Ë ÓÅÒ×ÅÒÁÍ ÐÏ ÐÁÒÏÌÑÍ. ôÁË ÞÔÏ ÅÓÌÉ ÎÁÐÒÉÍÅÒ ×Ù ÈÏÔÉÔÅ ÐÏÄËÌÀÞÉÔØÓÑ Ë ÓÅÒ×ÅÒÕ ircnet Ó ÐÁÒÏÌÅÍ ircpass
-É Ë OFTC Ó ÐÁÒÏÌÅÍ oftcpass, ×Ù ÄÏÌÖÎÙ ÓÄÅÌÁÔØ ÐÒÉÍÅÒÎÏ ÓÌÅÄÕÀÝÅÅ:</p>
-
-<pre>
-/SET -clear proxy_password
-/SET -clear proxy_string
-
-/SERVER ADD -auto -ircnet ircnet fake.ircnet 6667 ircpass
-/SERVER ADD -auto -ircnet OFTC fake.oftc 6667 oftcpass
-</pre>
-
-<p>éÍÑ ÓÅÒ×ÅÒÁ É ÐÏÒÔ, ËÏÔÏÒÙÅ ×Ù ××ÏÄÉÔÅ ÎÉÇÄÅ ÎÅ ÉÓÐÏÌØÚÕÀÔÓÑ, ÔÁË ÞÔÏ ×Ù ÍÏÖÅÔÅ ÐÉÓÁÔØ ÓÀÄÁ ×Ó£ ÞÔÏ ÕÇÏÄÎÏ.</p>
-
-<p><strong>psyBNC</strong></p>
-
-<p>psyBNC ÉÍÅÅÔ ×ÎÕÔÒÅÎÎÀÀ ÍÎÏÇÏÓÅÒ×ÅÒÎÕÀ ÐÏÄÄÅÒÖËÕ.
-üÔÏ ÍÏÖÅÔ ÄÏÓÔÁ×ÌÑÔØ ÎÅÂÏÌØÛÉÅ ÎÅÕÄÏÂÓÔ×Á É ÎÅËÏÔÏÒÙÅ ÌÀÄÉ ÐÒÏÓÔÏ ÉÓÐÏÌØÚÕÀÔ ÒÁÚÎÙÅ ÌÏÇÉÎÙ ÄÌÑ ÐÏÄËÌÀÞÅÎÉÑ Ë ÎÅÓËÏÌØËÉÍ ÓÅÒ×ÅÒÁÍ.
-÷Ù ÏÞÅÎØ ÐÒÏÓÔÏ ÍÏÖÅÔÅ ÄÅÌÁÔØ ÜÔÏ ÓÒÅÄÓÔ×ÁÍÉ Irssi:</p>
-
-<pre>
-/SET -clear proxy_password
-/SET -clear proxy_string
-
-/IRCNET ADD -user ircnetuser ircnet
-/SERVER ADD -auto -ircnet ircnet fake.ircnet 6667 ircpass
-/IRCNET ADD -user oftcuser OFTC
-/SERVER ADD -auto -ircnet OFTC fake.oftc 6667 oftcpass
-</pre>
-
-<p>úÄÅÓØ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄÙ <code>/IRCNET ADD</code> ×Ù ÚÁÄÁÅÔÅ ÉÍÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÅÊ
-É ÐÁÒÏÌÉ ÐÒÉ ÐÏÍÏÝÉ <code>/SERVER ADD</code>.</p>
-
-<p><strong>Irssi proxy</strong></p>
-
-<p>Irssi ×ËÌÀÞÁÅÔ Ó×ÏÀ ÓÏÂÓÔ×ÅÎÎÕÀ ÐÒÏËÓÀ, ËÏÔÏÒÕÀ ×Ù ÍÏÖÅÔÅ ÓÏÂÒÁÔØ ÐÒÉ ÐÏÍÏÝÉ ÏÐÃÉÉ configure
-<code>--with-proxy</code>. þÔÏÂ٠ţ ÉÓÐÏÌØÚÏ×ÁÔØ ×Ù ÄÏÌÖÎÙ ÏÓÔÁ×ÌÑÔØ irssi ÚÁÐÕÝÅÎÎÙÍ.</p>
-
-<p>Irssi-ÐÒÏËÓÑ ÎÅÍÎÏÇÏ ÏÔÌÉÞÁÅÔÓÑ ÏÔ ÏÓÔÁÌØÎÙÈ ÐÒÏËÓÉ-ÓÅÒ×ÅÒÏ×, ÎÏÒÍÁÌØÎÙÅ ÐÒÏËÓÉ ÓÏÚÄÁÀÔ ÎÏ×ÙÅ ÓÏÅÄÉÎÅÎÉÑ Ó IRC-ÓÅÒ×ÅÒÏÍ ËÏÇÄÁ ×Ù ÈÏÔÉÔÅ Ë ÎÅÍÕ ÐÏÄËÌÀÞÉÔØÓÑ, Á
-<strong>irssi-ÐÒÏËÓÑ ÉÓÐÏÌØÚÕÅÔ ÕÖÅ ÓÕÝÅÓÔ×ÕÀÝÅÅ ÓÏÅÄÉÎÅÎÉÅ(Ñ) ÄÌÑ ×ÓÅÈ ËÌÉÅÎÔÏ×</strong>. éÌÉ ÅÝ£ ÐÏÎÑÔÎÅÅ: <strong>÷Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ÔÏÌØËÏ ÏÄÎÏ ÓÏÅÄÉÎÅÎÉÅ Ó IRC-ÓÅÒ×ÅÒÏÍ ÄÌÑ ÎÅÏÇÒÁÎÉÞÅÎÎÏÇÏ ÞÉÓÌÁ ËÌÉÅÎÔÏ×</strong>.</p>
-
-<p>Irssi-ÐÒÏËÓÑ ÍÏÖÅÔ ÒÁÓÐÒÅÄÅÌÑÔØ ÎÅÓËÏÌØËÏ ÓÏÅÄÉÎÅÎÉÊ Ó ÓÅÒ×ÅÒÁÍÉ ÎÁ ÒÁÚÎÙÅ ÐÏÒÔÙ, ÎÁÐÒÉÍÅÒ ÎÁ 2777-ÏÍ ÐÏÒÔÕ Õ ×ÁÓ ÍÏÖÅÔ ÂÙÔØ ÓÏÅÄÉÎÅÎÉÅ Ó ircnet, Á ÎÁ 2778 Ó efnet.</p>
-
-<p>éÓÐÏÌØÚÏ×ÁÎÉÅ ÎÁ ÓÔÏÒÏÎÅ ÐÒÏËÓÉ:</p>
-
-<pre>
-/LOAD proxy
-/SET irssiproxy_password <ÐÁÒÏÌØ>
-/SET irssiproxy_ports <IRC_ÓÅÔØ>=<ÐÏÒÔ> ... (ÎÁÐÒÉÍÅÒ ircnet=2777 efnet=2778)
-</pre>
-<p>÷Ù <strong>ÄÏÌÖÎÙ</strong> ÄÏÂÁ×ÉÔØ ×ÓÅ ÓÅÒ×ÅÒÙ, ËÏÔÏÒÙÅ ×Ù ÉÓÐÏÌØÚÕÅÔÅ × ÓÐÉÓËÉ ÓÅÒ×ÅÒÏ× É ÓÅÔÅÊ
-ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄ <code>/SERVER ADD</code> É
-<code>/IRCNET ADD</code>. ..ÒÁÚ×Å ÞÔÏ ÅÓÌÉ ×Ù ÈÏÔÉÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ÔÏÌØËÏ ÏÄÎÏ ÓÏÅÄÉÎÅÎÉÅ, ÔÏ ×Ù ÍÏÖÅÔÅ ÕËÁÚÁÔØ:</p>
-
-<pre>
-/SET irssiproxy_ports *=2777
-</pre>
-
-<p>éÓÐÏÌØÚÏ×ÁÎÉÅ ÎÁ ÓÔÏÒÏÎÅ ËÌÉÅÎÔÁ:</p>
-
-<p>ðÒÏÓÔÏ ÐÏÄËÌÀÞÉÔÅÓØ Ë ÐÒÏËÓÅ ËÁË Ë ÎÏÒÍÁÌØÎÏÍÕ ÓÅÒ×ÅÒÕ Ó ÐÁÒÏÌÅÍ, ÚÁÄÁÎÎÙÍ ËÏÍÁÎÄÏÊ <code>/SET irssiproxy_password</code>. ðÒÉÍÅÒ:</p>
-
-<pre>
-/SERVER ADD -ircnet ircnet my.irssi-proxy.org 2777 secret
-/SERVER ADD -ircnet efnet my.irssi-proxy.org 2778 secret
-</pre>
-
-<p>Irssi-ÐÒÏËÓÑ ÔÁË-ÖÅ ÎÏÒÍÁÌØÎÏ ÒÁÂÏÔÁÅÔ Ó ÄÒÕÇÉÍÉ irc-ËÌÉÅÎÔÁÍÉ.</p>
-
-<p><strong>SOCKS</strong></p>
-
-Irssi ÍÏÖÅÔ ÂÙÔØ ÓÏÂÒÁÎ Ó ÐÏÄÄÅÒÖËÏÊ socks-ÐÒÏËÓÉ (ÏÐÃÉÑ configure <code>--with-socks</code>),
-ÎÏ Ñ ÎÁ ÓÁÍÏÍ ÄÅÌÅ ÎÅ ÚÎÁÀ ËÁË ÏÎÏ ÒÁÂÏÔÁÅÔ. îÁÓÔÒÏÊËÉ <code>/SET
-proxy</code> ÎÁ ÜÔÉ ÐÒÏËÓÉ ÎÉËÁË ÎÅ ÄÅÊÓÔ×ÕÀÔ.
-
-<p><strong>äÒÕÇÉÅ ÐÒÏËÓÉ</strong></p>
-
-<p>IRC-ÂÏÕÎÓÅÒÙ ÏÂÙÞÎÏ ÒÁÂÏÔÁÀÔ ÔÏÞÎÏ ÔÁË-ÖÅ ËÁË É IRC-ÓÅÒ×ÅÒÙ, ÎÏ ÐÒÏÓÑÔ ÐÁÒÏÌØ. ÷Ù ÍÏÖÅÔÅ ÄÁÔØ ÉÍ ÅÇÏ ÐÒÉ ÐÏÍÏÝÉ ÓÌÅÄÕÀÝÅÊ ËÏÍÁÎÄÙ:</p>
-
-<pre>
-/SET proxy_password <ÐÁÒÏÌØ>
-</pre>
-
-<p>CONNECT-ÓÔÒÏËÉ ÐÏ ÕÍÏÌÞÁÎÉÀ:</p>
-
-<pre>
-/SET proxy_string CONNECT %s %d
-/SET proxy_string_after
-</pre>
-
-<p>proxy_string ÏÔÐÒÁ×ÌÑÀÔÓÑ ÐÅÒÅÄ ËÏÍÁÎÄÁÍÉ NICK/USER, Á
-proxy_string_after ÏÔÐÒÁ×ÌÑÅÔÓÑ ÐÏÓÌÅ ÎÉÈ. %s and %d can be used with both
-of them.</p>
-
-<h3><a id="c11">11. îÁÓÔÒÏÊËÉ Irssi</a></h3>
-
-<p>÷ÁÍ ÍÏÇÕÔ ÎÅ ÐÏÎÒÁ×ÉÔÓÑ ÎÁÓÔÒÏÊËÉ Irssi ÐÏ ÕÍÏÌÞÁÎÉÀ.
-÷ÏÔ ÎÅËÏÔÏÒÙÅ ÉÚ ÎÉÈ, ËÏÔÏÒÙÅ ×Ù ÓËÏÒÅÅ ×ÓÅÇÏ ÚÁÈÏÔÉÔÅ ÉÚÍÅÎÉÔØ(× ÐÒÉÍÅÒÁÈ ÐÒÉ×ÅÄÅÎÙ "ÕÍÏÌÞÁÌØÎÙÅ" ÚÎÁÞÅÎÉÑ):</p>
-
-<p><strong>ïËÎÁ ÐÒÉ×ÁÔÏ×</strong></p>
-
-<dl>
-<dt>/SET autocreate_own_query ON</dt>
- <dd>á×ÔÏÍÁÔÉÞÅÓËÉ ÓÏÚÄÁ×ÁÔØ ÏËÎÏ ÐÒÉ×ÁÔÁ ËÏÇÄÁ ×Ù ÏÔÐÒÁ×ÌÑÅÔÅ ËÏÍÕ-ÔÏ ÓÏÏÂÝÅÎÉÅ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄÙ <code>/MSG</code>.</dd>
-
-<dt>/SET autocreate_query_level MSGS</dt>
- <dd>ðÒÉ ÐÏÌÕÞÅÎÉÉ ÓÏÏÂÝÅÎÉÊ ÏËÎÏ ÐÒÉ×ÁÔÁ ÓÏÚÄÁÅÔÓÑ Ó ÜÔÉÍ ÕÒÏ×ÎÅÍ ÓÏÏÂÝÅÎÉÊ. óÅÊÞÁÓ ÒÁÂÏÔÁÀÔ ÔÏÌØËÏ MSGS, DCCMSGS É NOTICES.
- ÷Ù ÍÏÖÅÔÅ ÏÔÍÅÎÉÔØ ÜÔÏ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄÙ <code>/SET -clear autocreate_query_level</code>.</dd>
-
-<dt>/SET autoclose_query 0</dt>
- <dd>ïËÎÁ ÐÒÉ×ÁÔÏ× ÍÏÇÕÔ ÂÙÔØ Á×ÔÏÍÁÔÉÞÅÓËÉ ÚÁËÒÙÔÙ ÐÏÓÌÅ ÚÁÄÁÎÎÏÇÏ "ÐÒÏÓÔÏÑ". áËÔÉ×ÎÏÅ ÏËÎÏ É ÏËÎÁ Ó ÎÅÐÒÏÞÉÔÁÎÎÙÍÉ ÓÏÏÂÝÅÎÉÑÍÉ ÎÅ ÚÁËÒÙ×ÁÀÔÓÑ. úÎÁÞÅÎÉÅ ÚÁÄÁÅÔÓÑ × ÓÅËÕÎÄÁÈ.</dd>
-</dl>
-
-<p><strong>ïËÎÁ</strong></p>
-
-<dl>
-<dt>/SET use_msgs_window OFF</dt>
- <dd>óÏÚÄÁ×ÁÔØ ÏËÎÏ ÓÏÏÂÝÅÎÉÊ ÐÒÉ ÚÁÐÕÓËÅ. ÷ÓÅ ÐÒÉ×ÁÔÎÙÅ ÓÏÏÂÝÅÎÉÑ ÂÕÄÕÔ ÎÁÐÒÁ×ÌÑÔØÓÑ × ÜÔÏ ÏËÎÏ.
- üÔÏ ÉÍÅÅÔ ÓÍÙÓÌ ÔÏÌØËÏ ÅÓÌÉ ×Ù ÏÔÍÅÎÉÌÉ Á×ÔÏÓÏÚÄÁÎÉÅ ÏËÏÎ ÐÒÉ×ÁÔÏ×.
- üÔÏ ÏËÎÏ ÔÁË-ÖÅ ÍÏÖÅÔ ÂÙÔØ ÓÏÚÄÁÎÏ ×ÒÕÞÎÕÀ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄÙ /WINDOW LEVEL
- MSGS, /WINDOW NAME (msgs).</dd>
-
-<dt>/SET use_status_window ON</dt>
- <dd>óÏÚÄÁ×ÁÔØ ÏËÎÏ ÓÔÁÔÕÓÁ ÐÒÉ ÚÁÐÕÓËÅ. ÷ÓÅ ÓÏÏÂÝÅÎÉÑ, ËÏÔÏÒÙÅ ÂÏÌØÛÅ ÎÅËÕÄÁ ÏÔÐÒÁ×ÉÔØ ÉÄÕÔ ÓÀÄÁ, ×ËÌÀÞÁÑ /WHOIS É.Ô.Ä.
- ïËÎÏ ÓÔÁÔÕÓÁ ÔÏÖÅ ÍÏÖÅÔ ÂÙÔØ ÓÏÚÄÁÎÏ ×ÒÕÞÎÕÀ ÐÒÉ ÐÏÍÏÝÉ ËÏÍÁÎÄ <code>/WINDOW LEVEL ALL -MSGS</code>,
- <code>/WINDOW NAME (status)</code>.</dd>
-
-<dt>/SET autocreate_windows ON</dt>
- <dd>åÓÌÉ ×Ù ÜÔÏ ÏÔËÌÀÞÉÔÅ, ÔÏ ×ÓÅ ÓÏÏÂÝÅÎÉÑ ÂÕÄÕÔ ÐÏÍÅÝÁÔØÓÑ × ÏÄÎÏ ÏËÎÏ</dd>
-
-<dt>/SET autoclose_windows ON</dt>
- <dd>á×ÔÏÚÁËÒÙÔÉÅ ÏËÏÎ (ÎÁÐÒÉÍÅÒ ÐÒÉ ×ÙÈÏÄÅ Ó ËÁÎÁÌÏ×(<code>/PART</code>)).</dd>
-
-<dt>/SET reuse_unused_windows OFF</dt>
- <dd>ëÏÇÄÁ ÉÝÅÔÓÑ ÍÅÓÔÏ ÄÌÑ ÓÏÚÄÁÎÉÑ ÎÏ×ÏÇÏ ÏËÎÁ (ËÁÎÁÌÁ ÉÌÉ ÐÒÉ×ÁÔÁ) Irssi
- ÓÎÁÞÁÌÁ ÐÙÔÁÅÔÓÑ ÉÓÐÏÌØÚÏ×ÁÔØ ÕÖÅ ÓÕÝÅÓÔ×ÕÀÝÉÅ ÐÕÓÔÙÅ ÏËÎÁ. åÓÌÉ ÜÔÁ ÏÐÃÉÑ ×ËÌÀÞÅÎÁ, ÔÏ ×ÓÅÇÄÁ ÂÕÄÕÔ ÓÏÚÄÁ×ÁÔØÓÑ ÎÏ×ÙÅ ÏËÎÁ.
- üÔÁ ÎÁÓÔÒÏÊËÁ ÉÇÎÏÒÉÒÕÅÔÓÑ ÅÓÌÉ autoclose_windows ×ËÌÀÞÅÎ.</dd>
-
-<dt>/SET window_auto_change OFF</dt>
- <dd>á×ÔÏÍÁÔÉÞÅÓËÉ ÐÅÒÅËÌÀÞÁÔØÓÑ × Á×ÔÏÍÁÔÉÞÅÓËÉ ÓÏÚÄÁÎÎÙÅ ÏËÎÁ.</dd>
-
-<dt>/SET print_active_channel OFF</dt>
- <dd>ëÏÇÄÁ ×Ù ÄÅÒÖÉÔÅ × ÏÄÎÏÍ ÏËÎÅ ÂÏÌØÛÅ ÞÅÍ ÏÄÉÎ ËÁÎÁÌ, Irssi ×Ù×ÏÄÉÔ ÓÏÏÂÝÅÎÉÑ, ÐÒÉÈÏÄÑÝÉÅ ÎÁ ÁËÔÉ×ÎÙÊ ËÁÎÁÌ × ÆÏÒÍÅ <code><ÎÉË> ÔÅËÓÔ</code>
- Á ÔÅ, ÞÔÏ ÐÒÉÈÏÄÑÔ ÎÁ ÄÒÕÇÉÅ ËÁÎÁÌÙ ÔÁË: <code><ÎÉË:ËÁÎÁÌ> ÔÅËÓÔ</code>. åÓÌÉ ÜÔÁ ÏÐÃÉÑ ×ËÌÀÞÅÎÁ, ÔÏ ÓÏÏÂÝÅÎÉÑ, ÐÒÉÈÏÄÑÝÉÅ ÎÁ ÁËÔÉ×ÎÙÊ ËÁÎÁÌ ÂÕÄÕÔ ÔÁË-ÖÅ ×Ù×ÏÄÉÔØÓÑ ×Ï ×ÔÏÒÏÍ ×ÁÒÉÁÎÔÅ.</dd>
-
-<dt>/SET window_history OFF</dt>
- <dd>èÒÁÎÉÔØ ÏÔÄÅÌØÎÕÀ ÉÓÔÏÒÉÀ ËÏÍÁÎÄ ÄÌÑ ËÁÖÄÏÇÏ ÏËÎÁ.</dd>
-</dl>
-
-
-<p><strong>éÎÆÏÒÍÁÃÉÑ Ï ÐÏÌØÚÏ×ÁÔÅÌÅ</strong></p>
-
-<dl>
-<dt>/SET nick</dt>
- <dd>÷ÁÛ ÎÉË</dd>
-
-<dt>/SET alternate_nick</dt>
- <dd>÷ÁÛ ÁÌØÔÅÒÎÁÔÉ×ÎÙÊ ÎÉË.</dd>
-
-<dt>/SET user_name</dt>
- <dd>÷ÁÛÅ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ. åÓÌÉ Õ ×ÁÓ ×ËÌÀÞÅÎ ident, ÔÏ ÏÎÏ ÎÉÞÅÇÏ ÎÅ ÄÁ£Ô.</dd>
-
-<dt>/SET real_name</dt>
- <dd>÷ÁÛÅ ÎÁÓÔÏÑÝÅÅ ÉÍÑ.</dd>
-</dl>
-
-
-<p><strong>éÎÆÏÒÍÁÃÉÑ Ï ÓÅÒ×ÅÒÅ</strong></p>
-
-<dl>
-<dt>/SET skip_motd OFF</dt>
- <dd>ðÒÏÐÕÓËÁÔØ motd ÐÒÉ ÐÏÄËÌÀÞÅÎÉÉ Ë ÓÅÒ×ÅÒÕ.</dd>
-
-<dt>/SET server_reconnect_time 300</dt>
- <dd>óËÏÌØËÏ ÓÅËÕÎÄ ÎÁÄÏ ÖÄÁÔØ ÐÅÒÅÄ ÐÏ×ÔÏÒÎÏÊ ÐÏÐÙÔËÏÊ ÐÏÄËÌÀÞÅÎÉÑ Ë ÓÅÒ×ÅÒÕ.</dd>
-
-<dt>/SET lag_max_before_disconnect 300</dt>
- <dd>ðÒÉ ËÁËÏÍ ÌÁÇÅ(× ÓÅËÕÎÄÁÈ) ÎÁÄÏ ÏÔËÌÀÞÁÔØÓÑ ÏÔ ÓÅÒ×ÅÒÁ É ÐÒÅÄÐÒÉÎÉÍÁÔØ ÐÏÐÙÔËÕ ÐÅÒÅÐÏÄËÌÀÞÅÎÉÑ.</dd>
-</dl>
-
-
-<p><strong>÷ÎÅÛÎÉÊ ×ÉÄ</strong></p>
-
-<dl>
-<dt>/SET timestamps ON</dt>
- <dd>ðÏËÁÚÙ×ÁÔØ ×ÒÅÍÑ ÐÅÒÅÄ ËÁÖÄÙÍ ÓÏÏÂÝÅÎÉÅÍ.</dd>
-
-<dt>/SET hide_text_style OFF</dt>
- <dd>óËÒÙÔØ ÏÆÏÒÍÌÅÎÉÅ ÔÅËÓÔÁ(ÖÉÒÎÙÊ ÛÒÉÆÔ, Ã×ÅÔÁ É.Ô.Ä.).</dd>
-
-<dt>/SET show_nickmode ON</dt>
- <dd>ðÏËÁÚÙ×ÁÔØ "ÒÅÖÉÍ ÎÉËÁ" ÎÁ ËÁÎÁÌÁÈ, ÎÁÐÒÉÍÅÒ
- <code><@nick></code> Õ ÏÐÏ×, <code><+nick></code> Õ ×ÏÊÓÏ× É.Ô.Ä.</dd>
-
-<dt>/SET show_nickmode_empty ON</dt>
- <dd>åÓÌÉ Õ ÎÉËÁ ÎÅÔ ÒÅÖÉÍÁ - ×Ù×ÏÄÉÔØ ÐÒÏÂÅÌ ÎÁ ÍÅÓÔÅ "ÓÉÍ×ÏÌÁ ÒÅÖÉÍÁ".</dd>
-
-<dt>/SET show_quit_once OFF</dt>
- <dd>ðÏËÁÚÙ×ÁÔØ quit-ÓÏÏÂÝÅÎÉÅ ÔÏÌØËÏ × ÏÄÎÏÍ ÏËÎÅ, ÅÓÌÉ ÞÅÌÏ×ÅË ×ÙÛÅÌ Ó ÎÅÓËÏÌØËÉÈ ËÁÎÁÌÏ×, ÎÁ ËÏÔÏÒÙÈ ×Ù ÓÉÄÉÔÅ.</dd>
-
-<dt>/SET lag_min_show 100</dt>
- <dd>ðÏËÁÚÙ×ÁÔØ × ÓÔÁÔÕÓ-ÂÁÒÅ ÌÁÇ ÅÓÌÉ ÏÎ ÐÒÅ×ÙÛÁÅÔ ÚÁÄÁÎÎÏÅ ÞÉÓÌÏ ÀÎÉÔÏ×. ÷ ÏÄÎÏÊ ÓÅËÕÎÄÅ 100 ÀÎÉÔÏ×.</dd>
-
-<dt>/SET indent 10</dt>
- <dd>åÓÌÉ ÓÔÒÏËÁ, ËÏÔÏÒÕÀ ÎÁÄÏ ×Ù×ÅÓÔÉ ÎÅ ×ÍÅÝÁÅÔÓÑ × ÏÄÎÕ ÓÔÒÏËÕ, ÔÏ ÏÎÁ ÒÁÚÂÉ×ÁÅÔÓÑ É ×Ù×ÏÄÉÔÓÑ ÎÁ ÓÌÅÄÕÀÝÉÈ ÓÔÒÏËÁÈ. üÔÏÔ ÐÁÒÁÍÅÔÒ ÐÏËÁÚÙ×ÁÅÔ ÓËÏÌØËÏ ÍÅÓÔÁ ÎÁÄÏ ÏÔÓÔÕÐÉÔØ ÐÅÒÅÄ ÎÁÞÁÌÏÍ ×Ù×ÏÄÁ ÔÅËÓÔÁ ÎÁ ÓÌÅÄÕÀÝÉÈ ÓÔÒÏËÁÈ.
- üÔÏ ÍÏÖÅÔ ÂÙÔØ ÐÅÒÅÏÐÒÅÄÅÌÅÎÏ × ÎÁÓÔÒÏÊËÁÈ ÆÏÒÍÁÔÉÒÏ×ÁÎÉÑ ÔÅËÓÔÁ ÐÒÉ ÐÏÍÏÝÉ ÆÏÒÍÁÔÁ <code>%|</code>.</dd>
-
-<dt>/SET activity_hide_targets</dt>
- <dd>åÓÌÉ ×Ù ÎÅ ÈÏÔÉÔÅ ×ÉÄÅÔØ ÁËÔÉ×ÎÏÓÔØ ÎÁ ËÁËÉÈ-ÔÏ ËÁÎÁÌÁÈ ÉÌÉ ÐÒÉ×ÁÔÁÈ, ÔÏ ÐÅÒÅÞÉÓÌÉÔÅ ÉÈ ÚÄÅÓØ. îÁÐÒÉÍÅÒ <code>#boringchannel =bot1
- =bot2</code>. üÔÁ ÎÁÓÔÒÏÊËÁ ÉÇÎÏÒÉÒÕÅÔÓÑ ÅÓÌÉ ×ÓÔÒÅÞÁÅÔÓÑ ÔÅËÓÔ ÉÌÉ ÓÏÏÂÝÅÎÉÅ, ÄÌÑ ËÏÔÏÒÏÇÏ ×Ù ÎÁÓÔÒÏÉÌÉ ÐÏÄÓ×ÅÔËÕ(highlight).</dd>
-</dl>
-
-<p><strong>á×ÔÏÄÏÐÏÌÎÅÎÉÅ ÎÉËÏ×</strong></p>
-
-<dl>
-<dt>/SET completion_auto OFF</dt>
- <dd>á×ÔÏÍÁÔÉÞÅÓËÉ ÄÏÐÏÌÎÑÔØ ÎÉË ÅÓÌÉ ÓÔÒÏËÁ ÎÁÞÉÎÁÅÔÓÑ Ó ÐÅÒ×ÙÈ ÂÕË× ÎÉËÁ É "ÓÉÍ×ÏÌÁ Á×ÔÏÄÏÐÏÌÎÅÎÉÑ".
- ìÕÞÛÅ ×ÓÅÇÏ ÉÓÐÏÌØÚÏ×ÁÔØ Á×ÔÏÄÏÐÏÌÎÅÎÉÅ ÔÁÂÏÍ.</dd>
-
-<dt>/SET completion_char :</dt>
- <dd>"óÉÍ×ÏÌ Á×ÔÏÄÏÐÏÌÎÅÎÉÑ".</dd>
-</dl>
-
-<h3><a id="c12">12. ðÁÎÅÌØ ÓÔÁÔÕÓÁ</a></h3>
-
-<p>ëÏÍÁÎÄÁ <code>/STATUSBAR</code> ×Ù×ÏÄÉÔ ÓÐÉÓÏË ÐÁÎÅÌÅÊ ÓÔÁÔÕÓÁ:</p>
-
-<pre>
-Name Type Placement Position Visible
-window window bottom 0 always
-window_inact window bottom 1 inactive
-prompt root bottom 100 always
-topic root top 1 always
-</pre>
-
-<p><code>/STATUSBAR <ÉÍÑ></code> ×Ù×ÏÄÉÔ ÎÁÓÔÒÏÊËÉ ÐÁÎÅÌÉ ÓÔÁÔÕÓÁ É Å£ ËÏÍÐÏÎÅÎÔÙ.
-<code>/STATUSBAR <ÉÍÑ> ENABLE|DISABLE</code>
-×ËÌÀÞÁÅÔ ÉÌÉ ÏÔËÌÀÞÁÅÔ ÐÁÎÅÌØ. <code>/STATUSBAR <ÉÍÑ> RESET</code>
-ÕÓÔÁÎÁ×ÌÉ×ÁÅÔ ÄÌÑ ÐÁÎÅÌÉ ÓÔÁÔÕÓÁ ÎÁÓÔÒÏÊËÉ ÐÏ ÕÍÏÌÞÁÎÉÀ, ÉÌÉ ÅÓÌÉ ÏÎÁ ÂÙÌÁ ÓÏÚÄÁÎÁ ×ÁÍÉ, ÔÏ ÕÄÁÌÑÅÔ Å£.</p>
-
-<p>ðÁÎÅÌØ ÍÏÖÅÔ ÉÍÅÔØ Ä×Á ÔÉÐÁ: windows É root - ÜÔÏ ÐÏÄÒÁÚÕÍÅ×ÁÅÔ, ÞÔÏ ÏÎÁ ÍÏÖÅÔ ÂÙÔØ ×ÉÄÎÁ ÄÌÑ ×ÓÅÈ ÏËÏÎ ÉÌÉ ÔÏÌØËÏ ÄÌÑ ÏÄÎÏÇÏ.
-Placement - ÜÔÏ ÒÁÓÐÏÌÏÖÅÎÉÅ ÐÁÎÅÌÉ: top - Ó×ÅÒÈÕ, bottom - ÓÎÉÚÕ.
-Position - ÜÔÏ ÞÉÓÌÏ, ÞÅÍ ÂÏÌØÛÅ ÚÎÁÞÅÎÉÅ ËÏÔÏÒÏÇÏ, ÔÅÍ ÎÉÖÅ ÎÁ ÜËÒÁÎÅ ÒÁÓÐÏÌÁÇÁÅÔÓÑ ÐÁÎÅÌØ.
-ðÁÒÁÍÅÔÒ Visible ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ 3 ÚÎÁÞÅÎÉÑ: always, active É inactive. òÅÖÉÍÙ active/inactive ÐÏÌÅÚÎÙ ÔÏÌØËÏ ÄÌÑ ÒÁÚÄÅÌÅÎÎÙÈ ÏËÏÎ.
-üÔÉ ÎÁÓÔÒÏÊËÉ ÍÏÇÕÔ ÂÙÔØ ÉÚÍÅÎÅÎÙ ÓÌÅÄÕÀÝÉÍÉ ËÏÍÁÎÄÁÍÉ:</p>
-
-<pre>
-/STATUSBAR <ÉÍÑ> TYPE window|root
-/STATUSBAR <ÉÍÑ> PLACEMENT top|bottom
-/STATUSBAR <ÉÍÑ> POSITION <num>
-/STATUSBAR <ÉÍÑ> VISIBLE always|active|inactive
-</pre>
-
-<p>ëÏÇÄÁ ×Ù ÚÁÇÒÕÖÁÅÔÅ ÎÏ×ÙÅ ÓËÒÉÐÔÙ ÄÌÑ ÐÁÎÅÌÅÊ ÓÔÁÔÕÓÁ ×ÁÍ ÓËÏÒÅÅ ×ÓÅÇÏ ÐÒÉÄÅÔÓÑ ×ÙÂÒÁÔØ ÇÄÅ ×Ù ÈÏÔÉÔÅ ÉÈ ÒÁÓÐÏÌÏÖÉÔØ.
-ëÏÍÐÏÎÅÎÔÙ ÐÁÎÅÌÅÊ ÍÏÇÕÔ ÂÙÔØ ÉÚÍÅÎÅÎÙ ÓÌÅÄÕÀÝÉÍÉ ËÏÍÁÎÄÁÍÉ:</p>
-
-<pre>
-/STATUSBAR <ÉÍÑ> ADD [-before | -after <item>] [-priority #] [-alignment left|right] <ËÏÍÐÏÎÅÎÔÁ(item)>
-/STATUSBAR <ÉÍÑ> REMOVE <ËÏÍÐÏÎÅÎÔÁ(item)>
-</pre>
-
-<p>ïÂÙÞÎÏ ÄÌÑ ÉÍÑ ËÏÍÐÏÎÅÎÔÙ × ÓËÒÉÐÔÅ ÄÌÑ ÐÁÎÅÌÉ ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÉÍÅÎÉ ÓËÒÉÐÔÁ.
-ï ÜÔÏÍ ÄÏÌÖÎÏ ÂÙÔØ ÎÁÐÉÓÁÎÏ × ÄÏËÕÍÅÎÔÁÃÉÉ Ë ÓËÒÉÐÔÕ. ôÁË ÞÔÏ ÞÔÏÂÙ ÄÏÂÁ×ÉÔØ ÓËÒÉÐÔ mail.pl
-ÐÅÒÅÄ ÓÐÉÓËÏÍ ÁËÔÉ×ÎÙÈ ÏËÏÎ (ÓÍÏÔÒÉÔÅ
-<code>/STATUSBAR</code>), ××ÅÄÉÔÅ ÜÔÕ ËÏÍÁÎÄÕ: <code>/STATUSBAR window ADD -before
-act mail</code>.</p>
<p>And example how to add servers:</p>
-<p>(OFTC network, identify with nickserv and wait for 2 seconds before
+<p>(openprojects network, identify with nickserv and wait for 2 seconds before
joining channels)</p>
<pre>
-/NETWORK ADD -autosendcmd "/^msg nickserv ident pass;wait 2000" OFTC
+/IRCNET ADD -autosendcmd "/^msg nickserv ident pass;wait -freenode 2000" freenode
</pre>
-<p>(NOTE: use /IRCNET with 0.8.9 and older)</p>
-
-<p>Then add some servers to different networks (network is already set up
+<p>Then add some servers to different networks (ircnet is already set up
for them), irc.kpnqwest.fi is used by default for IRCNet but if it fails,
irc.funet.fi is tried next:</p>
<pre>
-/SERVER ADD -auto -network IRCnet irc.kpnqwest.fi 6667
-/SERVER ADD -network IRCnet irc.funet.fi 6667
-/SERVER ADD -auto -network efnet efnet.cs.hut.fi 6667
+/SERVER ADD -auto -ircnet ircnet irc.kpnqwest.fi 6667
+/SERVER ADD -ircnet ircnet irc.funet.fi 6667
+/SERVER ADD -auto -ircnet efnet efnet.cs.hut.fi 6667
</pre>
<p>Automatically join to channels after connected to server, send op request
to bot after joined to efnet/#irssi:</p>
<pre>
-/CHANNEL ADD -auto #irssi IRCnet
+/CHANNEL ADD -auto #irssi ircnet
/CHANNEL ADD -auto -bots *!*bot@host.org -botcmd "/^msg $0 op pass" #irssi efnet
</pre>
</pre>
<p>Clearly the easiest way is to use Meta-number keys. And what is the Meta
-key? ESC key always works as Meta, but there's also easier ways. ALT could
-work as Meta, or if you have Windows keyboard, left Windows key might work
-as Meta. If they don't work directly, you'll need to set a few X resources
-(NOTE: these work with both xterm and rxvt):</p>
+key? For some terminals, it's the same as ALT. If you have Windows keyboard,
+it's probably the left Windows key. If they don't work directly, you'll need
+to set a few X resources (NOTE: these work with both xterm and rxvt):</p>
<pre>
XTerm*eightBitInput: false
<pre>
Split window 1: win#1 - Status window, win#2 - Messages window
-Split window 2: win#3 - IRCnet/#channel1, win#4 - IRCnet/#channel2
+Split window 2: win#3 - ircnet/#channel1, win#4 - ircnet/#channel2
Split window 3: win#5 - efnet/#channel1, win#6 - efnet/#channel2
</pre>
useful in some other ways too :) For information how to actually use
irssi correctly with multiple servers see the chapter 6.</p>
-<p>First you need to have your IRC network set, use <code>/NETWORK</code>
-command to see if it's already there. If it isn't, use <code>/NETWORK ADD
-yournetwork</code>. If you want to execute some commands automatically when
+<p>First you need to have your IRC network set, use <code>/IRCNET</code>
+command to see if it's already there. If it isn't, use <code>/IRCNET ADD
+yourircnet</code>. If you want to execute some commands automatically when
you're connected to some network, use <code>-autosendcmd</code> option.
-(NOTE: use /IRCNET with 0.8.9 and older.) Here's some examples:</p>
+Here's some examples:</p>
<pre>
-/NETWORK ADD -autosendcmd '^msg bot invite' IRCnet
-/NETWORK ADD -autosendcmd "/^msg nickserv ident pass;wait 2000" OFTC
+/IRCNET ADD -autosendcmd '^msg bot invite' ircnet
+/IRCNET ADD -autosendcmd "/^msg nickserv ident pass;wait -freenode 2000" freenode
</pre>
<p>After that you need to add your servers. For example:</p>
<pre>
-/SERVER ADD -auto -network IRCnet irc.kpnqwest.fi 6667
-/SERVER ADD -auto -network worknet irc.mycompany.com 6667 password
+/SERVER ADD -auto -ircnet ircnet irc.kpnqwest.fi 6667
+/SERVER ADD -auto -ircnet worknet irc.mycompany.com 6667 password
</pre>
<p>The <code>-auto</code> option specifies that this server is
<pre>
/CHANNEL ADD -auto -bots *!*bot@host.org -botcmd "/^msg $0 op pass" #irssi efnet
-/CHANNEL ADD -auto #secret IRCnet password
+/CHANNEL ADD -auto #secret ircnet password
</pre>
<p><code>-bots</code> and <code>-botcmd</code> should be the only ones
<pre>
-!- IRCNet: irc.song.fi:6667 (IRCNet)
--!- OFTC: irc.oftc.net:6667 (OFTC)
+-!- freenode: irc.freenode.net:6667 (freenode)
-!- RECON-1: 192.168.0.1:6667 () (02:59 left before reconnecting)
</pre>
-<p>Here you see that we're connected to IRCNet and OFTC networks.
+<p>Here you see that we're connected to IRCNet and freenode networks.
The IRCNet at the beginning is called the "server tag" while the
(IRCnet) at the end shows the IRC network. Server tag specifies unique
tag to refer to the server, usually it's the same as the IRC network.
When the IRC network isn't known it's some part of the server name.
When there's multiple connections to same IRC network or server, irssi
-adds a number after the tag so there could be network, network2, network3
+adds a number after the tag so there could be ircnet, ircnet2, ircnet3
etc.</p>
<p>Server tags beginning with <code>RECON-</code> mean server
reconnecting, use</p>
<pre>
-/DISCONNECT network - disconnect server with tag "network"
+/DISCONNECT ircnet - disconnect server with tag "ircnet"
/DISCONNECT recon-1 - stop trying to reconnect to RECON-1 server
/RMRECONNS - stop all server reconnections
/WINDOW NEW HIDE
/WINDOW NAME (status)
/WINDOW LEVEL ALL -MSGS
-/WINDOW SERVER -sticky network
+/WINDOW SERVER -sticky ircnet
/WINDOW NEW HIDE
/WINDOW NAME (msgs)
/WINDOW LEVEL MSGS
-/WINDOW SERVER -sticky network
+/WINDOW SERVER -sticky ircnet
</pre>
<h3><a id="c7">7. /LASTLOG and jumping around in scrollback</a></h3>
about them:</p>
<pre>
-/SERVER ADD -auto -network dalnet irc.dal.net
-/SERVER ADD -auto -network efnet irc.efnet.org
+/SERVER ADD -auto -ircnet dalnet irc.dal.net
+/SERVER ADD -auto -ircnet efnet irc.efnet.org
</pre>
<p>With the proxy <code>/SET</code>s however, irssi now connects to those
<pre>
/SET -clear proxy_password
-/EVAL SET proxy_string CONNECT %s:%d HTTP/1.0\n\n
+/EVAL SET proxy_string CONNECT %s:%d\n\n
</pre>
<p><strong>BNC</strong></p>
<p><strong>dircproxy</strong></p>
<p>dircproxy separates the server connections by passwords. So, if you
-for example have network connection with password ircpass and
-OFTC connection with oftcpass, you would do something like
+for example have ircnet connection with password ircpass and
+openprojects connection with freenodepass, you would do something like
this:</p>
<pre>
/SET -clear proxy_password
/SET -clear proxy_string
-/SERVER ADD -auto -network IRCnet fake.network 6667 ircpass
-/SERVER ADD -auto -network OFTC fake.oftc 6667 oftcpass
+/SERVER ADD -auto -ircnet ircnet fake.ircnet 6667 ircpass
+/SERVER ADD -auto -ircnet freenode fake.freenode 6667 freenodepass
</pre>
<p>The server name and port you give isn't used anywhere, so you can
/SET -clear proxy_password
/SET -clear proxy_string
-/NETWORK ADD -user networkuser IRCnet
-/SERVER ADD -auto -network IRCnet fake.network 6667 ircpass
-/NETWORK ADD -user oftcuser OFTC
-/SERVER ADD -auto -network OFTC fake.oftc 6667 oftcpass
+/IRCNET ADD -user ircnetuser ircnet
+/SERVER ADD -auto -ircnet ircnet fake.ircnet 6667 ircpass
+/IRCNET ADD -user freenodeuser freenode
+/SERVER ADD -auto -ircnet freenode fake.freenode 6667 freenodepass
</pre>
-<p>So, you'll specify the usernames with <code>/NETWORK ADD</code> command,
+<p>So, you'll specify the usernames with <code>/IRCNET ADD</code> command,
and the user's password with <code>/SERVER ADD</code>.</p>
-<p>(NOTE: use /IRCNET with 0.8.9 and older.)</p>
-
<p><strong>Irssi proxy</strong></p>
<p>Irssi contains it's own proxy which you can build giving
try to explain this thing for minutes every time? :)</p>
<p>Irssi proxy supports sharing multiple server connections in different
-ports, like you can share network in port 2777 and efnet in port 2778.</p>
+ports, like you can share ircnet in port 2777 and efnet in port 2778.</p>
<p>Usage in proxy side:</p>
<pre>
/LOAD proxy
/SET irssiproxy_password <password>
-/SET irssiproxy_ports <network>=<port> ... (eg. IRCnet=2777 efnet=2778)
+/SET irssiproxy_ports <ircnet>=<port> ... (eg. ircnet=2777 efnet=2778)
</pre>
<p><strong>NOTE</strong>: you <strong>MUST</strong> add all the servers you
-are using to server and network lists with <code>/SERVER ADD</code> and
-<code>/NETWORK ADD</code>. ..Except if you really don't want to for some
+are using to server and ircnet lists with <code>/SERVER ADD</code> and
+<code>/IRCNET ADD</code>. ..Except if you really don't want to for some
reason, and you only use one server connection, you may simply set:</p>
<pre>
specified in <code>/SET irssiproxy_password</code>. For example:</p>
<pre>
-/SERVER ADD -network IRCnet my.irssi-proxy.org 2777 secret
-/SERVER ADD -network efnet my.irssi-proxy.org 2778 secret
+/SERVER ADD -ircnet ircnet my.irssi-proxy.org 2777 secret
+/SERVER ADD -ircnet efnet my.irssi-proxy.org 2778 secret
</pre>
<p>Irssi proxy works fine with other IRC clients as well.</p>
<dt>/SET autocreate_query_level MSGS</dt>
<dd>New query window should be created when receiving messages with
this level. MSGS, DCCMSGS and NOTICES levels work currently. You can
- disable this with <code>/SET -clear autocreate_query_level</code>.</dd>
+ disable this with <code>/SET -clear autocrate_query_level</code>.</dd>
<dt>/SET autoclose_query 0</dt>
<dd>Query windows can be automatically closed after certain time of
dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject or
dnl gthread is specified in MODULES, pass to pkg-config
dnl
-AC_DEFUN([AM_PATH_GLIB_2_0],
+AC_DEFUN(AM_PATH_GLIB_2_0,
[dnl
dnl Get the cflags and libraries from pkg-config
dnl
gmodule)
pkg_config_args="$pkg_config_args gmodule-2.0"
;;
- gmodule-no-export)
- pkg_config_args="$pkg_config_args gmodule-no-export-2.0"
- ;;
gobject)
pkg_config_args="$pkg_config_args gobject-2.0"
;;
:
else
echo "*** Could not run GLIB test program, checking why..."
- ac_save_CFLAGS="$CFLAGS"
- ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $GLIB_CFLAGS"
LIBS="$LIBS $GLIB_LIBS"
AC_TRY_LINK([
echo "*** If you have an old version installed, it is best to remove it, although"
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ],
[ echo "*** The test program failed to compile or link. See the file config.log for the"
- echo "*** exact error that occured. This usually means GLIB is incorrectly installed."])
+ echo "*** exact error that occured. This usually means GLIB was incorrectly installed"
+ echo "*** or that you have moved GLIB since it was installed. In the latter case, you"
+ echo "*** may want to edit the pkg-config script: $PKG_CONFIG" ])
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
fi
-SUBDIRS = examples
-
-scriptdir = $(datadir)/irssi/scripts
+scriptdir = $(datadir)/silc/scripts
script_DATA = \
autoop.pl \
- autorejoin.pl \
- buf.pl \
- dns.pl \
- kills.pl \
- mail.pl \
- mlock.pl \
- quitmsg.pl \
- scriptassist.pl \
- splitlong.pl \
- usercount.pl
+ clones.pl \
+ hello.pl \
+ mail.pl \
+ beep.pl \
+ dns.pl \
+ mail-maildir.pl \
+ silc-mime.pl \
+ silc.pl
EXTRA_DIST = $(script_DATA)
# /AUTOOP <*|#channel> [<nickmasks>]
-# use friends.pl if you need more features
use Irssi;
use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'autoop',
- description => 'Simple auto-op script',
- license => 'Public Domain',
- changed => 'Sun Mar 10 23:18 EET 2002'
-);
my (%opnicks, %temp_opped);
if (!$temp_opped{$nick} &&
$server->masks_match($masks, $nick, $host)) {
- $channel->command("op $nick");
+ $channel->command("/op $nick");
$temp_opped{$nick} = 1;
}
}
+++ /dev/null
-# automatically rejoin to channel after kicked
-
-# /SET autorejoin_channels #channel1 #channel2 ...
-
-# NOTE: I personally don't like this feature, in most channels I'm in it
-# will just result as ban. You've probably misunderstood the idea of /KICK
-# if you kick/get kicked all the time "just for fun" ...
-
-use Irssi;
-use Irssi::Irc;
-use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'autorejoin',
- description => 'Automatically rejoin to channel after kicked',
- license => 'Public Domain',
- changed => 'Sun Mar 10 23:18 EET 2002'
-);
-
-sub channel_rejoin {
- my ($server, $channel) = @_;
-
- # check if channel has password
- my $chanrec = $server->channel_find($channel);
- my $password = $chanrec->{key} if ($chanrec);
-
- # We have to use send_raw() because the channel record still
- # exists and irssi won't even try to join to it with command()
- $server->send_raw("JOIN $channel $password");
-}
-
-sub event_rejoin_kick {
- my ($server, $data) = @_;
- my ($channel, $nick) = split(/ +/, $data);
-
- return if ($server->{nick} ne $nick);
-
- # check if we want to autorejoin this channel
- my @chans = split(/[ ,]+/, Irssi::settings_get_str('autorejoin_channels'));
- foreach my $chan (@chans) {
- if (lc($chan) eq lc($channel)) {
- channel_rejoin($server, $channel);
- last;
- }
- }
-}
-
-Irssi::settings_add_str('misc', 'autorejoin_channels', '');
-Irssi::signal_add('event kick', 'event_rejoin_kick');
+++ /dev/null
-use strict;
-use vars qw($VERSION %IRSSI);
-
-use Irssi qw(command signal_add signal_add_first active_win
- settings_get_str settings_get_bool channels windows
- settings_add_str settings_add_bool get_irssi_dir
- window_find_refnum signal_stop);
-$VERSION = '2.13';
-%IRSSI = (
- authors => 'Juerd',
- contact => 'juerd@juerd.nl',
- name => 'Scroll buffer restorer',
- description => 'Saves the buffer for /upgrade, so that no information is lost',
- license => 'Public Domain',
- url => 'http://juerd.nl/irssi/',
- changed => 'Mon May 13 19:41 CET 2002',
- changes => 'Severe formatting bug removed * oops, I ' .
- 'exposed Irssi to ircII foolishness * sorry ' .
- '** removed logging stuff (this is a fix)',
- note1 => 'This script HAS TO BE in your scripts/autorun!',
- note2 => 'Perl support must be static or in startup',
-);
-
-# Q: How can I get a very smooth and clean upgrade?
-#
-# A: /set -clear upgrade_separator
-# /set upgrade_suppress_join ON (default)
-# /set channel_sync OFF
-
-# Q: Can I use color in the upgrade_separator?
-# Q: Is it possible to save my command history?
-# Q: Can I prevent the screen from blinking?
-# Q: Can you make it faster?
-#
-# A: Probably not, but if you can do it, tell me how.
-
-use Irssi::TextUI;
-use Data::Dumper;
-
-my %suppress;
-
-sub upgrade {
- open BUF, sprintf('>%s/scrollbuffer', get_irssi_dir) or die $!;
- print BUF join("\0", map $_->{server}->{address} . $_->{name}, channels), "\n";
- for my $window (windows) {
- next unless defined $window;
- next if $window->{name} eq 'status';
- my $view = $window->view;
- my $line = $view->get_lines;
- my $lines = 0;
- my $buf = '';
- if (defined $line){
- {
- $buf .= $line->get_text(1) . "\n";
- $line = $line->next;
- $lines++;
- redo if defined $line;
- }
- }
- printf BUF "%s:%s\n%s", $window->{refnum}, $lines, $buf;
- }
- close BUF;
- unlink sprintf("%s/sessionconfig", get_irssi_dir);
- command 'layout save';
- command 'save';
-}
-
-sub restore {
- open BUF, sprintf('<%s/scrollbuffer', get_irssi_dir) or die $!;
- my @suppress = split /\0/, <BUF>;
- if (settings_get_bool 'upgrade_suppress_join') {
- chomp $suppress[-1];
- @suppress{@suppress} = (2) x @suppress;
- }
- active_win->command('^window scroll off');
- while (my $bla = <BUF>){
- chomp $bla;
- my ($refnum, $lines) = split /:/, $bla;
- next unless $lines;
- my $window = window_find_refnum $refnum;
- unless (defined $window){
- <BUF> for 1..$lines;
- next;
- }
- my $view = $window->view;
- $view->remove_all_lines();
- $view->redraw();
- my $buf = '';
- $buf .= <BUF> for 1..$lines;
- my $sep = settings_get_str 'upgrade_separator';
- $sep .= "\n" if $sep ne '';
- $window->gui_printtext_after(undef, MSGLEVEL_CLIENTNOTICE, "$buf\cO$sep");
- $view->redraw();
- }
- active_win->command('^window scroll on');
- active_win->command('^scrollback end');
-}
-
-sub suppress {
- my ($first, $second) = @_;
- return
- unless scalar keys %suppress
- and settings_get_bool 'upgrade_suppress_join';
- my $key = $first->{address} .
- (grep { (s/^://, /^[#!+&]/) } split ' ', $second)[0];
- if (exists $suppress{$key} and $suppress{$key}--) {
- signal_stop();
- delete $suppress{$key} unless $suppress{$key};
- }
-}
-
-settings_add_str 'buffer', 'upgrade_separator' => '=Upgrade=';
-settings_add_bool 'buffer', 'upgrade_suppress_join' => 1;
-
-signal_add_first 'session save' => 'upgrade';
-signal_add_first 'session restore' => 'restore';
-signal_add 'event 366' => 'suppress';
-signal_add 'event join' => 'suppress';
-
-unless (-f sprintf('%s/scripts/autorun/buf.pl', get_irssi_dir)) {
- Irssi::print('PUT THIS SCRIPT IN ~/.irssi/scripts/autorun/ BEFORE /UPGRADING!!');
-}
# /DNS <nick>|<host>|<ip> ...
+# for irssi 0.7.99 by Timo Sirainen
+# version 2.0
-use Irssi;
use strict;
use Socket;
use POSIX;
-use vars qw($VERSION %IRSSI);
-$VERSION = "2.1";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'dns',
- description => '/DNS <nick>|<host>|<ip> ...',
- license => 'Public Domain',
- changed => 'Sun Mar 10 23:23 EET 2002'
-);
-
my (%resolve_hosts, %resolve_nicks, %resolve_print); # resolve queues
my $userhosts; # number of USERHOSTs currently waiting for reply
my $lookup_waiting; # 1 if we're waiting a reply for host lookup
my $ask_nicks = "";
my $print_error = 0;
foreach my $nick (split(" ", $nicks)) {
- $nick = lc($nick);
if ($nick =~ /[\.:]/) {
# it's an IP or hostname
$resolve_hosts{$nick} = $tag;
# move resolve_nicks -> resolve_hosts
foreach my $host (@hosts) {
if ($host =~ /^([^=\*]*)\*?=.(.*)@(.*)/) {
- my $nick = lc($1);
+ my $nick = $1;
my $user = $2;
- $host = lc($3);
+ $host = $3;
$resolve_hosts{$host} = $resolve_nicks{$nick};
delete $resolve_nicks{$nick};
+++ /dev/null
-scriptdir = $(datadir)/irssi/scripts
-
-script_DATA = \
- command.pl \
- msg-event.pl \
- redirect.pl
-
-EXTRA_DIST = $(script_DATA)
+++ /dev/null
-# Example how to create your own /commands:
-
-# /HELLO <nick> - sends a "Hello, world!" to given nick.
-
-use Irssi;
-use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'command',
- description => 'Command example',
- license => 'Public Domain'
-);
-
-sub cmd_hello {
- my ($data, $server, $channel) = @_;
-
- $server->command("/msg $data Hello, world!");
-}
-
-Irssi::command_bind('hello', 'cmd_hello');
+++ /dev/null
-# Example how to react on specific messages:
-
-# !reverse <text> sends back the text reversed.
-
-use Irssi;
-use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'msg-event',
- description => 'Event example',
- license => 'Public Domain'
-);
-
-sub event_privmsg {
- # $server = server record where the message came
- # $data = the raw data received from server, with PRIVMSGs it is:
- # "target :text" where target is either your nick or #channel
- # $nick = the nick who sent the message
- # $host = host of the nick who sent the message
- my ($server, $data, $nick, $host) = @_;
-
- # split data to target/text
- my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
-
- # skip lines not beginning with !reverse
- return if ($text !~ /!reverse (.*)/);
- $text = $1;
-
- if (!$server->ischannel($target)) {
- # private message, $target contains our nick, so we'll need
- # to change it to $nick
- $target = $nick;
- }
-
- $server->command("notice $target reversed $text = ".reverse($text));
-}
-
-Irssi::signal_add('event privmsg', 'event_privmsg');
+++ /dev/null
-# Example how to do redirections, we'll grab the output of /WHOIS:
-
-# /RN - display real name of nick
-
-use Irssi;
-use Irssi::Irc;
-use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'redirect',
- description => 'Redirection example',
- license => 'Public Domain'
-);
-
-sub cmd_realname {
- my ($data, $server, $channel) = @_;
-
- # ignore all whois replies except "No such nick" or the
- # first line of the WHOIS reply
- $server->redirect_event('whois', 1, $data, -1, '', {
- 'event 402' => 'event 402',
- 'event 401' => 'event 401',
- 'event 311' => 'redir whois',
- '' => 'event empty' });
-
- $server->send_raw("WHOIS :$data");
-}
-
-sub event_rn_whois {
- my ($num, $nick, $user, $host, $empty, $realname) = split(/ +/, $_[1], 6);
- $realname =~ s/^://;
-
- Irssi::print("%_$nick%_ is $realname");
-}
-
-Irssi::command_bind('rn', 'cmd_realname');
-Irssi::signal_add('redir whois', 'event_rn_whois');
+++ /dev/null
-# Display kills with more understandable messages.
-# for irssi 0.7.98 by Timo Sirainen
-
-# There's one kind of nick collision this script doesn't handle - if the
-# collision is detected by the server you're connected to, it won't use
-# kill as quit reason, but "Nick collision(new)" or "..(old)". This is pretty
-# easy to understand already, happens hardly ever(?) and it can be faked
-# so I thought better not change it to kill message.
-
-# There's a pretty good explanation of (ircnet) ircd's server kills in
-# http://www.irc.org/tech_docs/ircnet/kills.html
-
-use Irssi;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'kills',
- description => 'Displays kills with more understandable messages',
- license => 'Public Domain',
- changed => 'Sun Mar 10 23:18 EET 2002'
-);
-
-Irssi::theme_register([
- 'kill_public', '{channick $0} {chanhost $1} killed by {nick $2}$3 {reason $4}'
-]);
-
-sub msg_quit {
- my ($server, $nick, $addr, $data) = @_;
-
- my $localkill;
- if ($data =~ /^Killed \(([^ ]*) \((.*)\)\)$/) {
- # remote kill
- $localkill = 0;
- } elsif ($data =~ /^Local Kill by ([^ ]*) \((.*)\)/) {
- # local kill
- $localkill = 1;
- } else {
- return;
- }
-
- my $killer = $1;
- my $killmsg = $2;
- my $msg = "\002Nick collision\002: ";
-
- my @printargs = ();
- if ($killmsg =~ /([^ ]*) != (.*)/) {
- # 1 != 2
- my $server1 = $1, $server2 = $2;
-
- $server1 =~ s/([^\[]*)\[([^\]]*)\]/\1/;
- $msg .= "$2 != $server2";
- } elsif ($killmsg =~ /([^ ]*) <- (.*)/) {
- # 1 <- 2
- my $server1 = $1, $server2 = $2;
-
- if ($server1 =~ /^\(/) {
- # (addr1)server1 <- (add2)server2
- $server1 =~ s/^\(([^\)]*)\)//;
- my $nick1 = $1;
- $server2 =~ s/^\(([^\)]*)\)//;
- my $nick2 = $1;
-
- $msg .= "server $server1";
- $msg .= " (nick from $nick1)" if $nick1;
- $msg .= " <- ";
- $msg .= "\002$server2\002";
- $msg .= " (nick from \002$nick2\002)" if $nick2;
- } elsif ($server1 =~ /\)$/ || $server2 =~ /\)$/) {
- # server1(nick) <- server2
- # server1 <- server2(nick)
- $server1 =~ s/\(([^\)]*)\)$//;
- my $oldnick = $1;
- $server2 =~ s/\(([^\)]*)\)$//;
- $oldnick = $1 if $1;
- $msg = "\002Nick change collision\002: $server1 <- \002$server2\002 (old nick \002$oldnick\002)";
- } else {
- # server1 <- server2
- $msg = "\002Nick/server collision\002: $server1 <- \002$server2\002";
- }
- } else {
- # something else, just show it as-is
- $msg = $killmsg;
- }
-
- @list = $server->nicks_get_same($nick);
- while (@list) {
- $channel = $list[0];
- shift @list;
- # skip nick record
- shift @list;
-
- $channel->printformat(MSGLEVEL_QUITS, 'kill_public',
- $nick, $addr, $killer,
- $localkill ? " (local)" : "", $msg);
- }
-
- Irssi::signal_stop();
-}
-
-Irssi::signal_add('message quit', 'msg_quit');
-$VERSION = "2.92";
-%IRSSI = (
- authors => "Timo Sirainen, Matti Hiljanen, Joost Vunderink, Bart Matthaei",
- contact => "tss\@iki.fi, matti\@hiljanen.com, joost\@carnique.nl, bart\@dreamflow.nl",
- name => "mail",
- description => "Fully customizable mail counter statusbar item with multiple mailbox and multiple Maildir support",
- license => "Public Domain",
- url => "http://irssi.org, http://scripts.irssi.de",
-);
-
# Mail counter statusbar item
-# for irssi 0.8.1 by Timo Sirainen
-#
-# Maildir support added by Matti Hiljanen
-# Multiple Maildir/mbox and customization support added by Joost Vunderink
-# OLD mailtreatment switch added by Bart Matthaei.
-# Improved some regexps in maildirmode by Bart Matthaei.
-# Maildirmode regexps (hopefully) fixed for good by Matti Hiljanen.
-#
-# You can add any number of mailboxes or Maildirs to watch for new mail in.
-# Give them any name and <name>:<count> will appear in your mail
-# statusbar item, where <count> is the number of unread messages.
-# If only 1 mailbox/Maildir is defined, the statusbar item will have the
-# familiar form [Mail: <count>].
-# If you set mail_show_message to ON, irssi will print a message in the
-# active window whenever new mail arrives.
-#
-# Check /mailbox help for help.
+# for irssi 0.7.99 by Timo Sirainen
+# /SET mail_ext_program - specify external mail checker program
+# /SET mail_file - specifies mbox file location
+# /SET mail_refresh_time - in seconds, how often to check for new mail
+use strict;
use Irssi::TextUI;
-my $maildirmode = 0; # maildir=1, file(spools)=0
-my $old_is_not_new = 0;
my $extprog;
my ($last_refresh_time, $refresh_tag);
# for mbox caching
-my $last_size, $last_mtime, $last_mailcount, $last_mode;
-
-# list of mailboxes
-my %mailboxes = ();
-my %new_mails_in_box = ();
-my $nummailboxes = 0;
-
-# the string to be stored in Irssi's mail_mailboxes setting
-my $mailboxsetting = "";
-
-sub cmd_print_help {
- Irssi::print(
- "MAILBOX ADD <num> <file|dir>\n".
- "MAILBOX DEL <num>\n".
- "MAILBOX SHOW\n\n".
- "Statusbar item to keep track of how many (new) emails there are in ".
- "each of your mailboxes/Maildirs.\n\n".
- "/MAILBOX ADD <name> <file|dir>\n".
- " - Adds a mailbox or a Maildir to the list.\n".
- "/MAILBOX DEL <name>\n".
- " - Removes mailbox or Maildir named <name> from the list.\n".
- "/MAILBOX SHOW\n".
- " - Shows a list of the defined mailboxes.\n\n".
- "Use the following commands to change the behaviour:\n\n".
- "/SET MAILDIRMODE on|off\n".
- " - If maildirmode is on, the mailboxes in the list are assumed to be ".
- "directories. Otherwise they are assumed to be spool files.\n".
- " Default: off.\n".
- "/SET MAIL_OLDNOTNEW on|off\n".
- " - If switched on, mail marked als \"OLD\" will not be treated as new.\n".
- " Default: off.\n".
- "/SET MAIL_EXT_PROGRAM <prog>\n".
- " - <prog> will be used to check for mail.\n".
- "/SET MAIL_REFRESH_TIME <num>\n".
- " - Sets the time between checks to <num> seconds.\n Default: 60.\n".
- "/SET MAIL_SHOW_MESSAGE on|off\n".
- " - If this is on, a message will be printed in the active window ".
- "whenever new email is received.\n Default: off.\n".
- "/SET MAIL_SHOW_ONLY_UNREAD on|off\n".
- " - If you don't want to see a mailbox if it does not contain any new ".
- "mail, set this to on.\n Default: on.\n" .
- "/SET MAIL_SEPARATOR <char>\n".
- " - Sets the character to be printed between each mailbox.\n".
- " The default is a comma.\n".
- "/SET MAIL_FORMAT <format>\n".
- " - Sets the format of each mailbox.\n".
- " Allowed variables:\n".
- " %%n = mailbox name\n".
- " %%u = number of unread mail\n".
- " %%r = number of read mail\n".
- " %%t = total amount of mail\n".
- " The default format is %%n:%%u/%%t.\n".
- "\nSee also: STATUSBAR"
- ,MSGLEVEL_CRAP);
-}
+my ($last_size, $last_mtime, $last_mailcount);
sub mbox_count {
my $mailfile = shift;
- my $unread = 0;
- my $read = 0;
- my $maildirmode=Irssi::settings_get_bool('maildir_mode');
- my $old_is_not_new=Irssi::settings_get_bool('mail_oldnotnew');
-
- if ($extprog ne "") {
- $total = `$extprog`;
- chomp $unread;
- } else {
- if (!$maildirmode) {
- if (-f $mailfile) {
- my @stat = stat($mailfile);
- my $size = $stat[7];
- my $mtime = $stat[9];
-
- # if the file hasn't changed, get the count from cache
- return $last_mailcount if ($last_size == $size && $last_mtime == $mtime);
- $last_size = $size;
- $last_mtime = $mtime;
- my $f = gensym;
- return 0 if (!open($f, $mailfile));
+ my @stat = stat($mailfile);
+ my $size = $stat[7];
+ my $mtime = $stat[9];
- # count new mails only
- my $internal_removed = 0;
- while (<$f>) {
- $unread++ if (/^From /);
+ # if the file hasn't changed, get the count from cache
+ return $last_mailcount if ($last_size == $size && $last_mtime == $mtime);
+ $last_size = $size;
+ $last_mtime = $mtime;
- if(!$old_is_not_new) {
- $unread-- if (/^Status: R/);
- } else {
- $unread-- if (/^Status: [OR]/);
- }
-
- $read++ if (/^From /);
-
- # Remove folder internal data, but only once
- if (/^Subject: .*FOLDER INTERNAL DATA/) {
- if ($internal_removed == 0) {
- $internal_removed = 1;
- $read--;
- $unread--;
- }
- }
- }
- close($f);
- }
- } else {
- opendir(DIR, "$mailfile/cur") or return 0;
- while (defined(my $file = readdir(DIR))) {
- next if $file =~ /^(.|..)$/;
- # Maildir flags: http://cr.yp.to/proto/maildir.html
- # My old regexps were useless if the MUA added any
- # non-default flags -qvr
- #
- # deleted mail
- next if $file =~ /\:.*?T.*?$/;
- if($old_is_not_new) {
- # when mail gets moved from new to cur it's name _always_
- # changes from uniq to uniq:info, even when it's still not
- # read. I assume "old mail" means mail which hasn't been read
- # yet but it has been "acknowledged" by the user. (it's been
- # moved to cur) -qvr
- if ($file =~ /\:.*?$/) {
- $read++;
- next;
- }
- } else {
- if ($file =~ /\:.*?S.*?$/) {
- $read++;
- next;
- }
- }
- $unread++;
- }
- closedir(DIR);
+ my $count;
+ if ($extprog ne "") {
+ $count = `$extprog`;
+ chomp $count;
+ } else {
+ return 0 if (!open(F, $mailfile));
- opendir(DIR, "$mailfile/new") or return 0;
- while (defined(my $file = readdir(DIR))) {
- next if $file =~ /^(.|..)$/;
- $unread++;
- }
- closedir(DIR);
+ $count = 0;
+ while (<F>) {
+ $count++ if (/^From /);
+ $count-- if (/^Subject: .*FOLDER INTERNAL DATA/);
}
+ close(F);
}
- if ($unread eq "" || $unread < 0) {
- $unread = 0;
- }
- if ($read eq "" || $read < 0) {
- $read = 0;
- }
-
- $last_mailcount = $unread;
-
- return ($unread, $read);
+ $last_mailcount = $count;
+ return $count;
}
-# Checks for mail and sets the statusbar item to the right string.
-# Also shows a message in the active window if that setting is set.
sub mail {
my ($item, $get_size_only) = @_;
- my $result;
- my $format = Irssi::settings_get_str('mail_format');
- my $unread = 0;
- my $read = 0;
- my $total = 0;
-
- # check all mailboxes for new email
- foreach $name (keys(%mailboxes)) {
- my $box = $mailboxes{$name};
- # replace "~/" at the beginning by the user's home dir
- $box =~ s/^~\//$ENV{'HOME'}\//;
-
- ($unread, $read) = mbox_count($box);
- $unread = "0" if ($unread eq "");
- $read = "0" if ($read eq "");
- $total = $unread + $read;
- $total = "0" if ($total eq "");
-
- next if (Irssi::settings_get_bool('mail_show_only_unread') && $unread == 0);
-
- if ($total eq "") { $total = 0; }
- if (length($result) > 0) {
- $result .= Irssi::settings_get_str('mail_separator');
- }
- my $string = $format;
- $string =~ s/%n/$name/;
- $string =~ s/%u/$unread/;
- $string =~ s/%r/$read/;
- $string =~ s/%t/$total/;
- $result .= $string;
-
- # Show -!- You have <num> new messages in <name>.
- # Show this only if there are any new, unread messages.
- if (Irssi::settings_get_bool('mail_show_message') &&
- $unread > $new_mails_in_box{$name}) {
- $new_mails = $unread - $new_mails_in_box{$name};
- if ($nummailboxes == 1) {
- Irssi::print("You have $new_mails new message" . ($new_mails != 1 ? "s." : "."), MSGLEVEL_CRAP);
- } else {
- Irssi::print("You have $new_mails new message" . ($new_mails != 1 ? "s " : " ") . "in $name.", MSGLEVEL_CRAP);
- }
- }
-
- $new_mails_in_box{$name} = $unread;
- }
-
- if (length($result) == 0) {
+ my $count = mbox_count(Irssi::settings_get_str('mail_file'));
+ if ($count == 0) {
# no mail - don't print the [Mail: ] at all
if ($get_size_only) {
$item->{min_size} = $item->{max_size} = 0;
}
} else {
- $item->default_handler($get_size_only, undef, $result, 1);
+ $item->default_handler($get_size_only, undef, $count, 1);
}
}
Irssi::statusbar_items_redraw('mail');
}
-# Adds the mailboxes from a string. Only to be used during startup.
-sub add_mailboxes {
- my $boxstring = $_[0];
- my @boxes = split(/,/, $boxstring);
-
- foreach $dbox(@boxes) {
- my $name = $dbox;
- $name = substr($dbox, 0, index($dbox, '='));
- my $box = $dbox;
- $box = substr($dbox, index($dbox, '=') + 1, length($dbox));
- addmailbox($name, $box);
- }
-}
-
-sub addmailbox {
- my ($name, $box) = @_;
-
- if (exists($mailboxes{$name})) {
- if ($box eq $mailboxes{$name}) {
- Irssi::print("Mailbox $name already set to $box", MSGLEVEL_CRAP);
- } else {
- Irssi::print("Mailbox $name changed to $box", MSGLEVEL_CRAP);
- $new_mails_in_box{$name} = 0;
- }
- } else {
- Irssi::print("Mailbox $name added: " . $box, MSGLEVEL_CRAP);
- $new_mails_in_box{$name} = 0;
- $nummailboxes++;
- }
- $mailboxes{$name} = $box;
-}
-
-sub delmailbox {
- my $name = $_[0];
-
- if (exists($mailboxes{$name})) {
- Irssi::print("Mailbox $name removed", MSGLEVEL_CRAP);
- delete($mailboxes{$name});
- delete($new_mails_in_box{$name});
- $nummailboxes--;
- } else {
- Irssi::print("No such mailbox $name. Use /mailbox show to see a list.", MSGLEVEL_CRAP);
- }
-}
-
-sub update_settings_string {
- my $setting;
-
- foreach $name (keys(%mailboxes)) {
- $setting .= $name . "=" . $mailboxes{$name} . ",";
- }
-
- Irssi::settings_set_str("mail_mailboxes", $setting);
-}
-
-sub cmd_addmailbox {
- my ($name, $box) = split(/ +/, $_[0]);
-
- if ($name eq "" || $box eq "") {
- Irssi::print("Use /mailbox add <name> <mailbox> to add a mailbox.", MSGLEVEL_CRAP);
- return;
- }
-
- addmailbox($name, $box);
- update_settings_string();
- refresh_mail();
-}
-
-sub cmd_delmailbox {
- my $name = $_[0];
-
- if ($name eq "") {
- Irssi::print("Use /mailbox del <name> to delete a mailbox.", MSGLEVEL_CRAP);
- return;
- }
-
- delmailbox($name);
- update_settings_string();
- refresh_mail();
-}
-
-sub cmd_showmailboxes {
- if ($nummailboxes == 0) {
- Irssi::print("No mailboxes defined.", MSGLEVEL_CRAP);
- return;
- }
- Irssi::print("Mailboxes:", MSGLEVEL_CRAP);
- foreach $box (keys(%mailboxes)) {
- Irssi::print("$box: " . $mailboxes{$box}, MSGLEVEL_CRAP);
- }
-}
-
-sub cmd_mailboxes {
- my ($data, $server, $item) = @_;
- if ($data =~ m/^[(show)|(add)|(del)]/i ) {
- Irssi::command_runsub ('mailbox', $data, $server, $item);
- }
- else {
- Irssi::print("Use /mailbox (show|add|del).")
- }
-}
-
-sub init_mailboxes {
- # Add the mailboxes at startup of the script
- my $boxes = Irssi::settings_get_str('mail_mailboxes');
- if (length($boxes) > 0) {
- add_mailboxes($boxes);
- }
-}
-
sub read_settings {
$extprog = Irssi::settings_get_str('mail_ext_program');
my $time = Irssi::settings_get_int('mail_refresh_time');
- my $mode = Irssi::settings_get_bool('maildir_mode');
- unless ($time == $last_refresh_time) {
- $last_refresh_time = $time;
- Irssi::timeout_remove($refresh_tag) if ($refresh_tag);
- $refresh_tag = Irssi::timeout_add($time*1000, 'refresh_mail', undef);
- }
- return if ($mode == $last_mode);
- $last_mode = $mode;
- refresh_mail;
-}
-
+ return if ($time == $last_refresh_time);
-if (!$maildirmode) {
- my $default = "1=" . $ENV{'MAIL'} . ",";
- Irssi::settings_add_str('misc', 'mail_mailboxes', $default);
-} else {
- my $default = "1=~/Maildir/,";
- Irssi::settings_add_str('misc', 'mail_mailboxes', $default);
+ $last_refresh_time = $time;
+ Irssi::timeout_remove($refresh_tag) if ($refresh_tag);
+ $refresh_tag = Irssi::timeout_add($time*1000, 'refresh_mail', undef);
}
-Irssi::command_bind('mailbox show', 'cmd_showmailboxes');
-Irssi::command_bind('mailbox add', 'cmd_addmailbox');
-Irssi::command_bind('mailbox del', 'cmd_delmailbox');
-Irssi::command_bind('mailbox help', 'cmd_print_help');
-Irssi::command_bind('mailbox', 'cmd_mailboxes');
-
Irssi::settings_add_str('misc', 'mail_ext_program', '');
+Irssi::settings_add_str('misc', 'mail_file', $ENV{'MAIL'});
Irssi::settings_add_int('misc', 'mail_refresh_time', 60);
-Irssi::settings_add_bool('misc', 'maildir_mode', "$maildirmode");
-Irssi::settings_add_bool('misc', 'mail_oldnotnew', "$old_is_not_new");
-Irssi::settings_add_str('misc', 'mail_separator', ",");
-Irssi::settings_add_bool('misc', 'mail_show_message', "0");
-Irssi::settings_add_str('misc', 'mail_format', '%n:%u/%t');
-Irssi::settings_add_bool('misc', 'mail_show_only_unread', "1");
Irssi::statusbar_item_register('mail', '{sb Mail: $0-}', 'mail');
read_settings();
-init_mailboxes();
Irssi::signal_add('setup changed', 'read_settings');
-refresh_mail();
-
-# EOF
+mbox_count(Irssi::settings_get_str('mail_file'));
+++ /dev/null
-# /MLOCK <channel> <mode>
-#
-# Locks the channel mode to <mode>, if someone else tries to change the mode
-# Irssi will automatically change it back. +k and +l are a bit special since
-# they require the parameter. If you omit the parameter, like setting the
-# mode to "+ntlk", Irssi will allow all +k and +l (or -lk) mode changes.
-# You can remove the lock with /MODE #channel -
-
-use Irssi;
-use Irssi::Irc;
-use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'mlock',
- description => 'Channel mode locking',
- license => 'Public Domain',
- changed => 'Sun Mar 10 23:18 EET 2002'
-);
-
-my %keep_channels;
-
-sub cmd_mlock {
- my ($data, $server) = @_;
- my ($channel, $mode) = split(/ /, $data, 2);
-
- if ($mode eq "-") {
- # remove checking
- delete $keep_channels{$channel};
- } else {
- $keep_channels{$channel} = $mode;
- mlock_check_mode($server, $channel);
- }
-}
-
-sub mlock_check_mode {
- my ($server, $channame) = @_;
-
- my $channel = $server->channel_find($channame);
- return if (!$channel || !$channel->{chanop});
-
- my $keep_mode = $keep_channels{$channame};
- return if (!$keep_mode);
-
- # old channel mode
- my ($oldmode, $oldkey, $oldlimit);
- $oldmode = $channel->{mode};
- $oldmode =~ s/^([^ ]*).*/\1/;
- $oldkey = $channel->{key};
- $oldlimit = $channel->{limit};
-
- # get the new channel key/limit
- my (@newmodes, $newkey, $limit);
- @newmodes = split(/ /, $keep_mode); $keep_mode = $newmodes[0];
- if ($keep_mode =~ /k/) {
- if ($keep_mode =~ /k.*l/) {
- $newkey = $newmodes[1];
- $limit = $newmodes[2];
- } elsif ($keep_mode =~ /l.*k/) {
- $limit = $newmodes[1];
- $newkey = $newmodes[2];
- } else {
- $newkey = $newmodes[1];
- }
- } elsif ($keep_mode =~ /l/) {
- $limit = $newmodes[1];
- }
-
- # check the differences
- my %allmodes;
- $keep_mode =~ s/^\+//;
- for (my $n = 0; $n < length($keep_mode); $n++) {
- my $modechar = substr($keep_mode, $n, 1);
- $allmodes{$modechar} = '+';
- }
-
- for (my $n = 0; $n < length($oldmode); $n++) {
- my $modechar = substr($oldmode, $n, 1);
-
- if ($allmodes{$modechar} eq '+') {
- next if (($modechar eq "k" && $newkey ne $oldkey) ||
- ($modechar eq "l" && $limit != $oldlimit));
- delete $allmodes{$modechar};
- } else {
- $allmodes{$modechar} = '-';
- }
- }
-
- # create the mode change string
- my ($modecmd, $extracmd);
- foreach my $mode (keys %allmodes) {
- Irssi::print("key = '$mode':".$allmodes{$mode});
- if ($mode eq "k") {
- if ($allmodes{$mode} eq '+') {
- next if ($newkey eq "");
- if ($oldkey ne "") {
- # we need to get rid of old key too
- $modecmd .= "-k";
- $extracmd .= " $oldkey";
- }
- $extracmd .= " $newkey";
- } else {
- $extracmd .= " $oldkey";
- }
- }
- if ($mode eq "l" && $allmodes{$mode} eq '+') {
- next if ($limit <= 0);
- $extracmd .= " $limit";
- }
- $modecmd .= $allmodes{$mode}.$mode;
- }
-
- if ($modecmd ne "") {
- $channel->{server}->command("mode $channame $modecmd$extracmd");
- }
-}
-
-sub mlock_mode_changed {
- my ($server, $data) = @_;
- my ($channel, $mode) = split(/ /, $data, 2);
-
- mlock_check_mode($server, $channel);
-}
-
-sub mlock_synced {
- my $channel = $_[0];
-
- mlock_check_mode($channel->{server}, $channel->{name});
-}
-
-Irssi::command_bind('mlock', 'cmd_mlock');
-Irssi::signal_add_last("event mode", "mlock_mode_changed");
-Irssi::signal_add("channel synced", "mlock_synced");
+++ /dev/null
-# If quit message isn't given, quit with a random message
-# read from ~/.irssi/irssi.quit
-
-use Irssi;
-use Irssi::Irc;
-use strict;
-use vars qw($VERSION %IRSSI);
-
-$VERSION = "1.00";
-%IRSSI = (
- authors => 'Timo Sirainen',
- name => 'quitmsg',
- description => 'Random quit messages',
- license => 'Public Domain',
- changed => 'Sun Mar 10 23:18 EET 2002'
-);
-
-my $quitfile = glob "~/.irssi/irssi.quit";
-
-sub cmd_quit {
- my ($data, $server, $channel) = @_;
- return if ($data ne "");
-
- open (f, $quitfile) || return;
- my $lines = 0; while(<f>) { $lines++; };
-
- my $line = int(rand($lines))+1;
-
- my $quitmsg;
- seek(f, 0, 0); $. = 0;
- while(<f>) {
- next if ($. != $line);
-
- chomp;
- $quitmsg = $_;
- last;
- }
- close(f);
-
- foreach my $server (Irssi::servers) {
- $server->command("disconnect ".$server->{tag}." $quitmsg");
- }
-}
-
-Irssi::command_bind('quit', 'cmd_quit');
+++ /dev/null
-# by Stefan "tommie" Tomanek
-#
-# scriptassist.pl
-
-
-use strict;
-
-use vars qw($VERSION %IRSSI);
-$VERSION = '2003020803';
-%IRSSI = (
- authors => 'Stefan \'tommie\' Tomanek',
- contact => 'stefan@pico.ruhr.de',
- name => 'scriptassist',
- description => 'keeps your scripts on the cutting edge',
- license => 'GPLv2',
- url => 'http://irssi.org/scripts/',
- changed => $VERSION,
- modules => 'Data::Dumper LWP::UserAgent (GnuPG)',
- commands => "scriptassist"
-);
-
-use vars qw($forked %remote_db $have_gpg);
-
-use Irssi 20020324;
-use Data::Dumper;
-use LWP::UserAgent;
-use POSIX;
-
-# GnuPG is not always needed
-use vars qw($have_gpg @complist);
-$have_gpg = 0;
-eval "use GnuPG qw(:algo :trust);";
-$have_gpg = 1 if not ($@);
-
-sub show_help() {
- my $help = "scriptassist $VERSION
-/scriptassist check
- Check all loaded scripts for new available versions
-/scriptassist update <script|all>
- Update the selected or all script to the newest version
-/scriptassist search <query>
- Search the script database
-/scriptassist info <scripts>
- Display information about <scripts>
-/scriptassist ratings <scripts>
- Retrieve the average ratings of the the scripts
-/scriptassist top <num>
- Retrieve the first <num> top rated scripts
-/scriptassist new <num>
- Display the newest <num> scripts
-/scriptassist rate <script> <stars>
- Rate the script with a number of stars ranging from 0-5
-/scriptassist contact <script>
- Write an email to the author of the script
- (Requires OpenURL)
-/scriptassist cpan <module>
- Visit CPAN to look for missing Perl modules
- (Requires OpenURL)
-/scriptassist install <script>
- Retrieve and load the script
-/scriptassist autorun <script>
- Toggles automatic loading of <script>
-";
- my $text='';
- foreach (split(/\n/, $help)) {
- $_ =~ s/^\/(.*)$/%9\/$1%9/;
- $text .= $_."\n";
- }
- print CLIENTCRAP &draw_box("ScriptAssist", $text, "scriptassist help", 1);
- #theme_box("ScriptAssist", $text, "scriptassist help", 1);
-}
-
-sub theme_box ($$$$) {
- my ($title, $text, $footer, $colour) = @_;
- Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'box_header', $title);
- foreach (split(/\n/, $text)) {
- Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'box_inside', $_);
- }
- Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'box_footer', $footer);
-}
-
-sub draw_box ($$$$) {
- my ($title, $text, $footer, $colour) = @_;
- my $box = '';
- $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n";
- foreach (split(/\n/, $text)) {
- $box .= '%R|%n '.$_."\n";
- } $box .= '%R`--<%n'.$footer.'%R>->%n';
- $box =~ s/%.//g unless $colour;
- return $box;
-}
-
-sub call_openurl ($) {
- my ($url) = @_;
- no strict "refs";
- # check for a loaded openurl
- if (defined %{ "Irssi::Script::openurl::" }) {
- &{ "Irssi::Script::openurl::launch_url" }($url);
- } else {
- print CLIENTCRAP "%R>>%n Please install openurl.pl";
- }
- use strict;
-}
-
-sub bg_do ($) {
- my ($func) = @_;
- my ($rh, $wh);
- pipe($rh, $wh);
- if ($forked) {
- print CLIENTCRAP "%R>>%n Please wait until your earlier request has been finished.";
- return;
- }
- my $pid = fork();
- $forked = 1;
- if ($pid > 0) {
- print CLIENTCRAP "%R>>%n Please wait...";
- close $wh;
- Irssi::pidwait_add($pid);
- my $pipetag;
- my @args = ($rh, \$pipetag, $func);
- $pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args);
- } else {
- eval {
- my @items = split(/ /, $func);
- my %result;
- my $ts1 = $remote_db{timestamp};
- my $xml = get_scripts();
- my $ts2 = $remote_db{timestamp};
- if (not($ts1 eq $ts2) && Irssi::settings_get_bool('scriptassist_cache_sources')) {
- $result{db} = $remote_db{db};
- $result{timestamp} = $remote_db{timestamp};
- }
- if ($items[0] eq 'check') {
- $result{data}{check} = check_scripts($xml);
- } elsif ($items[0] eq 'update') {
- shift(@items);
- $result{data}{update} = update_scripts(\@items, $xml);
- } elsif ($items[0] eq 'search') {
- shift(@items);
- #$result{data}{search}{-foo} = 0;
- foreach (@items) {
- $result{data}{search}{$_} = search_scripts($_, $xml);
- }
- } elsif ($items[0] eq 'install') {
- shift(@items);
- $result{data}{install} = install_scripts(\@items, $xml);
- } elsif ($items[0] eq 'debug') {
- shift(@items);
- $result{data}{debug} = debug_scripts(\@items);
- } elsif ($items[0] eq 'ratings') {
- shift(@items);
- @items = @{ loaded_scripts() } if $items[0] eq "all";
- #$result{data}{rating}{-foo} = 1;
- my %ratings = %{ get_ratings(\@items, '') };
- foreach (keys %ratings) {
- $result{data}{rating}{$_}{rating} = $ratings{$_}->[0];
- $result{data}{rating}{$_}{votes} = $ratings{$_}->[1];
- }
- } elsif ($items[0] eq 'rate') {
- #$result{data}{rate}{-foo} = 1;
- $result{data}{rate}{$items[1]} = rate_script($items[1], $items[2]);
- } elsif ($items[0] eq 'info') {
- shift(@items);
- $result{data}{info} = script_info(\@items);
- } elsif ($items[0] eq 'echo') {
- $result{data}{echo} = 1;
- } elsif ($items[0] eq 'top') {
- my %ratings = %{ get_ratings([], $items[1]) };
- foreach (keys %ratings) {
- $result{data}{rating}{$_}{rating} = $ratings{$_}->[0];
- $result{data}{rating}{$_}{votes} = $ratings{$_}->[1];
- }
- } elsif ($items[0] eq 'new') {
- my $new = get_new($items[1]);
- $result{data}{new} = $new;
- } elsif ($items[0] eq 'unknown') {
- my $cmd = $items[1];
- $result{data}{unknown}{$cmd} = get_unknown($cmd, $xml);
- }
- my $dumper = Data::Dumper->new([\%result]);
- $dumper->Purity(1)->Deepcopy(1)->Indent(0);
- my $data = $dumper->Dump;
- print($wh $data);
- };
- close($wh);
- POSIX::_exit(1);
- }
-}
-
-sub get_unknown ($$) {
- my ($cmd, $db) = @_;
- foreach (keys %$db) {
- next unless defined $db->{$_}{commands};
- foreach my $item (split / /, $db->{$_}{commands}) {
- return { $_ => $db->{$_} } if ($item =~ /^$cmd$/i);
- }
- }
- return undef;
-}
-
-sub script_info ($) {
- my ($scripts) = @_;
- no strict "refs";
- my %result;
- my $xml = get_scripts();
- foreach (@{$scripts}) {
- next unless (defined $xml->{$_.".pl"} || (defined %{ 'Irssi::Script::'.$_.'::' } && defined %{ 'Irssi::Script::'.$_.'::IRSSI' }));
- $result{$_}{version} = get_remote_version($_, $xml);
- my @headers = ('authors', 'contact', 'description', 'license', 'source');
- foreach my $entry (@headers) {
- $result{$_}{$entry} = ${ 'Irssi::Script::'.$_.'::IRSSI' }{$entry};
- if (defined $xml->{$_.".pl"}{$entry}) {
- $result{$_}{$entry} = $xml->{$_.".pl"}{$entry};
- }
- }
- if ($xml->{$_.".pl"}{signature_available}) {
- $result{$_}{signature_available} = 1;
- }
- if (defined $xml->{$_.".pl"}{modules}) {
- my $modules = $xml->{$_.".pl"}{modules};
- #$result{$_}{modules}{-foo} = 1;
- foreach my $mod (split(/ /, $modules)) {
- my $opt = ($mod =~ /\((.*)\)/)? 1 : 0;
- $mod = $1 if $1;
- $result{$_}{modules}{$mod}{optional} = $opt;
- $result{$_}{modules}{$mod}{installed} = module_exist($mod);
- }
- } elsif (defined ${ 'Irssi::Script::'.$_.'::IRSSI' }{modules}) {
- my $modules = ${ 'Irssi::Script::'.$_.'::IRSSI' }{modules};
- foreach my $mod (split(/ /, $modules)) {
- my $opt = ($mod =~ /\((.*)\)/)? 1 : 0;
- $mod = $1 if $1;
- $result{$_}{modules}{$mod}{optional} = $opt;
- $result{$_}{modules}{$mod}{installed} = module_exist($mod);
- }
- }
- if (defined $xml->{$_.".pl"}{depends}) {
- my $depends = $xml->{$_.".pl"}{depends};
- foreach my $dep (split(/ /, $depends)) {
- $result{$_}{depends}{$dep}{installed} = 1; #(defined ${ 'Irssi::Script::'.$dep });
- }
- }
- }
- return \%result;
-}
-
-sub rate_script ($$) {
- my ($script, $stars) = @_;
- my $ua = LWP::UserAgent->new(env_proxy=>1, keep_alive=>1, timeout=>30);
- $ua->agent('ScriptAssist/'.$VERSION);
- my $request = HTTP::Request->new('GET', 'http://ratings.irssi.de/irssirate.pl?&stars='.$stars.'&mode=rate&script='.$script);
- my $response = $ua->request($request);
- unless ($response->is_success() && $response->content() =~ /You already rated this script/) {
- return 1;
- } else {
- return 0;
- }
-}
-
-sub get_ratings ($$) {
- my ($scripts, $limit) = @_;
- my $ua = LWP::UserAgent->new(env_proxy=>1, keep_alive=>1, timeout=>30);
- $ua->agent('ScriptAssist/'.$VERSION);
- my $script = join(',', @{$scripts});
- my $request = HTTP::Request->new('GET', 'http://ratings.irssi.de/irssirate.pl?script='.$script.'&sort=rating&limit='.$limit);
- my $response = $ua->request($request);
- my %result;
- if ($response->is_success()) {
- foreach (split /\n/, $response->content()) {
- if (/<tr><td><a href=".*?">(.*?)<\/a>/) {
- my $entry = $1;
- if (/"><\/td><td>([0-9.]+)<\/td><td>(.*?)<\/td><td>/) {
- $result{$entry} = [$1, $2];
- }
- }
- }
- }
- return \%result;
-}
-
-sub get_new ($) {
- my ($num) = @_;
- my $result;
- my $xml = get_scripts();
- foreach (sort {$xml->{$b}{last_modified} cmp $xml->{$a}{last_modified}} keys %$xml) {
- my %entry = %{ $xml->{$_} };
- $result->{$_} = \%entry;
- $num--;
- last unless $num;
- }
- return $result;
-}
-sub module_exist ($) {
- my ($module) = @_;
- $module =~ s/::/\//g;
- foreach (@INC) {
- return 1 if (-e $_."/".$module.".pm");
- }
- return 0;
-}
-
-sub debug_scripts ($) {
- my ($scripts) = @_;
- my %result;
- foreach (@{$scripts}) {
- my $xml = get_scripts();
- if (defined $xml->{$_.".pl"}{modules}) {
- my $modules = $xml->{$_.".pl"}{modules};
- foreach my $mod (split(/ /, $modules)) {
- my $opt = ($mod =~ /\((.*)\)/)? 1 : 0;
- $mod = $1 if $1;
- $result{$_}{$mod}{optional} = $opt;
- $result{$_}{$mod}{installed} = module_exist($mod);
- }
- }
- }
- return(\%result);
-}
-
-sub install_scripts ($$) {
- my ($scripts, $xml) = @_;
- my %success;
- #$success{-foo} = 1;
- my $dir = Irssi::get_irssi_dir()."/scripts/";
- foreach (@{$scripts}) {
- if (get_local_version($_) && (-e $dir.$_.".pl")) {
- $success{$_}{installed} = -2;
- } else {
- $success{$_} = download_script($_, $xml);
- }
- }
- return \%success;
-}
-
-sub update_scripts ($$) {
- my ($list, $database) = @_;
- $list = loaded_scripts() if ($list->[0] eq "all" || scalar(@$list) == 0);
- my %status;
- #$status{-foo} = 1;
- foreach (@{$list}) {
- my $local = get_local_version($_);
- my $remote = get_remote_version($_, $database);
- next if $local eq '' || $remote eq '';
- if (compare_versions($local, $remote) eq "older") {
- $status{$_} = download_script($_, $database);
- } else {
- $status{$_}{installed} = -2;
- }
- $status{$_}{remote} = $remote;
- $status{$_}{local} = $local;
- }
- return \%status;
-}
-
-sub search_scripts ($$) {
- my ($query, $database) = @_;
- my %result;
- #$result{-foo} = " ";
- foreach (sort keys %{$database}) {
- my %entry = %{$database->{$_}};
- my $string = $_." ";
- $string .= $entry{description} if defined $entry{description};
- if ($string =~ /$query/i) {
- my $name = $_;
- $name =~ s/\.pl$//;
- if (defined $entry{description}) {
- $result{$name}{desc} = $entry{description};
- } else {
- $result{$name}{desc} = "";
- }
- if (defined $entry{authors}) {
- $result{$name}{authors} = $entry{authors};
- } else {
- $result{$name}{authors} = "";
- }
- if (get_local_version($name)) {
- $result{$name}{installed} = 1;
- } else {
- $result{$name}{installed} = 0;
- }
- }
- }
- return \%result;
-}
-
-sub pipe_input {
- my ($rh, $pipetag) = @{$_[0]};
- my @lines = <$rh>;
- close($rh);
- Irssi::input_remove($$pipetag);
- $forked = 0;
- my $text = join("", @lines);
- unless ($text) {
- print CLIENTCRAP "%R<<%n Something weird happend";
- return();
- }
- no strict "vars";
- my $incoming = eval("$text");
- if ($incoming->{db} && $incoming->{timestamp}) {
- $remote_db{db} = $incoming->{db};
- $remote_db{timestamp} = $incoming->{timestamp};
- }
- unless (defined $incoming->{data}) {
- print CLIENTCRAP "%R<<%n Something weird happend";
- return;
- }
- my %result = %{ $incoming->{data} };
- @complist = ();
- if (defined $result{new}) {
- print_new($result{new});
- push @complist, $_ foreach keys %{ $result{new} };
- }
- if (defined $result{check}) {
- print_check(%{$result{check}});
- push @complist, $_ foreach keys %{ $result{check} };
- }
- if (defined $result{update}) {
- print_update(%{ $result{update} });
- push @complist, $_ foreach keys %{ $result{update} };
- }
- if (defined $result{search}) {
- foreach (keys %{$result{search}}) {
- print_search($_, %{$result{search}{$_}});
- push @complist, keys(%{$result{search}{$_}});
- }
- }
- if (defined $result{install}) {
- print_install(%{ $result{install} });
- push @complist, $_ foreach keys %{ $result{install} };
- }
- if (defined $result{debug}) {
- print_debug(%{ $result{debug} });
- }
- if (defined $result{rating}) {
- print_ratings(%{ $result{rating} });
- push @complist, $_ foreach keys %{ $result{rating} };
- }
- if (defined $result{rate}) {
- print_rate(%{ $result{rate} });
- }
- if (defined $result{info}) {
- print_info(%{ $result{info} });
- }
- if (defined $result{echo}) {
- Irssi::print "ECHO";
- }
- if ($result{unknown}) {
- print_unknown($result{unknown});
- }
-
-}
-
-sub print_unknown ($) {
- my ($data) = @_;
- foreach my $cmd (keys %$data) {
- print CLIENTCRAP "%R<<%n No script provides '/$cmd'" unless $data->{$cmd};
- foreach (keys %{ $data->{$cmd} }) {
- my $text .= "The command '/".$cmd."' is provided by the script '".$data->{$cmd}{$_}{name}."'.\n";
- $text .= "This script is currently not installed on your system.\n";
- $text .= "If you want to install the script, enter\n";
- my ($name) = /(.*?)\.pl$/;
- $text .= " %U/script install ".$name."%U ";
- my $output = draw_box("ScriptAssist", $text, "'".$_."' missing", 1);
- print CLIENTCRAP $output;
- }
- }
-}
-
-sub check_autorun ($) {
- my ($script) = @_;
- my $dir = Irssi::get_irssi_dir()."/scripts/";
- if (-e $dir."/autorun/".$script.".pl") {
- if (readlink($dir."/autorun/".$script.".pl") eq "../".$script.".pl") {
- return 1;
- }
- }
- return 0;
-}
-
-sub array2table {
- my (@array) = @_;
- my @width;
- foreach my $line (@array) {
- for (0..scalar(@$line)-1) {
- my $l = $line->[$_];
- $l =~ s/%[^%]//g;
- $l =~ s/%%/%/g;
- $width[$_] = length($l) if $width[$_]<length($l);
- }
- }
- my $text;
- foreach my $line (@array) {
- for (0..scalar(@$line)-1) {
- my $l = $line->[$_];
- $text .= $line->[$_];
- $l =~ s/%[^%]//g;
- $l =~ s/%%/%/g;
- $text .= " "x($width[$_]-length($l)+1) unless ($_ == scalar(@$line)-1);
- }
- $text .= "\n";
- }
- return $text;
-}
-
-
-sub print_info (%) {
- my (%data) = @_;
- my $line;
- foreach my $script (sort keys(%data)) {
- my ($local, $autorun);
- if (get_local_version($script)) {
- $line .= "%go%n ";
- $local = get_local_version($script);
- } else {
- $line .= "%ro%n ";
- $local = undef;
- }
- if (defined $local || check_autorun($script)) {
- $autorun = "no";
- $autorun = "yes" if check_autorun($script);
- } else {
- $autorun = undef;
- }
- $line .= "%9".$script."%9\n";
- $line .= " Version : ".$data{$script}{version}."\n";
- $line .= " Source : ".$data{$script}{source}."\n";
- $line .= " Installed : ".$local."\n" if defined $local;
- $line .= " Autorun : ".$autorun."\n" if defined $autorun;
- $line .= " Authors : ".$data{$script}{authors};
- $line .= " %Go-m signed%n" if $data{$script}{signature_available};
- $line .= "\n";
- $line .= " Contact : ".$data{$script}{contact}."\n";
- $line .= " Description: ".$data{$script}{description}."\n";
- $line .= "\n" if $data{$script}{modules};
- $line .= " Needed Perl modules:\n" if $data{$script}{modules};
-
- foreach (sort keys %{$data{$script}{modules}}) {
- if ( $data{$script}{modules}{$_}{installed} == 1 ) {
- $line .= " %g->%n ".$_." (found)";
- } else {
- $line .= " %r->%n ".$_." (not found)";
- }
- $line .= " <optional>" if $data{$script}{modules}{$_}{optional};
- $line .= "\n";
- }
- #$line .= " Needed Irssi scripts:\n";
- $line .= " Needed Irssi Scripts:\n" if $data{$script}{depends};
- foreach (sort keys %{$data{$script}{depends}}) {
- if ( $data{$script}{depends}{$_}{installed} == 1 ) {
- $line .= " %g->%n ".$_." (loaded)";
- } else {
- $line .= " %r->%n ".$_." (not loaded)";
- }
- #$line .= " <optional>" if $data{$script}{depends}{$_}{optional};
- $line .= "\n";
- }
- }
- print CLIENTCRAP draw_box('ScriptAssist', $line, 'info', 1) ;
-}
-
-sub print_rate (%) {
- my (%data) = @_;
- my $line;
- foreach my $script (sort keys(%data)) {
- if ($data{$script}) {
- $line .= "%go%n %9".$script."%9 has been rated";
- } else {
- $line .= "%ro%n %9".$script."%9 : Already rated this script";
- }
- }
- print CLIENTCRAP draw_box('ScriptAssist', $line, 'rating', 1) ;
-}
-
-sub print_ratings (%) {
- my (%data) = @_;
- my @table;
- foreach my $script (sort {$data{$b}{rating}<=>$data{$a}{rating}} keys(%data)) {
- my @line;
- if (get_local_version($script)) {
- push @line, "%go%n";
- } else {
- push @line, "%yo%n";
- }
- push @line, "%9".$script."%9";
- push @line, $data{$script}{rating};
- push @line, "[".$data{$script}{votes}." votes]";
- push @table, \@line;
- }
- print CLIENTCRAP draw_box('ScriptAssist', array2table(@table), 'ratings', 1) ;
-}
-
-sub print_new ($) {
- my ($list) = @_;
- my @table;
- foreach (sort {$list->{$b}{last_modified} cmp $list->{$a}{last_modified}} keys %$list) {
- my @line;
- my ($name) = /^(.*?)\.pl$/;
- if (get_local_version($name)) {
- push @line, "%go%n";
- } else {
- push @line, "%yo%n";
- }
- push @line, "%9".$name."%9";
- push @line, $list->{$_}{last_modified};
- push @table, \@line;
- }
- print CLIENTCRAP draw_box('ScriptAssist', array2table(@table), 'new scripts', 1) ;
-}
-
-sub print_debug (%) {
- my (%data) = @_;
- my $line;
- foreach my $script (sort keys %data) {
- $line .= "%ro%n %9".$script."%9 failed to load\n";
- $line .= " Make sure you have the following perl modules installed:\n";
- foreach (sort keys %{$data{$script}}) {
- if ( $data{$script}{$_}{installed} == 1 ) {
- $line .= " %g->%n ".$_." (found)";
- } else {
- $line .= " %r->%n ".$_." (not found)\n";
- $line .= " [This module is optional]\n" if $data{$script}{$_}{optional};
- $line .= " [Try /scriptassist cpan ".$_."]";
- }
- $line .= "\n";
- }
- print CLIENTCRAP draw_box('ScriptAssist', $line, 'debug', 1) ;
- }
-}
-
-sub load_script ($) {
- my ($script) = @_;
- Irssi::command('script load '.$script);
-}
-
-sub print_install (%) {
- my (%data) = @_;
- my $text;
- my ($crashed, @installed);
- foreach my $script (sort keys %data) {
- my $line;
- if ($data{$script}{installed} == 1) {
- my $hacked;
- if ($have_gpg && Irssi::settings_get_bool('scriptassist_use_gpg')) {
- if ($data{$script}{signed} >= 0) {
- load_script($script) unless (lc($script) eq lc($IRSSI{name}));
- } else {
- $hacked = 1;
- }
- } else {
- load_script($script) unless (lc($script) eq lc($IRSSI{name}));
- }
- if (get_local_version($script) && not lc($script) eq lc($IRSSI{name})) {
- $line .= "%go%n %9".$script."%9 installed\n";
- push @installed, $script;
- } elsif (lc($script) eq lc($IRSSI{name})) {
- $line .= "%yo%n %9".$script."%9 installed, please reload manually\n";
- } else {
- $line .= "%Ro%n %9".$script."%9 fetched, but unable to load\n";
- $crashed .= $script." " unless $hacked;
- }
- if ($have_gpg && Irssi::settings_get_bool('scriptassist_use_gpg')) {
- foreach (split /\n/, check_sig($data{$script})) {
- $line .= " ".$_."\n";
- }
- }
- } elsif ($data{$script}{installed} == -2) {
- $line .= "%ro%n %9".$script."%9 already loaded, please try \"update\"\n";
- } elsif ($data{$script}{installed} <= 0) {
- $line .= "%ro%n %9".$script."%9 not installed\n";
- foreach (split /\n/, check_sig($data{$script})) {
- $line .= " ".$_."\n";
- }
- } else {
- $line .= "%Ro%n %9".$script."%9 not found on server\n";
- }
- $text .= $line;
- }
- # Inspect crashed scripts
- bg_do("debug ".$crashed) if $crashed;
- print CLIENTCRAP draw_box('ScriptAssist', $text, 'install', 1);
- list_sbitems(\@installed);
-}
-
-sub list_sbitems ($) {
- my ($scripts) = @_;
- my $text;
- foreach (@$scripts) {
- no strict 'refs';
- next unless defined %{ "Irssi::Script::${_}::" };
- next unless defined %{ "Irssi::Script::${_}::IRSSI" };
- my %header = %{ "Irssi::Script::${_}::IRSSI" };
- next unless $header{sbitems};
- $text .= '%9"'.$_.'"%9 provides the following statusbar item(s):'."\n";
- $text .= ' ->'.$_."\n" foreach (split / /, $header{sbitems});
- }
- return unless $text;
- $text .= "\n";
- $text .= "Enter '/statusbar window add <item>' to add an item.";
- print CLIENTCRAP draw_box('ScriptAssist', $text, 'sbitems', 1);
-}
-
-sub check_sig ($) {
- my ($sig) = @_;
- my $line;
- my %trust = ( -1 => 'undefined',
- 0 => 'never',
- 1 => 'marginal',
- 2 => 'fully',
- 3 => 'ultimate'
- );
- if ($sig->{signed} == 1) {
- $line .= "Signature found from ".$sig->{sig}{user}."\n";
- $line .= "Timestamp : ".$sig->{sig}{date}."\n";
- $line .= "Fingerprint: ".$sig->{sig}{fingerprint}."\n";
- $line .= "KeyID : ".$sig->{sig}{keyid}."\n";
- $line .= "Trust : ".$trust{$sig->{sig}{trust}}."\n";
- } elsif ($sig->{signed} == -1) {
- $line .= "%1Warning, unable to verify signature%n\n";
- } elsif ($sig->{signed} == 0) {
- $line .= "%1No signature found%n\n" unless Irssi::settings_get_bool('scriptassist_install_unsigned_scripts');
- }
- return $line;
-}
-
-sub print_search ($%) {
- my ($query, %data) = @_;
- my $text;
- foreach (sort keys %data) {
- my $line;
- $line .= "%go%n" if $data{$_}{installed};
- $line .= "%yo%n" if not $data{$_}{installed};
- $line .= " %9".$_."%9 ";
- $line .= $data{$_}{desc};
- $line =~ s/($query)/%U$1%U/gi;
- $line .= ' ('.$data{$_}{authors}.')';
- $text .= $line." \n";
- }
- print CLIENTCRAP draw_box('ScriptAssist', $text, 'search: '.$query, 1) ;
-}
-
-sub print_update (%) {
- my (%data) = @_;
- my $text;
- my @table;
- my $verbose = Irssi::settings_get_bool('scriptassist_update_verbose');
- foreach (sort keys %data) {
- my $signed = 0;
- if ($data{$_}{installed} == 1) {
- my $local = $data{$_}{local};
- my $remote = $data{$_}{remote};
- push @table, ['%yo%n', '%9'.$_.'%9', 'upgraded ('.$local.'->'.$remote.')'];
- foreach (split /\n/, check_sig($data{$_})) {
- push @table, ['', '', $_];
- }
- if (lc($_) eq lc($IRSSI{name})) {
- push @table, ['', '', "%R%9Please reload manually%9%n"];
- } else {
- load_script($_);
- }
- } elsif ($data{$_}{installed} == 0 || $data{$_}{installed} == -1) {
- push @table, ['%yo%n', '%9'.$_.'%9', 'not upgraded'];
- foreach (split /\n/, check_sig($data{$_})) {
- push @table, ['', '', $_];
- }
- } elsif ($data{$_}{installed} == -2 && $verbose) {
- my $local = $data{$_}{local};
- push @table, ['%go%n', '%9'.$_.'%9', 'already at the latest version ('.$local.')'];
- }
- }
- $text = array2table(@table);
- print CLIENTCRAP draw_box('ScriptAssist', $text, 'update', 1) ;
-}
-
-sub contact_author ($) {
- my ($script) = @_;
- no strict 'refs';
- return unless defined %{ "Irssi::Script::${script}::" };
- my %header = %{ "Irssi::Script::${script}::IRSSI" };
- if (defined $header{contact}) {
- my @ads = split(/ |,/, $header{contact});
- my $address = $ads[0];
- $address .= '?subject='.$script;
- $address .= '_'.get_local_version($script) if defined get_local_version($script);
- call_openurl($address);
- }
-}
-
-sub get_scripts {
- my $ua = LWP::UserAgent->new(env_proxy=>1, keep_alive=>1, timeout=>30);
- $ua->agent('ScriptAssist/'.$VERSION);
- $ua->env_proxy();
- my @mirrors = split(/ /, Irssi::settings_get_str('scriptassist_script_sources'));
- my %sites_db;
- my $fetched = 0;
- my @sources;
- foreach my $site (@mirrors) {
- my $request = HTTP::Request->new('GET', $site);
- if ($remote_db{timestamp}) {
- $request->if_modified_since($remote_db{timestamp});
- }
- my $response = $ua->request($request);
- next unless $response->is_success;
- $fetched = 1;
- my $data = $response->content();
- my ($src, $type);
- if ($site =~ /(.*\/).+\.(.+)/) {
- $src = $1;
- $type = $2;
- }
- push @sources, $src;
- #my @header = ('name', 'contact', 'authors', 'description', 'version', 'modules', 'last_modified');
- if ($type eq 'dmp') {
- no strict 'vars';
- my $new_db = eval "$data";
- foreach (keys %$new_db) {
- if (defined $sites_db{script}{$_}) {
- my $old = $sites_db{$_}{version};
- my $new = $new_db->{$_}{version};
- next if (compare_versions($old, $new) eq 'newer');
- }
- #foreach my $key (@header) {
- foreach my $key (keys %{ $new_db->{$_} }) {
- next unless defined $new_db->{$_}{$key};
- $sites_db{$_}{$key} = $new_db->{$_}{$key};
- }
- $sites_db{$_}{source} = $src;
- }
- } else {
- ## FIXME Panic?!
- }
-
- }
- if ($fetched) {
- # Clean database
- foreach (keys %{$remote_db{db}}) {
- foreach my $site (@sources) {
- if ($remote_db{db}{$_}{source} eq $site) {
- delete $remote_db{db}{$_};
- last;
- }
- }
- }
- $remote_db{db}{$_} = $sites_db{$_} foreach (keys %sites_db);
- $remote_db{timestamp} = time();
- }
- return $remote_db{db};
-}
-
-sub get_remote_version ($$) {
- my ($script, $database) = @_;
- return $database->{$script.".pl"}{version};
-}
-
-sub get_local_version ($) {
- my ($script) = @_;
- no strict 'refs';
- return unless defined %{ "Irssi::Script::${script}::" };
- my $version = ${ "Irssi::Script::${script}::VERSION" };
- return $version;
-}
-
-sub compare_versions ($$) {
- my ($ver1, $ver2) = @_;
- my @ver1 = split /\./, $ver1;
- my @ver2 = split /\./, $ver2;
- #if (scalar(@ver2) != scalar(@ver1)) {
- # return 0;
- #}
- my $cmp = 0;
- ### Special thanks to Clemens Heidinger
- $cmp ||= $ver1[$_] <=> $ver2[$_] || $ver1[$_] cmp $ver2[$_] for 0..scalar(@ver2);
- return 'newer' if $cmp == 1;
- return 'older' if $cmp == -1;
- return 'equal';
-}
-
-sub loaded_scripts {
- no strict 'refs';
- my @modules;
- foreach (sort grep(s/::$//, keys %Irssi::Script::)) {
- #my $name = ${ "Irssi::Script::${_}::IRSSI" }{name};
- #my $version = ${ "Irssi::Script::${_}::VERSION" };
- push @modules, $_;# if $name && $version;
- }
- return \@modules;
-
-}
-
-sub check_scripts {
- my ($data) = @_;
- my %versions;
- #$versions{-foo} = 1;
- foreach (@{loaded_scripts()}) {
- my $remote = get_remote_version($_, $data);
- my $local = get_local_version($_);
- my $state;
- if ($local && $remote) {
- $state = compare_versions($local, $remote);
- } elsif ($local) {
- $state = 'noversion';
- $remote = '/';
- } else {
- $state = 'noheader';
- $local = '/';
- $remote = '/';
- }
- if ($state) {
- $versions{$_}{state} = $state;
- $versions{$_}{remote} = $remote;
- $versions{$_}{local} = $local;
- }
- }
- return \%versions;
-}
-
-sub download_script ($$) {
- my ($script, $xml) = @_;
- my %result;
- my $site = $xml->{$script.".pl"}{source};
- $result{installed} = 0;
- $result{signed} = 0;
- my $dir = Irssi::get_irssi_dir();
- my $ua = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1,timeout => 30);
- $ua->agent('ScriptAssist/'.$VERSION);
- my $request = HTTP::Request->new('GET', $site.'/scripts/'.$script.'.pl');
- my $response = $ua->request($request);
- if ($response->is_success()) {
- my $file = $response->content();
- mkdir $dir.'/scripts/' unless (-e $dir.'/scripts/');
- local *F;
- open(F, '>'.$dir.'/scripts/'.$script.'.pl.new');
- print F $file;
- close(F);
- if ($have_gpg && Irssi::settings_get_bool('scriptassist_use_gpg')) {
- my $ua2 = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1,timeout => 30);
- $ua->agent('ScriptAssist/'.$VERSION);
- my $request2 = HTTP::Request->new('GET', $site.'/signatures/'.$script.'.pl.asc');
- my $response2 = $ua->request($request2);
- if ($response2->is_success()) {
- local *S;
- my $sig_dir = $dir.'/scripts/signatures/';
- mkdir $sig_dir unless (-e $sig_dir);
- open(S, '>'.$sig_dir.$script.'.pl.asc');
- my $file2 = $response2->content();
- print S $file2;
- close(S);
- my $sig;
- foreach (1..2) {
- # FIXME gpg needs two rounds to load the key
- my $gpg = new GnuPG();
- eval {
- $sig = $gpg->verify( file => $dir.'/scripts/'.$script.'.pl.new', signature => $sig_dir.$script.'.pl.asc' );
- };
- }
- if (defined $sig->{user}) {
- $result{installed} = 1;
- $result{signed} = 1;
- $result{sig}{$_} = $sig->{$_} foreach (keys %{$sig});
- } else {
- # Signature broken?
- $result{installed} = 0;
- $result{signed} = -1;
- }
- } else {
- $result{signed} = 0;
- $result{installed} = -1;
- $result{installed} = 1 if Irssi::settings_get_bool('scriptassist_install_unsigned_scripts');
- }
- } else {
- $result{signed} = 0;
- $result{installed} = -1;
- $result{installed} = 1 if Irssi::settings_get_bool('scriptassist_install_unsigned_scripts');
- }
- }
- if ($result{installed}) {
- my $old_dir = "$dir/scripts/old/";
- mkdir $old_dir unless (-e $old_dir);
- rename "$dir/scripts/$script.pl", "$old_dir/$script.pl.old" if -e "$dir/scripts/$script.pl";
- rename "$dir/scripts/$script.pl.new", "$dir/scripts/$script.pl";
- }
- return \%result;
-}
-
-sub print_check (%) {
- my (%data) = @_;
- my $text;
- my @table;
- foreach (sort keys %data) {
- my $state = $data{$_}{state};
- my $remote = $data{$_}{remote};
- my $local = $data{$_}{local};
- if (Irssi::settings_get_bool('scriptassist_check_verbose')) {
- push @table, ['%go%n', '%9'.$_.'%9', 'Up to date. ('.$local.')'] if $state eq 'equal';
- }
- push @table, ['%mo%n', '%9'.$_.'%9', "No version information available on network."] if $state eq "noversion";
- push @table, ['%mo%n', '%9'.$_.'%9', 'No header in script.'] if $state eq "noheader";
- push @table, ['%bo%n', '%9'.$_.'%9', "Your version is newer (".$local."->".$remote.")"] if $state eq "newer";
- push @table, ['%ro%n', '%9'.$_.'%9', "A new version is available (".$local."->".$remote.")"] if $state eq "older";;
- }
- $text = array2table(@table);
- print CLIENTCRAP draw_box('ScriptAssist', $text, 'check', 1) ;
-}
-
-sub toggle_autorun ($) {
- my ($script) = @_;
- my $dir = Irssi::get_irssi_dir()."/scripts/";
- mkdir $dir."autorun/" unless (-e $dir."autorun/");
- return unless (-e $dir.$script.".pl");
- if (check_autorun($script)) {
- if (readlink($dir."/autorun/".$script.".pl") eq "../".$script.".pl") {
- if (unlink($dir."/autorun/".$script.".pl")) {
- print CLIENTCRAP "%R>>%n Autorun of ".$script." disabled";
- } else {
- print CLIENTCRAP "%R>>%n Unable to delete link";
- }
- } else {
- print CLIENTCRAP "%R>>%n ".$dir."/autorun/".$script.".pl is not a correct link";
- }
- } else {
- symlink("../".$script.".pl", $dir."/autorun/".$script.".pl");
- print CLIENTCRAP "%R>>%n Autorun of ".$script." enabled";
- }
-}
-
-sub sig_script_error ($$) {
- my ($script, $msg) = @_;
- return unless Irssi::settings_get_bool('scriptassist_catch_script_errors');
- if ($msg =~ /Can't locate (.*?)\.pm in \@INC \(\@INC contains:(.*?) at/) {
- my $module = $1;
- $module =~ s/\//::/g;
- missing_module($module);
- }
-}
-
-sub missing_module ($$) {
- my ($module) = @_;
- my $text;
- $text .= "The perl module %9".$module."%9 is missing on your system.\n";
- $text .= "Please ask your administrator about it.\n";
- $text .= "You can also check CPAN via '/scriptassist cpan ".$module."'.\n";
- print CLIENTCRAP &draw_box('ScriptAssist', $text, $module, 1);
-}
-
-sub cmd_scripassist ($$$) {
- my ($arg, $server, $witem) = @_;
- my @args = split(/ /, $arg);
- if ($args[0] eq 'help' || $args[0] eq '-h') {
- show_help();
- } elsif ($args[0] eq 'check') {
- bg_do("check");
- } elsif ($args[0] eq 'update') {
- shift @args;
- bg_do("update ".join(' ', @args));
- } elsif ($args[0] eq 'search' && defined $args[1]) {
- shift @args;
- bg_do("search ".join(" ", @args));
- } elsif ($args[0] eq 'install' && defined $args[1]) {
- shift @args;
- bg_do("install ".join(' ', @args));
- } elsif ($args[0] eq 'contact' && defined $args[1]) {
- contact_author($args[1]);
- } elsif ($args[0] eq 'ratings' && defined $args[1]) {
- shift @args;
- bg_do("ratings ".join(' ', @args));
- } elsif ($args[0] eq 'rate' && defined $args[1] && defined $args[2]) {
- shift @args;
- bg_do("rate ".join(' ', @args)) if ($args[2] >= 0 && $args[2] < 6);
- } elsif ($args[0] eq 'info' && defined $args[1]) {
- shift @args;
- bg_do("info ".join(' ', @args));
- } elsif ($args[0] eq 'echo') {
- bg_do("echo");
- } elsif ($args[0] eq 'top') {
- my $number = defined $args[1] ? $args[1] : 10;
- bg_do("top ".$number);
- } elsif ($args[0] eq 'cpan' && defined $args[1]) {
- call_openurl('http://search.cpan.org/search?mode=module&query='.$args[1]);
- } elsif ($args[0] eq 'autorun' && defined $args[1]) {
- toggle_autorun($args[1]);
- } elsif ($args[0] eq 'new') {
- my $number = defined $args[1] ? $args[1] : 5;
- bg_do("new ".$number);
- }
-}
-
-sub sig_command_script_load ($$$) {
- my ($script, $server, $witem) = @_;
- no strict;
- $script = $2 if $script =~ /(.*\/)?(.*?)\.pl$/;
- if (defined %{ "Irssi::Script::${script}::" }) {
- if (defined &{ "Irssi::Script::${script}::pre_unload" }) {
- print CLIENTCRAP "%R>>%n Triggering pre_unload function of $script...";
- &{ "Irssi::Script::${script}::pre_unload" }();
- }
- }
-}
-
-sub sig_default_command ($$) {
- my ($cmd, $server) = @_;
- return unless Irssi::settings_get_bool("scriptassist_check_unknown_commands");
- bg_do('unknown '.$cmd);
-}
-
-sub sig_complete ($$$$$) {
- my ($list, $window, $word, $linestart, $want_space) = @_;
- return unless $linestart =~ /^.script(assist)? (install|rate|ratings|update|check|contact|info|autorun)/;
- my @newlist;
- my $str = $word;
- foreach (@complist) {
- if ($_ =~ /^(\Q$str\E.*)?$/) {
- push @newlist, $_;
- }
- }
- foreach (@{loaded_scripts()}) {
- push @newlist, $_ if /^(\Q$str\E.*)?$/;
- }
- $want_space = 0;
- push @$list, $_ foreach @newlist;
- Irssi::signal_stop();
-}
-
-
-Irssi::settings_add_str($IRSSI{name}, 'scriptassist_script_sources', 'http://scripts.irssi.org/scripts.dmp');
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_cache_sources', 1);
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_update_verbose', 1);
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_check_verbose', 1);
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_catch_script_errors', 1);
-
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_install_unsigned_scripts', 1);
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_use_gpg', 1);
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_integrate', 1);
-Irssi::settings_add_bool($IRSSI{name}, 'scriptassist_check_unknown_commands', 1);
-
-Irssi::signal_add_first("default command", \&sig_default_command);
-Irssi::signal_add_first('complete word', \&sig_complete);
-Irssi::signal_add_first('command script load', \&sig_command_script_load);
-Irssi::signal_add_first('command script unload', \&sig_command_script_load);
-
-if (defined &Irssi::signal_register) {
- Irssi::signal_register({ 'script error' => [ 'Irssi::Script', 'string' ] });
- Irssi::signal_add_last('script error', \&sig_script_error);
-}
-
-Irssi::command_bind('scriptassist', \&cmd_scripassist);
-
-Irssi::theme_register(['box_header', '%R,--[%n$*%R]%n',
-'box_inside', '%R|%n $*',
-'box_footer', '%R`--<%n$*%R>->%n',
-]);
-
-foreach my $cmd ( ( 'check', 'install', 'update', 'contact', 'search', '-h', 'help', 'ratings', 'rate', 'info', 'echo', 'top', 'cpan', 'autorun', 'new') ) {
- Irssi::command_bind('scriptassist '.$cmd => sub {
- cmd_scripassist("$cmd ".$_[0], $_[1], $_[2]); });
- if (Irssi::settings_get_bool('scriptassist_integrate')) {
- Irssi::command_bind('script '.$cmd => sub {
- cmd_scripassist("$cmd ".$_[0], $_[1], $_[2]); });
- }
-}
-
-print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /scriptassist help for help';
--- /dev/null
+#!/usr/bin/perl -w
+
+#<scriptinfo>
+use vars qw($VERSION %IRSSI);
+
+use Irssi 20020519;
+$VERSION = "0.3";
+%IRSSI = (
+ authors => "c0ffee",
+ contact => "c0ffee\@penguin-breeder.org",
+ name => "sign_messages from silc-plugin",
+ description => "introduces a setting sign_messages which automatically signs messages",
+ license => "Public Domain",
+ url => "http://www.penguin-breeder.org/?page=silc",
+ changed => "Wed Jan 29 20:55 CET 2003",
+);
+#</scriptinfo>
+
+sub sig_ownpub {
+ my ($server, $msg, $target) = @_;
+
+ if (($server->{chat_type} =~ /^silc$/i) &&
+ (Irssi::settings_get_bool("sign_messages"))) {
+
+ Irssi::signal_stop();
+ $server->command("SMSG -channel $target $msg");
+
+ }
+
+}
+
+sub sig_sendtext {
+ my ($line, $server, $witem) = @_;
+ return unless ref $witem;
+
+ if (($server->{chat_type} =~ /^silc$/i) &&
+ (Irssi::settings_get_bool("sign_messages"))) {
+
+ return if $line eq "";
+
+ if ($witem->{type} eq "CHANNEL") {
+ $target = "-channel $witem->{name}";
+ } elsif ($witem->{type} eq "QUERY") {
+ $target = "$witem->{name}";
+ } else {
+ return;
+ }
+
+ Irssi::signal_stop();
+ $server->command("SMSG $target $line");
+
+ }
+
+}
+
+Irssi::signal_add_first("send text", "sig_sendtext");
+Irssi::settings_add_bool("silc", "sign_messages", 0);
+++ /dev/null
-# /set splitlong_max_length
-# specifies the maximum length of a msg, automatically chosen when set to "0"
-# default: 0
-#
-# /set splitlong_line_start
-# /set splitlong_line_end
-# self-explanatory
-# defaults: "... ", " ..."
-###
-use strict;
-use vars qw($VERSION %IRSSI);
-
-use Irssi 20011001;
-
-$VERSION = "0.20";
-%IRSSI = (
- authors => "Bjoern \'fuchs\' Krombholz",
- contact => "bjkro\@gmx.de",
- name => "splitlong",
- licence => "Public Domain",
- description => "Split overlong PRIVMSGs to msgs with length allowed by ircd",
- changed => "Wed Jun 25 00:17:00 CET 2003",
- changes => "Actually the real 0.19 (now 0.20), but upload didn't work some month ago, target problem fixed..."
-);
-
-sub sig_command_msg {
- my ($cmd, $server, $winitem) = @_;
- my ( $param, $target,$data) = $cmd =~ /^(-\S*\s)?(\S*)\s(.*)/;
-
- my $maxlength = Irssi::settings_get_int('splitlong_max_length');
- my $lstart = Irssi::settings_get_str('splitlong_line_start');
- my $lend = Irssi::settings_get_str('splitlong_line_end');
-
- if ($maxlength == 0) {
- # 497 = 510 - length(":" . "!" . " PRIVMSG " . " :");
- $maxlength = 497 - length($server->{nick} . $server->{userhost} . $target);
- }
- my $maxlength2 = $maxlength - length($lend);
-
- if (length($data) > ($maxlength)) {
- my @spltarr;
-
- while (length($data) > ($maxlength2)) {
- my $pos = rindex($data, " ", $maxlength2);
- push @spltarr, substr($data, 0, ($pos < ($maxlength/10 + 4)) ? $maxlength2 : $pos) . $lend;
- $data = $lstart . substr($data, ($pos < ($maxlength/10 + 4)) ? $maxlength2 : $pos+1);
- }
-
- push @spltarr, $data;
- foreach (@spltarr) {
- Irssi::signal_emit("command msg", "$target $_", $server, $winitem);
- }
- Irssi::signal_stop();
- }
-}
-
-Irssi::settings_add_int('misc', 'splitlong_max_length', 0);
-Irssi::settings_add_str('misc', 'splitlong_line_start', "... ");
-Irssi::settings_add_str('misc', 'splitlong_line_end', " ...");
-Irssi::command_bind('msg', 'sig_command_msg');
+++ /dev/null
-use Irssi 20020101.0250 ();
-$VERSION = "1.16";
-%IRSSI = (
- authors => 'David Leadbeater, Timo Sirainen, Georg Lukas',
- contact => 'dgl@dgl.cx, tss@iki.fi, georg@boerde.de',
- name => 'usercount',
- description => 'Adds a usercount for a channel as a statusbar item',
- license => 'GNU GPLv2 or later',
- url => 'http://irssi.dgl.yi.org/',
-);
-
-# Once you have loaded this script run the following command:
-# /statusbar window add usercount
-# You can also add -alignment left|right option
-
-# /set usercount_show_zero on or off to show users when 0 users of that type
-# /set usercount_show_ircops (default off)
-# /set usercount_show_halfops (default on)
-
-# you can customize the look of this item from theme file:
-# sb_usercount = "{sb %_$0%_ nicks ($1-)}";
-# sb_uc_ircops = "%_*%_$*";
-# sb_uc_ops = "%_@%_$*";
-# sb_uc_halfops = "%_%%%_$*";
-# sb_uc_voices = "%_+%_$*";
-# sb_uc_normal = "$*";
-# sb_uc_space = " ";
-
-
-use strict;
-use Irssi::TextUI;
-
-my ($ircops, $ops, $halfops, $voices, $normal, $total);
-my ($timeout_tag, $recalc);
-
-# Called to make the status bar item
-sub usercount {
- my ($item, $get_size_only) = @_;
- my $wi = !Irssi::active_win() ? undef : Irssi::active_win()->{active};
-
- if(!ref $wi || $wi->{type} ne "CHANNEL") { # only works on channels
- return unless ref $item;
- $item->{min_size} = $item->{max_size} = 0;
- return;
- }
-
- if ($recalc) {
- $recalc = 0;
- calc_users($wi);
- }
-
- my $theme = Irssi::current_theme();
- my $format = $theme->format_expand("{sb_usercount}");
- if ($format) {
- # use theme-specific look
- my $ircopstr = $theme->format_expand("{sb_uc_ircops $ircops}",
- Irssi::EXPAND_FLAG_IGNORE_EMPTY);
- my $opstr = $theme->format_expand("{sb_uc_ops $ops}",
- Irssi::EXPAND_FLAG_IGNORE_EMPTY);
- my $halfopstr = $theme->format_expand("{sb_uc_halfops $halfops}",
- Irssi::EXPAND_FLAG_IGNORE_EMPTY);
- my $voicestr = $theme->format_expand("{sb_uc_voices $voices}",
- Irssi::EXPAND_FLAG_IGNORE_EMPTY);
- my $normalstr = $theme->format_expand("{sb_uc_normal $normal}",
- Irssi::EXPAND_FLAG_IGNORE_EMPTY);
- my $space = $theme->format_expand('{sb_uc_space}',
- Irssi::EXPAND_FLAG_IGNORE_EMPTY);
- $space = " " unless $space;
-
- my $str = "";
- $str .= $ircopstr.$space if defined $ircops;
- $str .= $opstr.$space if defined $ops;
- $str .= $halfopstr.$space if defined $halfops;
- $str .= $voicestr.$space if defined $voices;
- $str .= $normalstr.$space if defined $normal;
- $str =~ s/\Q$space\E$//;
-
- $format = $theme->format_expand("{sb_usercount $total $str}",
- Irssi::EXPAND_FLAG_IGNORE_REPLACES);
- } else {
- # use the default look
- $format = "{sb \%_$total\%_ nicks \%c(\%n";
- $format .= '*'.$ircops.' ' if (defined $ircops);
- $format .= '@'.$ops.' ' if (defined $ops);
- $format .= '%%'.$halfops.' ' if (defined $halfops);
- $format .= "+$voices " if (defined $voices);
- $format .= "$normal " if (defined $normal);
- $format =~ s/ $//;
- $format .= "\%c)}";
- }
-
- $item->default_handler($get_size_only, $format, undef, 1);
-}
-
-sub calc_users() {
- my $channel = shift;
- my $server = $channel->{server};
-
- $ircops = $ops = $halfops = $voices = $normal = 0;
- for ($channel->nicks()) {
- if ($_->{serverop}) {
- $ircops++;
- }
-
- if ($_->{op}) {
- $ops++;
- } elsif ($_->{halfop}) {
- $halfops++;
- } elsif ($_->{voice}) {
- $voices++;
- } else {
- $normal++;
- }
- }
-
- $total = $ops+$halfops+$voices+$normal;
- if (!Irssi::settings_get_bool('usercount_show_zero')) {
- $ircops = undef if ($ircops == 0);
- $ops = undef if ($ops == 0);
- $halfops = undef if ($halfops == 0);
- $voices = undef if ($voices == 0);
- $normal = undef if ($normal == 0);
- }
- $halfops = undef unless Irssi::settings_get_bool('usercount_show_halfops');
- $ircops = undef unless Irssi::settings_get_bool('usercount_show_ircops');
-}
-
-sub refresh {
- if ($timeout_tag > 0) {
- Irssi::timeout_remove($timeout_tag);
- $timeout_tag = 0;
- }
- Irssi::statusbar_items_redraw('usercount');
-}
-
-sub refresh_check {
- my $channel = shift;
- my $wi = ref Irssi::active_win() ? Irssi::active_win()->{active} : 0;
-
- return unless ref $wi && ref $channel;
- return if $wi->{name} ne $channel->{name};
- return if $wi->{server}->{tag} ne $channel->{server}->{tag};
-
- # don't refresh immediately, or we'll end up refreshing
- # a lot around netsplits
- $recalc = 1;
- Irssi::timeout_remove($timeout_tag) if ($timeout_tag > 0);
- $timeout_tag = Irssi::timeout_add(500, 'refresh', undef);
-}
-
-sub refresh_recalc {
- $recalc = 1;
- refresh();
-}
-
-$recalc = 1;
-$timeout_tag = 0;
-
-Irssi::settings_add_bool('usercount', 'usercount_show_zero', 1);
-Irssi::settings_add_bool('usercount', 'usercount_show_ircops', 0);
-Irssi::settings_add_bool('usercount', 'usercount_show_halfops', 1);
-
-Irssi::statusbar_item_register('usercount', undef, 'usercount');
-Irssi::statusbars_recreate_items();
-
-Irssi::signal_add_last('nicklist new', 'refresh_check');
-Irssi::signal_add_last('nicklist remove', 'refresh_check');
-Irssi::signal_add_last('nick mode changed', 'refresh_check');
-Irssi::signal_add_last('setup changed', 'refresh_recalc');
-Irssi::signal_add_last('window changed', 'refresh_recalc');
-Irssi::signal_add_last('window item changed', 'refresh_recalc');
-
# You can set the default cipher, hash function and HMAC to be used
# as setting as well. You can set it here or use the /SET command.
#
-# /set crypto_default_cipher
-# /set crypto_default_hash
-# /set crypto_default_hmac
-#
# Available ciphers are (default: aes-256-cbc):
#
-# aes-256-ctr, aes-192-ctr, aes-128-ctr,
# aes-256-cbc, aes-192-cbc, aes-128-cbc,
# twofish-256-cbc, twofish-192-cbc, twofish-128-cbc,
# cast-256-cbc, cast-192-cbc and cast-128-cbc
#
-# Available hash functions are (default: sha1):
+# Available hash functions are (default: sha256):
#
# sha256, sha1 and md5
#
-# Available HMAC's are (default: hmac-sha1-96):
+# Available HMAC's are (default: hmac-sha256-96):
#
-# hmac-sha1-96, hmac-md5-96, hmac-sha1 and hmac-md5
+# hmac-sha256-96, hmac-sha1-96, hmac-md5-96, hmac-sha1 and hmac-md5
#
settings = {
+ "server" = {
+ crypto_default_cipher = "aes-256-cbc";
+ crypto_default_hash = "sha1";
+ crypto_default_hmac = "hmac-sha1-96";
+ };
"fe-common/core" = {
autocreate_own_query = "yes";
use_status_window = "no";
PERLDIR=perl
endif
-pkginc_srcdir=$(pkgincludedir)/src
-pkginc_src_HEADERS = \
- common.h
noinst_HEADERS = \
common.h
#include "config.h"
#endif
-#ifndef PACKAGE
-#define PACKAGE "SILC Client"
-#endif /* PACKAGE */
-
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
# include <gmodule.h>
#endif
-#ifdef USE_GC
-# define g_free(x) G_STMT_START { (x) = NULL; } G_STMT_END
-#endif
-
#if defined (UOFF_T_INT)
typedef unsigned int uoff_t;
#elif defined (UOFF_T_LONG)
typedef unsigned long uoff_t;
-#elif defined (UOFF_T_LONG_LONG)
+#elif defined (UOFF_T_LONGLONG)
typedef unsigned long long uoff_t;
#else
-# error uoff_t size not set
+typedef unsigned int uoff_t;
#endif
/* input functions */
pidwait.c \
queries.c \
rawlog.c \
- recode.c \
servers.c \
servers-reconnect.c \
servers-setup.c \
pidwait.h \
queries.h \
rawlog.h \
- recode.h \
servers.h \
servers-reconnect.h \
servers-setup.h \
g_free_not_null(channel->key);
g_free(channel->mode);
g_free(channel->name);
- g_free(channel->visible_name);
channel->type = 0;
g_free(channel);
static int match_nick_flags(SERVER_REC *server, NICK_REC *nick, char flag)
{
- const char *flags = server->get_nick_flags(server);
+ const char *flags = server->get_nick_flags();
return strchr(flags, flag) == NULL ||
(flag == flags[0] && nick->op) ||
continue;
nick = nicklist_find_mask(channel,
- channel->server->isnickflag(channel->server, *botnick) ?
+ channel->server->isnickflag(*botnick) ?
botnick+1 : botnick);
if (nick != NULL &&
match_nick_flags(channel->server, nick, *botnick)) {
#include "commands.h"
#include "special-vars.h"
#include "settings.h"
-#include "recode.h"
#include "chat-protocols.h"
#include "servers.h"
CHAT_PROTOCOL_REC *proto;
SERVER_CONNECT_REC *conn;
GHashTable *optlist;
- char *addr, *portstr, *password, *nick, *chatnet, *host, *tmp;
+ char *addr, *portstr, *password, *nick, *chatnet, *host;
void *free_arg;
g_return_val_if_fail(data != NULL, NULL);
/* connect to server */
chatnet = proto == NULL ? NULL :
g_hash_table_lookup(optlist, proto->chatnet);
-
- if (chatnet == NULL)
- chatnet = g_hash_table_lookup(optlist, "network");
-
conn = server_create_conn(proto != NULL ? proto->id : -1, addr,
atoi(portstr), chatnet, password, nick);
if (proto == NULL)
else if (g_hash_table_lookup(optlist, "4") != NULL)
conn->family = AF_INET;
- if (g_hash_table_lookup(optlist, "ssl") != NULL)
- conn->use_ssl = TRUE;
- if ((tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL)
- conn->ssl_cert = g_strdup(tmp);
- if ((tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL)
- conn->ssl_pkey = g_strdup(tmp);
- if (g_hash_table_lookup(optlist, "ssl_verify") != NULL)
- conn->ssl_verify = TRUE;
- if ((tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL)
- conn->ssl_cafile = g_strdup(tmp);
- if ((tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL)
- conn->ssl_capath = g_strdup(tmp);
- if ((conn->ssl_capath != NULL && conn->ssl_capath[0] != '\0')
- || (conn->ssl_cafile != NULL && conn->ssl_cafile[0] != '\0'))
- conn->ssl_verify = TRUE;
- if ((conn->ssl_cert != NULL && conn->ssl_cert[0] != '\0') || conn->ssl_verify)
+ if(g_hash_table_lookup(optlist, "ssl") != NULL)
conn->use_ssl = TRUE;
if (g_hash_table_lookup(optlist, "!") != NULL)
return conn;
}
-/* SYNTAX: CONNECT [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>]
- [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
- [-noproxy] [-network <network>] [-host <hostname>]
- [-rawlog <file>]
- <address>|<chatnet> [<port> [<password> [<nick>]]] */
-/* NOTE: -network replaces the old -ircnet flag. */
+/* SYNTAX: CONNECT [-4 | -6] [-ssl] [-noproxy] [-silcnet <silcnet>]
+ [-host <hostname>] [-rawlog <file>]
+ <address>|<chatnet> [<port> [<password> [<nick>]]] */
static void cmd_connect(const char *data)
{
SERVER_CONNECT_REC *conn;
signal_emit("command server connect", 3, data, server, item);
}
-/* SYNTAX: SERVER [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>]
- [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
- [-noproxy] [-network <network>] [-host <hostname>]
- [-rawlog <file>]
+/* SYNTAX: SERVER [-4 | -6] [-ssl] [-noproxy] [-silcnet <silcnet>]
+ [-host <hostname>] [-rawlog <file>]
[+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
-/* NOTE: -network replaces the old -ircnet flag. */
static void cmd_server_connect(const char *data, SERVER_REC *server)
{
SERVER_CONNECT_REC *conn;
signal_emit("gui exit", 0);
}
-/* SYNTAX: JOIN [-invite] [-<server tag>] <channels> [<keys>] */
static void cmd_join(const char *data, SERVER_REC *server)
{
GHashTable *optlist;
cmd_params_free(free_arg);
}
-/* SYNTAX: MSG [-<server tag>] [-channel | -nick] <targets> <message> */
+/* SYNTAX: MSG [-channel] <target> <message> */
static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
{
GHashTable *optlist;
- char *target, *origtarget, *msg, *recoded;
+ char *target, *origtarget, *msg;
void *free_arg;
- int free_ret, target_type = SEND_TARGET_NICK;
+ int free_ret, target_type;
g_return_if_fail(data != NULL);
if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0) {
target = parse_special(&target, server, item,
NULL, &free_ret, NULL, 0);
- if (target != NULL && *target == '\0') {
- if (free_ret)
- g_free(target);
+ if (target != NULL && *target == '\0')
target = NULL;
- free_ret = FALSE;
- }
}
- if (target != NULL) {
- if (strcmp(target, "*") == 0) {
- /* send to active channel/query */
- if (item == NULL)
- cmd_param_error(CMDERR_NOT_JOINED);
-
- target_type = IS_CHANNEL(item) ?
- SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
- target = (char *) window_item_get_target(item);
- } else if (g_hash_table_lookup(optlist, "channel") != NULL)
- target_type = SEND_TARGET_CHANNEL;
- else if (g_hash_table_lookup(optlist, "nick") != NULL)
- target_type = SEND_TARGET_NICK;
- else {
- /* Need to rely on server_ischannel(). If the protocol
- doesn't really know if it's channel or nick based on
- the name, it should just assume it's nick, because
- when typing text to channels it's always sent with
- /MSG -channel. */
- target_type = server_ischannel(server, target) ?
- SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
- }
- }
- recoded = recode_out(server, msg, target);
- if (target != NULL) {
- signal_emit("server sendmsg", 4, server, target, recoded,
- GINT_TO_POINTER(target_type));
+ if (strcmp(target, "*") == 0) {
+ /* send to active channel/query */
+ if (item == NULL)
+ cmd_param_error(CMDERR_NOT_JOINED);
+
+ target_type = IS_CHANNEL(item) ?
+ SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
+ target = (char *) window_item_get_target(item);
+ } else if (g_hash_table_lookup(optlist, "channel") != NULL)
+ target_type = SEND_TARGET_CHANNEL;
+ else if (g_hash_table_lookup(optlist, "nick") != NULL)
+ target_type = SEND_TARGET_NICK;
+ else {
+ /* Need to rely on server_ischannel(). If the protocol
+ doesn't really know if it's channel or nick based on the
+ name, it should just assume it's nick, because when typing
+ text to channels it's always sent with /MSG -channel. */
+ target_type = server_ischannel(server, target) ?
+ SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
}
+
+ if (target != NULL)
+ server->send_message(server, target, msg, target_type);
+
signal_emit(target != NULL && target_type == SEND_TARGET_CHANNEL ?
"message own_public" : "message own_private", 4,
- server, recoded, target, origtarget);
-
- g_free(recoded);
+ server, msg, target, origtarget);
+
if (free_ret && target != NULL) g_free(target);
cmd_params_free(free_arg);
}
-static void sig_server_sendmsg(SERVER_REC *server, const char *target,
- const char *msg, void *target_type_p)
-{
- server->send_message(server, target, msg,
- GPOINTER_TO_INT(target_type_p));
-}
-
static void cmd_foreach(const char *data, SERVER_REC *server,
WI_ITEM_REC *item)
{
command_bind("foreach channel", NULL, (SIGNAL_FUNC) cmd_foreach_channel);
command_bind("foreach query", NULL, (SIGNAL_FUNC) cmd_foreach_query);
- signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
- signal_add("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
+ signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
- command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey ssl_verify +ssl_cafile +ssl_capath +host noproxy -rawlog");
+ command_set_options("connect", "4 6 !! ssl +host noproxy -rawlog");
command_set_options("join", "invite");
command_set_options("msg", "channel nick");
}
command_unbind("foreach query", (SIGNAL_FUNC) cmd_foreach_query);
signal_remove("default command server", (SIGNAL_FUNC) sig_default_command_server);
- signal_remove("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
}
g_return_if_fail(IS_SERVER(server));
- if (server->connrec->chatnet == NULL || server->session_reconnect ||
- server->connrec->no_autojoin_channels)
+ if (server->connrec->chatnet == NULL || server->session_reconnect)
return;
rec = chatnet_find(server->connrec->chatnet);
if (cb->func == func) {
rec->callbacks =
g_slist_remove(rec->callbacks, cb);
- g_free(cb);
return rec;
}
}
}
(*data)++;
- if (**data == '-' && (*data)[1] == ' ') {
+ if (**data == '-' && i_isspace((*data)[1])) {
/* -- option means end of options even
if next word starts with - */
(*data)++;
- while (**data == ' ') (*data)++;
+ while (i_isspace(**data)) (*data)++;
break;
}
if (**data == '\0')
option = "-";
- else if (**data != ' ')
+ else if (!i_isspace(**data))
option = cmd_get_param(data);
else {
option = "-";
*optlist[pos] == '!')
option = NULL;
- while (**data == ' ') (*data)++;
+ while (i_isspace(**data)) (*data)++;
continue;
}
}
option = NULL;
- while (**data == ' ') (*data)++;
+ while (i_isspace(**data)) (*data)++;
}
return 0;
parse_command(line, expand_aliases, server, item);
}
-static int eval_recursion_depth=0;
/* SYNTAX: EVAL <command(s)> */
static void cmd_eval(const char *data, SERVER_REC *server, void *item)
{
g_return_if_fail(data != NULL);
- if (eval_recursion_depth > 100)
- cmd_return_error(CMDERR_EVAL_MAX_RECURSE);
-
- eval_recursion_depth++;
eval_special_string(data, "", server, item);
- eval_recursion_depth--;
}
/* SYNTAX: CD <directory> */
CMDERR_CHAN_NOT_FOUND, /* channel not found */
CMDERR_CHAN_NOT_SYNCED, /* channel not fully synchronized yet */
CMDERR_ILLEGAL_PROTO, /* requires different chat protocol than the active server */
- CMDERR_NOT_GOOD_IDEA, /* not good idea to do, -yes overrides this */
- CMDERR_INVALID_TIME, /* invalid time specification */
- CMDERR_INVALID_CHARSET, /* invalid charset specification */
- CMDERR_EVAL_MAX_RECURSE, /* eval hit recursion limit */
- CMDERR_PROGRAM_NOT_FOUND /* program not found */
+ CMDERR_NOT_GOOD_IDEA /* not good idea to do, -yes overrides this */
};
/* Return the full command for `alias' */
#include "log.h"
#include "rawlog.h"
#include "ignore.h"
-#include "recode.h"
#include "channels.h"
#include "queries.h"
int irssi_gui;
int irssi_init_finished;
int reload_config;
-time_t client_start_time;
static char *irssi_dir, *irssi_config_file;
static GSList *dialog_type_queue, *dialog_text_queue;
void core_init_paths(int argc, char *argv[])
{
static struct poptOption options[] = {
- { "config", 0, POPT_ARG_STRING, NULL, 0, "Configuration file location (~/.irssi/config)", "PATH" },
- { "home", 0, POPT_ARG_STRING, NULL, 0, "Irssi home dir location (~/.irssi)", "PATH" },
+ { "config", 0, POPT_ARG_STRING, NULL, 0, "Configuration file location (~/.silc/config)", "PATH" },
+ { "home", 0, POPT_ARG_STRING, NULL, 0, "Irssi home dir location (~/.silc)", "PATH" },
{ NULL, '\0', 0, NULL }
};
const char *home;
{
dialog_type_queue = NULL;
dialog_text_queue = NULL;
- client_start_time = time(NULL);
modules_init();
#ifndef WIN32
log_init();
log_away_init();
rawlog_init();
- recode_init();
channels_init();
queries_init();
chat_commands_init();
settings_add_str("misc", "ignore_signals", "");
- settings_add_bool("misc", "override_coredump_limit", FALSE);
+ settings_add_bool("misc", "override_coredump_limit", TRUE);
#ifdef HAVE_SYS_RESOURCE_H
getrlimit(RLIMIT_CORE, &orig_core_rlimit);
queries_deinit();
channels_deinit();
- recode_deinit();
rawlog_deinit();
log_away_deinit();
log_deinit();
#ifndef __IRSSI_CORE_H
#define __IRSSI_CORE_H
-#include "common.h"
-
/* for determining what GUI is currently in use: */
#define IRSSI_GUI_NONE 0
#define IRSSI_GUI_TEXT 1
extern int irssi_gui;
extern int irssi_init_finished; /* TRUE after "irssi init finished" signal is sent */
extern int reload_config; /* TRUE after received SIGHUP. */
-extern time_t client_start_time;
void core_init_paths(int argc, char *argv[]);
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "core.h"
#include "module.h"
#include "modules.h"
#include "signals.h"
static EXPANDO_REC *char_expandos[255];
static GHashTable *expandos;
+static time_t client_start_time;
static char *last_sent_msg, *last_sent_msg_body;
static char *last_privmsg_from, *last_public_from;
static char *sysname, *sysrelease, *sysarch;
/* Destroy expando */
void expando_destroy(const char *key, EXPANDO_FUNC func)
{
- gpointer origkey, value;
+ gpointer origkey;
EXPANDO_REC *rec;
g_return_if_fail(key != NULL || *key == '\0');
char_expandos[(int) (unsigned char) *key] = NULL;
g_free(rec);
}
- } else if (g_hash_table_lookup_extended(expandos, key,
- &origkey, &value)) {
- rec = value;
+ } else if (g_hash_table_lookup_extended(expandos, key, &origkey,
+ (gpointer *) &rec)) {
if (rec->func == func) {
g_hash_table_remove(expandos, key);
g_free(origkey);
return rec == NULL ? NULL : rec->func;
}
-static gboolean free_expando(gpointer key, gpointer value, gpointer user_data)
-{
- g_free(key);
- g_free(value);
- return TRUE;
-}
-
/* last person who sent you a MSG */
static char *expando_lastmsg(SERVER_REC *server, void *item, int *free_ret)
{
/* modes of current channel, if any */
static char *expando_chanmode(SERVER_REC *server, void *item, int *free_ret)
-{
- char *cmode;
-
- *free_ret = FALSE;
-
- if (!IS_CHANNEL(item))
- return NULL;
-
- if (!settings_get_bool("chanmode_expando_strip"))
- return CHANNEL(item)->mode;
-
- *free_ret = TRUE;
- cmode = g_strdup(CHANNEL(item)->mode);
- if (strchr(cmode, ' ') != NULL)
- *(strchr(cmode, ' ')) = 0;
-
- return cmode;
+{
+ return !IS_CHANNEL(item) ? NULL : CHANNEL(item)->mode;
}
/* current nickname */
#endif
settings_add_str("misc", "STATUS_OPER", "*");
settings_add_str("lookandfeel", "timestamp_format", "%H:%M");
- settings_add_bool("lookandfeel", "chanmode_expando_strip", FALSE);
+ client_start_time = time(NULL);
last_sent_msg = NULL; last_sent_msg_body = NULL;
last_privmsg_from = NULL; last_public_from = NULL;
last_timestamp = 0;
for (n = 0; n < sizeof(char_expandos)/sizeof(char_expandos[0]); n++)
g_free_not_null(char_expandos[n]);
- g_hash_table_foreach_remove(expandos, free_expando, NULL);
+ expando_destroy("sysname", expando_sysname);
+ expando_destroy("sysrelease", expando_sysrelease);
+ expando_destroy("sysarch", expando_sysarch);
+ expando_destroy("topic", expando_topic);
+ expando_destroy("tag", expando_servertag);
+ expando_destroy("chatnet", expando_chatnet);
+
g_hash_table_destroy(expandos);
g_free_not_null(last_sent_msg); g_free_not_null(last_sent_msg_body);
int line_split(const char *data, int len, char **output, LINEBUF_REC **buffer)
{
LINEBUF_REC *rec;
- int ret;
g_return_val_if_fail(data != NULL, -1);
g_return_val_if_fail(output != NULL, -1);
}
}
- ret = remove_newline(rec);
*output = rec->str;
- return ret;
+ return remove_newline(rec);
}
void line_split_free(LINEBUF_REC *buffer)
static void awaylog_open(void)
{
- const char *fname;
+ const char *fname, *levelstr;
LOG_REC *log;
int level;
fname = settings_get_str("awaylog_file");
- level = settings_get_level("awaylog_level");
- if (*fname == '\0' || level == 0) return;
+ levelstr = settings_get_str("awaylog_level");
+ if (*fname == '\0' || *levelstr == '\0') return;
+
+ level = level2bits(levelstr);
+ if (level == 0) return;
log = log_find(fname);
if (log != NULL && log->handle != -1)
void log_away_init(void)
{
- char *awaylog_file;
-
awaylog = NULL;
away_filepos = 0;
away_msgs = 0;
- awaylog_file = g_strconcat(get_irssi_dir(), "/away.log", NULL);
- settings_add_str("log", "awaylog_file", awaylog_file);
- g_free(awaylog_file);
- settings_add_level("log", "awaylog_level", "msgs hilight");
+ settings_add_str("log", "awaylog_file", IRSSI_DIR_SHORT"/away.log");
+ settings_add_str("log", "awaylog_level", "msgs hilight");
signal_add("log written", (SIGNAL_FUNC) sig_log_written);
signal_add("away mode changed", (SIGNAL_FUNC) sig_away_changed);
g_free_not_null(colorstr);
}
-static int itemcmp(const char *patt, const char *item)
-{
- /* returns 0 on match, nonzero otherwise */
-
- if (item == NULL)
- return g_strcasecmp(patt, "*") != 0;
- if (*patt == '*')
- return 0;
- return g_strcasecmp(patt, item);
-}
-
LOG_ITEM_REC *log_item_find(LOG_REC *log, int type, const char *item,
const char *servertag)
{
GSList *tmp;
g_return_val_if_fail(log != NULL, NULL);
+ g_return_val_if_fail(item != NULL, NULL);
for (tmp = log->items; tmp != NULL; tmp = tmp->next) {
LOG_ITEM_REC *rec = tmp->data;
- if (rec->type == type && itemcmp(rec->name, item) == 0 &&
+ if (rec->type == type && g_strcasecmp(rec->name, item) == 0 &&
(rec->servertag == NULL || (servertag != NULL &&
g_strcasecmp(rec->servertag, servertag) == 0)))
return rec;
return -1;
}
+int execute(const char *cmd)
+{
+ char **args;
+#ifndef WIN32
+ int pid;
+#endif
+
+ g_return_val_if_fail(cmd != NULL, -1);
+
+#ifndef WIN32
+ pid = fork();
+ if (pid == -1) return FALSE;
+ if (pid != 0) {
+ pidwait_add(pid);
+ return pid;
+ }
+
+ args = g_strsplit(cmd, " ", -1);
+ execvp(args[0], args);
+ g_strfreev(args);
+
+ _exit(99);
+ return -1;
+#else
+ args = g_strsplit(cmd, " ", -1);
+ _spawnvp(_P_DETACH, args[0], args);
+ g_strfreev(args);
+ return 0;
+#endif
+}
+
GSList *gslist_find_string(GSList *list, const char *key)
{
for (list = list; list != NULL; list = list->next)
return ret;
}
-
-int strocpy(char *dest, const char *src, size_t dstsize)
-{
- if (dstsize == 0)
- return -1;
-
- while (*src != '\0' && dstsize > 1) {
- *dest++ = *src++;
- dstsize--;
- }
-
- *dest++ = '\0';
- return *src == '\0' ? 0 : -1;
-}
-
-int nearest_power(int num)
-{
- int n = 1;
-
- while (n < num) n <<= 1;
- return n;
-}
-
-int parse_time_interval(const char *time, int *msecs)
-{
- const char *desc;
- int number, sign, len, ret;
-
- *msecs = 0;
-
- /* max. return value is around 24 days */
- number = 0; sign = 1; ret = TRUE;
- for (;;) {
- if (*time == '-') {
- sign = -sign;
- time++;
- continue;
- }
-
- if (i_isdigit(*time)) {
- number = number*10 + (*time - '0');
- time++;
- continue;
- }
-
- /* skip punctuation */
- while (*time != '\0' && i_ispunct(*time))
- time++;
-
- /* get description */
- for (len = 0, desc = time; i_isalpha(*time); time++)
- len++;
-
- if (len == 0) {
- *msecs += number * 1000; /* assume seconds */
- *msecs *= sign;
- return TRUE;
- }
-
- if (g_strncasecmp(desc, "days", len) == 0) {
- if (number > 24) {
- /* would overflow */
- return FALSE;
- }
- *msecs += number * 1000*3600*24;
- } else if (g_strncasecmp(desc, "hours", len) == 0)
- *msecs += number * 1000*3600;
- else if (g_strncasecmp(desc, "minutes", len) == 0 ||
- g_strncasecmp(desc, "mins", len) == 0)
- *msecs += number * 1000*60;
- else if (g_strncasecmp(desc, "seconds", len) == 0 ||
- g_strncasecmp(desc, "secs", len) == 0)
- *msecs += number * 1000;
- else if (g_strncasecmp(desc, "milliseconds", len) == 0 ||
- g_strncasecmp(desc, "millisecs", len) == 0 ||
- g_strncasecmp(desc, "mseconds", len) == 0 ||
- g_strncasecmp(desc, "msecs", len) == 0)
- *msecs += number;
- else {
- ret = FALSE;
- }
-
- /* skip punctuation */
- while (*time != '\0' && i_ispunct(*time))
- time++;
-
- if (*time == '\0')
- break;
-
- number = 0;
- }
-
- *msecs *= sign;
- return ret;
-}
-
-int parse_size(const char *size, int *bytes)
-{
- const char *desc;
- int number, len;
-
- *bytes = 0;
-
- /* max. return value is about 1.6 years */
- number = 0;
- while (*size != '\0') {
- if (i_isdigit(*size)) {
- number = number*10 + (*size - '0');
- size++;
- continue;
- }
-
- /* skip punctuation */
- while (*size != '\0' && i_ispunct(*size))
- size++;
-
- /* get description */
- for (len = 0, desc = size; i_isalpha(*size); size++)
- len++;
-
- if (len == 0) {
- if (number == 0) {
- /* "0" - allow it */
- return TRUE;
- }
-
- *bytes += number*1024; /* assume kilobytes */
- return FALSE;
- }
-
- if (g_strncasecmp(desc, "gbytes", len) == 0)
- *bytes += number * 1024*1024*1024;
- if (g_strncasecmp(desc, "mbytes", len) == 0)
- *bytes += number * 1024*1024;
- if (g_strncasecmp(desc, "kbytes", len) == 0)
- *bytes += number * 1024;
- if (g_strncasecmp(desc, "bytes", len) == 0)
- *bytes += number;
-
- /* skip punctuation */
- while (*size != '\0' && i_ispunct(*size))
- size++;
- }
-
- return TRUE;
-}
typedef void* (*FOREACH_FIND_FUNC) (void *item, void *data);
typedef int (*COLUMN_LEN_FUNC)(void *data);
+static inline int nearest_power(int num)
+{
+ int n = 1;
+
+ while (n < num) n <<= 1;
+ return n;
+}
+
/* Returns 1 if tv1 > tv2, -1 if tv2 > tv1 or 0 if they're equal. */
int g_timeval_cmp(const GTimeVal *tv1, const GTimeVal *tv2);
/* Returns "tv1 - tv2", returns the result in milliseconds. Note that
/* return index of `item' in `array' or -1 if not found */
int strarray_find(char **array, const char *item);
+int execute(const char *cmd); /* returns pid or -1 = error */
+
GSList *gslist_find_string(GSList *list, const char *key);
GSList *gslist_find_icase_string(GSList *list, const char *key);
GList *glist_find_string(GList *list, const char *key);
/* Escape all '"', "'" and '\' chars with '\' */
char *escape_string(const char *str);
-/* Like strlcpy(), but return -1 if buffer was overflown, 0 if not. */
-int strocpy(char *dest, const char *src, size_t dstsize);
-
-int nearest_power(int num);
-
-/* Returns TRUE / FALSE */
-int parse_time_interval(const char *time, int *msecs);
-int parse_size(const char *size, int *bytes);
-
#endif
GModule *gmodule;
MODULE_REC *module;
MODULE_FILE_REC *rec;
- gpointer value1, value2;
char *initfunc, *deinitfunc;
int found;
/* get the module's init() and deinit() functions */
initfunc = module_get_func(rootmodule, submodule, "init");
deinitfunc = module_get_func(rootmodule, submodule, "deinit");
- found = g_module_symbol(gmodule, initfunc, &value1) &&
- g_module_symbol(gmodule, deinitfunc, &value2);
+ found = g_module_symbol(gmodule, initfunc, (gpointer *) &module_init) &&
+ g_module_symbol(gmodule, deinitfunc, (gpointer *) &module_deinit);
g_free(initfunc);
g_free(deinitfunc);
- module_init = value1;
- module_deinit = value2;
-
if (!found) {
module_error(MODULE_ERROR_INVALID, NULL,
rootmodule, submodule);
void module_uniq_destroy(const char *module)
{
GHashTable *idlist;
- gpointer key, value;
-
- if (g_hash_table_lookup_extended(idlookup, module, &key, &value)) {
- idlist = value;
+ gpointer key;
+ if (g_hash_table_lookup_extended(idlookup, module, &key,
+ (gpointer *) &idlist)) {
g_hash_table_remove(idlookup, key);
g_free(key);
g_hash_table_destroy(idlist);
}
- if (g_hash_table_lookup_extended(stridlookup, module, &key, &value)) {
- idlist = value;
-
+ if (g_hash_table_lookup_extended(stridlookup, module, &key,
+ (gpointer *) &idlist)) {
g_hash_table_remove(stridlookup, key);
g_free(key);
static int g_io_channel_write_block(GIOChannel *channel, void *data, int len)
{
- gsize ret;
+ unsigned int ret;
int err, sent;
sent = 0;
static int g_io_channel_read_block(GIOChannel *channel, void *data, int len)
{
time_t maxwait;
- gsize ret;
+ unsigned int ret;
int err, received;
maxwait = time(NULL)+2;
#endif
/* child */
- srand(time(NULL));
-
memset(&rec, 0, sizeof(rec));
rec.error = net_gethostbyname(addr, &rec.ip4, &rec.ip6);
if (rec.error == 0) {
#include "network.h"
#include "net-sendbuffer.h"
+struct _NET_SENDBUF_REC {
+ GIOChannel *handle;
+
+ int send_tag;
+ int bufsize;
+ int bufpos;
+ char *buffer; /* Buffer is NULL until it's actually needed. */
+};
+
static GSList *buffers;
/* Create new buffer - if `bufsize' is zero or less, DEFAULT_BUFFER_SIZE
#define DEFAULT_BUFFER_SIZE 8192
-struct _NET_SENDBUF_REC {
- GIOChannel *handle;
-
- int send_tag;
- int bufsize;
- int bufpos;
- char *buffer; /* Buffer is NULL until it's actually needed. */
-};
-
/* Create new buffer - if `bufsize' is zero or less, DEFAULT_BUFFER_SIZE
is used */
NET_SENDBUF_REC *net_sendbuffer_create(GIOChannel *handle, int bufsize);
#include "module.h"
#include "network.h"
-#include "misc.h"
#ifdef HAVE_OPENSSL
gint fd;
GIOChannel *giochan;
SSL *ssl;
- SSL_CTX *ctx;
- unsigned int got_cert:1;
- unsigned int verify:1;
+ X509 *cert;
} GIOSSLChannel;
-static SSL_CTX *ssl_ctx = NULL;
-
static void irssi_ssl_free(GIOChannel *handle)
{
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
g_io_channel_unref(chan->giochan);
SSL_free(chan->ssl);
- if (chan->ctx != ssl_ctx)
- SSL_CTX_free(chan->ctx);
g_free(chan);
}
-static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, X509 *cert)
-{
- if (SSL_get_verify_result(ssl) != X509_V_OK) {
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int n;
- char *str;
-
- g_warning("Could not verify SSL servers certificate:");
- if ((str = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) == NULL)
- g_warning(" Could not get subject-name from peer certificate");
- else {
- g_warning(" Subject : %s", str);
- free(str);
- }
- if ((str = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) == NULL)
- g_warning(" Could not get issuer-name from peer certificate");
- else {
- g_warning(" Issuer : %s", str);
- free(str);
- }
- if (! X509_digest(cert, EVP_md5(), md, &n))
- g_warning(" Could not get fingerprint from peer certificate");
- else {
- char hex[] = "0123456789ABCDEF";
- char fp[EVP_MAX_MD_SIZE*3];
- if (n < sizeof(fp)) {
- unsigned int i;
- for (i = 0; i < n; i++) {
- fp[i*3+0] = hex[(md[i] >> 4) & 0xF];
- fp[i*3+1] = hex[(md[i] >> 0) & 0xF];
- fp[i*3+2] = i == n - 1 ? '\0' : ':';
- }
- g_warning(" MD5 Fingerprint : %s", fp);
- }
- }
- return FALSE;
- }
- return TRUE;
-}
-
-
#if GLIB_MAJOR_VERSION < 2
-static GIOError ssl_errno(gint e)
+#ifdef G_CAN_INLINE
+G_INLINE_FUNC
+#else
+static
+#endif
+GIOError ssl_errno(gint e)
{
switch(e)
{
static GIOError irssi_ssl_cert_step(GIOSSLChannel *chan)
{
- X509 *cert;
gint err;
switch(err = SSL_do_handshake(chan->ssl))
{
case 1:
- if(!(cert = SSL_get_peer_certificate(chan->ssl)))
+ if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
{
g_warning("SSL server supplied no certificate");
return G_IO_ERROR_INVAL;
}
- if (chan->verify && ! irssi_ssl_verify(chan->ssl, chan->ctx, cert)) {
- X509_free(cert);
- return G_IO_ERROR_INVAL;
- }
- X509_free(cert);
return G_IO_ERROR_NONE;
default:
if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
gint err;
- if(! chan->got_cert)
+ if(chan->cert == NULL)
{
gint cert_err = irssi_ssl_cert_step(chan);
if(cert_err != G_IO_ERROR_NONE)
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
gint err;
- if(chan->got_cert)
+ if(chan->cert == NULL)
{
gint cert_err = irssi_ssl_cert_step(chan);
if(cert_err != G_IO_ERROR_NONE)
#else /* GLIB_MAJOR_VERSION < 2 */
-static GIOStatus ssl_errno(gint e)
+#ifdef G_CAN_INLINE
+G_INLINE_FUNC
+#else
+static
+#endif
+GIOStatus ssl_errno(gint e)
{
switch(e)
{
static GIOStatus irssi_ssl_cert_step(GIOSSLChannel *chan)
{
- X509 *cert;
gint err;
switch(err = SSL_do_handshake(chan->ssl))
{
case 1:
- if(!(cert = SSL_get_peer_certificate(chan->ssl)))
+ if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
{
g_warning("SSL server supplied no certificate");
return G_IO_STATUS_ERROR;
}
- if (chan->verify && ! irssi_ssl_verify(chan->ssl, chan->ctx, cert)) {
- X509_free(cert);
- return G_IO_STATUS_ERROR;
- }
- X509_free(cert);
return G_IO_STATUS_NORMAL;
default:
if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
return G_IO_STATUS_ERROR;
}
-static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, gsize len, gsize *ret, GError **gerr)
+static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint *ret, GError **gerr)
{
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
gint err;
- if(! chan->got_cert)
+ if(chan->cert == NULL)
{
gint cert_err = irssi_ssl_cert_step(chan);
if(cert_err != G_IO_STATUS_NORMAL)
GIOSSLChannel *chan = (GIOSSLChannel *)handle;
gint err;
- if(! chan->got_cert)
+ if(chan->cert == NULL)
{
gint cert_err = irssi_ssl_cert_step(chan);
if(cert_err != G_IO_STATUS_NORMAL)
#endif
+static SSL_CTX *ssl_ctx = NULL;
+
static gboolean irssi_ssl_init(void)
{
SSL_library_init();
}
-static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycert, const char *mypkey, const char *cafile, const char *capath, gboolean verify)
+static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle)
{
GIOSSLChannel *chan;
GIOChannel *gchan;
int err, fd;
SSL *ssl;
X509 *cert = NULL;
- SSL_CTX *ctx = NULL;
g_return_val_if_fail(handle != NULL, NULL);
if(!(fd = g_io_channel_unix_get_fd(handle)))
return NULL;
- if (mycert && *mycert) {
- char *scert = NULL, *spkey = NULL;
- if ((ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
- g_error("Could not allocate memory for SSL context");
- return NULL;
- }
- scert = convert_home(mycert);
- if (mypkey && *mypkey)
- spkey = convert_home(mypkey);
- if (! SSL_CTX_use_certificate_file(ctx, scert, SSL_FILETYPE_PEM))
- g_warning("Loading of client certificate '%s' failed", mycert);
- else if (! SSL_CTX_use_PrivateKey_file(ctx, spkey ? spkey : scert, SSL_FILETYPE_PEM))
- g_warning("Loading of private key '%s' failed", mypkey ? mypkey : mycert);
- else if (! SSL_CTX_check_private_key(ctx))
- g_warning("Private key does not match the certificate");
- g_free(scert);
- g_free(spkey);
- }
-
- if ((cafile && *cafile) || (capath && *capath)) {
- char *scafile = NULL;
- char *scapath = NULL;
- if (! ctx && (ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
- g_error("Could not allocate memory for SSL context");
- return NULL;
- }
- if (cafile && *cafile)
- scafile = convert_home(cafile);
- if (capath && *capath)
- scapath = convert_home(capath);
- if (! SSL_CTX_load_verify_locations(ctx, scafile, scapath)) {
- g_warning("Could not load CA list for verifying SSL server certificate");
- g_free(scafile);
- g_free(scapath);
- SSL_CTX_free(ctx);
- return NULL;
- }
- g_free(scafile);
- g_free(scapath);
- verify = TRUE;
- }
-
- if (ctx == NULL)
- ctx = ssl_ctx;
-
- if(!(ssl = SSL_new(ctx)))
+ if(!(ssl = SSL_new(ssl_ctx)))
{
g_warning("Failed to allocate SSL structure");
return NULL;
if(!(err = SSL_set_fd(ssl, fd)))
{
g_warning("Failed to associate socket to SSL stream");
- SSL_free(ssl);
- if (ctx != ssl_ctx)
- SSL_CTX_free(ctx);
return NULL;
}
case SSL_ERROR_WANT_WRITE:
break;
default:
- SSL_free(ssl);
- if (ctx != ssl_ctx)
- SSL_CTX_free(ctx);
return NULL;
}
}
else if(!(cert = SSL_get_peer_certificate(ssl)))
{
g_warning("SSL server supplied no certificate");
- if (ctx != ssl_ctx)
- SSL_CTX_free(ctx);
- SSL_free(ssl);
return NULL;
}
else
- {
- if (verify && ! irssi_ssl_verify(ssl, ctx, cert)) {
- SSL_free(ssl);
- if (ctx != ssl_ctx)
- SSL_CTX_free(ctx);
- return NULL;
- }
X509_free(cert);
- }
chan = g_new0(GIOSSLChannel, 1);
chan->fd = fd;
chan->giochan = handle;
chan->ssl = ssl;
- chan->ctx = ctx;
- chan->got_cert = cert != NULL;
- chan->verify = verify;
+ chan->cert = cert;
+ g_io_channel_ref(handle);
gchan = (GIOChannel *)chan;
gchan->funcs = &irssi_ssl_channel_funcs;
return gchan;
}
-GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
{
- GIOChannel *handle, *ssl_handle;
-
- handle = net_connect_ip(ip, port, my_ip);
- ssl_handle = irssi_ssl_get_iochannel(handle, cert, pkey, cafile, capath, verify);
- if (ssl_handle == NULL)
- g_io_channel_unref(handle);
- return ssl_handle;
+ GIOChannel *gret = net_connect_ip(ip, port, my_ip);
+ gret = irssi_ssl_get_iochannel(gret);
+ return gret;
}
#else /* HAVE_OPENSSL */
-GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
{
g_warning("Connection failed: SSL support not enabled in this build.");
errno = ENOSYS;
# define INADDR_NONE INADDR_BROADCAST
#endif
-union sockaddr_union {
+union irssi_sockaddr_union {
struct sockaddr sa;
struct sockaddr_in sin;
#ifdef HAVE_IPV6
/* Cygwin need this, don't know others.. */
/*#define BLOCKING_SOCKETS 1*/
-IPADDR ip4_any = {
- AF_INET,
- { INADDR_ANY }
-};
-
int net_ip_compare(IPADDR *ip1, IPADDR *ip2)
{
if (ip1->family != ip2->family)
}
-static void sin_set_ip(union sockaddr_union *so, const IPADDR *ip)
+/* copy IP to sockaddr */
+#ifdef G_CAN_INLINE
+G_INLINE_FUNC
+#else
+static
+#endif
+void sin_set_ip(union irssi_sockaddr_union *so, const IPADDR *ip)
{
if (ip == NULL) {
#ifdef HAVE_IPV6
memcpy(&so->sin.sin_addr, &ip->ip, 4);
}
-void sin_get_ip(const union sockaddr_union *so, IPADDR *ip)
+void sin_get_ip(const union irssi_sockaddr_union *so, IPADDR *ip)
{
ip->family = so->sin.sin_family;
memcpy(&ip->ip, &so->sin.sin_addr, 4);
}
-static void sin_set_port(union sockaddr_union *so, int port)
+#ifdef G_CAN_INLINE
+G_INLINE_FUNC
+#else
+static
+#endif
+void sin_set_port(union irssi_sockaddr_union *so, int port)
{
#ifdef HAVE_IPV6
if (so->sin.sin_family == AF_INET6)
- so->sin6.sin6_port = htons((unsigned short)port);
+ so->sin6.sin6_port = htons(port);
else
#endif
so->sin.sin_port = htons((unsigned short)port);
}
-static int sin_get_port(union sockaddr_union *so)
+#ifdef G_CAN_INLINE
+G_INLINE_FUNC
+#else
+static
+#endif
+int sin_get_port(union irssi_sockaddr_union *so)
{
#ifdef HAVE_IPV6
if (so->sin.sin_family == AF_INET6)
/* Connect to socket with ip address */
GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip)
{
- union sockaddr_union so;
+ union irssi_sockaddr_union so;
int handle, ret, opt = 1;
if (my_ip != NULL && ip->family != my_ip->family) {
/* set our own address */
if (my_ip != NULL) {
sin_set_ip(&so, my_ip);
- if (bind(handle, &so.sa, SIZEOF_SOCKADDR(so)) < 0) {
- int old_errno = errno;
-
- close(handle);
- errno = old_errno;
- return NULL;
+ if (bind(handle, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
+ /* failed, set it back to INADDR_ANY */
+ sin_set_ip(&so, NULL);
+ bind(handle, &so.sa, SIZEOF_SOCKADDR(so));
}
}
address. */
GIOChannel *net_listen(IPADDR *my_ip, int *port)
{
- union sockaddr_union so;
+ union irssi_sockaddr_union so;
int ret, handle, opt = 1;
socklen_t len;
g_return_val_if_fail(port != NULL, NULL);
memset(&so, 0, sizeof(so));
- sin_set_ip(&so, my_ip);
sin_set_port(&so, *port);
+ sin_set_ip(&so, my_ip);
/* create the socket */
handle = socket(so.sin.sin_family, SOCK_STREAM, 0);
/* Accept a connection on a socket */
GIOChannel *net_accept(GIOChannel *handle, IPADDR *addr, int *port)
{
- union sockaddr_union so;
+ union irssi_sockaddr_union so;
int ret;
socklen_t addrlen;
/* Read data from socket, return number of bytes read, -1 = error */
int net_receive(GIOChannel *handle, char *buf, int len)
{
- gsize ret;
+ unsigned int ret;
int err;
g_return_val_if_fail(handle != NULL, -1);
/* Transmit data, return number of bytes sent, -1 = error */
int net_transmit(GIOChannel *handle, const char *data, int len)
{
- gsize ret;
+ unsigned int ret;
int err;
g_return_val_if_fail(handle != NULL, -1);
/* Get socket address/port */
int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port)
{
- union sockaddr_union so;
+ union irssi_sockaddr_union so;
socklen_t addrlen;
g_return_val_if_fail(handle != NULL, -1);
int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6)
{
#ifdef HAVE_IPV6
- union sockaddr_union *so;
+ union irssi_sockaddr_union *so;
struct addrinfo hints, *ai, *ailist;
- int ret, count_v4, count_v6, use_v4, use_v6;
+ int ret, count;
#else
struct hostent *hp;
- int count;
#endif
g_return_val_if_fail(addr != NULL, -1);
if (ret != 0)
return ret;
- /* count IPs */
- count_v4 = count_v6 = 0;
- for (ai = ailist; ai != NULL; ai = ai->ai_next) {
- if (ai->ai_family == AF_INET)
- count_v4++;
- else if (ai->ai_family == AF_INET6)
- count_v6++;
- }
+ count = 0;
+ for (ai = ailist; ai != NULL && count < 2; ai = ai->ai_next) {
+ so = (union irssi_sockaddr_union *) ai->ai_addr;
- if (count_v4 == 0 && count_v6 == 0)
- return HOST_NOT_FOUND; /* shouldn't happen? */
-
- /* if there are multiple addresses, return random one */
- use_v4 = count_v4 <= 1 ? 0 : rand() % count_v4;
- use_v6 = count_v6 <= 1 ? 0 : rand() % count_v6;
-
- count_v4 = count_v6 = 0;
- for (ai = ailist; ai != NULL; ai = ai->ai_next) {
- so = (union sockaddr_union *) ai->ai_addr;
-
- if (ai->ai_family == AF_INET) {
- if (use_v4 == count_v4)
- sin_get_ip(so, ip4);
- count_v4++;
- } else if (ai->ai_family == AF_INET6) {
- if (use_v6 == count_v6)
- sin_get_ip(so, ip6);
- count_v6++;
+ if (ai->ai_family == AF_INET6 && ip6->family == 0) {
+ sin_get_ip(so, ip6);
+ count++;
+ } else if (ai->ai_family == AF_INET && ip4->family == 0) {
+ sin_get_ip(so, ip4);
+ count++;
}
}
freeaddrinfo(ailist);
- return 0;
+ return count > 0 ? 0 : 1;
#else
hp = gethostbyname(addr);
if (hp == NULL)
return h_errno;
- /* count IPs */
- count = 0;
- while (hp->h_addr_list[count] != NULL)
- count++;
-
- if (count == 0)
- return HOST_NOT_FOUND; /* shouldn't happen? */
-
- /* if there are multiple addresses, return random one */
ip4->family = AF_INET;
- memcpy(&ip4->ip, hp->h_addr_list[rand() % count], 4);
+ memcpy(&ip4->ip, hp->h_addr, 4);
return 0;
#endif
int net_gethostbyaddr(IPADDR *ip, char **name)
{
#ifdef HAVE_IPV6
- union sockaddr_union so;
+ struct addrinfo req, *ai;
int host_error;
char hostname[NI_MAXHOST];
+ char ipname[MAX_IP_LEN];
#else
struct hostent *hp;
#endif
*name = NULL;
#ifdef HAVE_IPV6
- memset(&so, 0, sizeof(so));
- sin_set_ip(&so, ip);
+ net_ip2host(ip, ipname);
+
+ memset(&req, 0, sizeof(struct addrinfo));
+ req.ai_socktype = SOCK_STREAM;
+ req.ai_flags = AI_CANONNAME;
/* save error to host_error for later use */
- host_error = getnameinfo((struct sockaddr *) &so, sizeof(so),
- hostname, sizeof(hostname), NULL, 0, 0);
- if (host_error != 0)
+ host_error = getaddrinfo(ipname, NULL, &req, &ai);
+ if (host_error != 0)
+ return host_error;
+ host_error = getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ hostname, NI_MAXHOST, NULL, 0, 0);
+ if (host_error != 0) {
+ freeaddrinfo(ai);
return host_error;
+ }
*name = g_strdup(hostname);
+
+ freeaddrinfo(ai);
#else
if (ip->family != AF_INET) return -1;
- hp = gethostbyaddr((const char *) &ip->ip, 4, AF_INET);
+ hp = gethostbyaddr(&ip->ip, 4, AF_INET);
if (hp == NULL) return -1;
*name = g_strdup(hp->h_name);
int net_hosterror_notfound(int error)
{
#ifdef HAVE_IPV6
-#ifdef EAI_NODATA /* NODATA is depricated */
return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
-#else
- return error != 1 && (error == EAI_NONAME);
-#endif
#else
return error == HOST_NOT_FOUND || error == NO_ADDRESS;
#endif
#define IPADDR_IS_V6(ip) ((ip)->family != AF_INET)
-extern IPADDR ip4_any;
-
/* returns 1 if IPADDRs are the same */
int net_ip_compare(IPADDR *ip1, IPADDR *ip2);
/* Connect to socket */
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
/* Connect to socket with ip address and SSL*/
-GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip);
/* Connect to socket with ip address */
GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
/* Connect to named UNIX socket */
unsigned int op:1;
unsigned int halfop:1;
unsigned int voice:1;
-char other;
/*GHashTable *module_data;*/
return rec.list;
}
-#if GLIB_MAJOR_VERSION < 2
-/* glib1 doesn't have g_slist_sort_with_data, so non-standard prefixes won't be sorted correctly */
-int nicklist_compare_glib1(NICK_REC *p1, NICK_REC *p2)
-{
- return nicklist_compare(p1, p2, NULL);
-}
-#endif
-
/* nick record comparision for sort functions */
-int nicklist_compare(NICK_REC *p1, NICK_REC *p2, const char *nick_prefix)
+int nicklist_compare(NICK_REC *p1, NICK_REC *p2)
{
int status1, status2;
* returns :-)
* -- yath */
- if (p1->other) {
- const char *other = (nick_prefix == NULL) ? NULL : strchr(nick_prefix, p1->other);
- status1 = (other == NULL) ? 5 : 1000 - (other - nick_prefix);
- } else if (p1->op)
+ if (p1->op)
status1 = 4;
else if (p1->halfop)
status1 = 3;
else
status1 = 1;
- if (p2->other) {
- const char *other = (nick_prefix == NULL) ? NULL : strchr(nick_prefix, p2->other);
- status2 = (other == NULL) ? 5 : 1000 - (other - nick_prefix);
- } else if (p2->op)
+ if (p2->op)
status2 = 4;
else if (p2->halfop)
status2 = 3;
void nicklist_set_own(CHANNEL_REC *channel, NICK_REC *nick);
/* Nick record comparision for sort functions */
-#if GLIB_MAJOR_VERSION < 2
-int nicklist_compare_glib1(NICK_REC *p1, NICK_REC *p2);
-#endif
-int nicklist_compare(NICK_REC *p1, NICK_REC *p2, const char *nick_prefix);
+int nicklist_compare(NICK_REC *p1, NICK_REC *p2);
/* Check is `msg' is meant for `nick'. */
int nick_match_msg(CHANNEL_REC *channel, const char *msg, const char *nick);
+++ /dev/null
-/*
- recode.c : irssi
-
- Copyright (C) 1999-2000 Timo Sirainen
-
- 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.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "module.h"
-#include "settings.h"
-#include "servers.h"
-#include "signals.h"
-#include "lib-config/iconfig.h"
-#include "misc.h"
-
-static gboolean recode_get_charset(const char **charset)
-{
- *charset = settings_get_str("term_charset");
- if (**charset)
- /* we use the same test as in src/fe-text/term.c:123 */
- return (g_strcasecmp(*charset, "utf-8") == 0);
-
-#ifdef HAVE_GLIB2
- return g_get_charset(charset);
-#else
- return FALSE;
-#endif
-}
-
-gboolean is_utf8(void)
-{
- const char *charset;
-
- return recode_get_charset(&charset);
-}
-
-#ifdef HAVE_GLIB2
-static gboolean is_translit(const char *charset)
-{
- char *pos;
-
- pos = stristr(charset, "//translit");
- return (pos != NULL);
-}
-#endif
-
-gboolean is_valid_charset(const char *charset)
-{
-#ifdef HAVE_GLIB2
- const char *from="UTF-8";
- const char *str="irssi";
- char *recoded, *to = NULL;
- gboolean valid;
-
- if (!charset || *charset == '\0')
- return FALSE;
-
- if (settings_get_bool("recode_transliterate") && !is_translit(charset))
- charset = to = g_strconcat(charset, "//TRANSLIT", NULL);
-
- recoded = g_convert(str, strlen(str), charset, from, NULL, NULL, NULL);
- valid = (recoded != NULL);
- g_free(recoded);
- g_free(to);
- return valid;
-#else
- if (!charset || *charset =='\0')
- return FALSE;
- return TRUE;
-#endif
-}
-
-char *recode_in(const SERVER_REC *server, const char *str, const char *target)
-{
-#ifdef HAVE_GLIB2
- const char *from = NULL;
- const char *to = NULL;
- char *translit_to = NULL;
- char *recoded = NULL;
- gboolean term_is_utf8, str_is_utf8, translit, recode, autodetect;
- int len;
- int i;
-
- if (!str)
- return NULL;
-
- recode = settings_get_bool("recode");
- if (!recode)
- return g_strdup(str);
-
- len = strlen(str);
-
- /* Only validate for UTF-8 if an 8-bit encoding. */
- str_is_utf8 = 0;
- for (i = 0; i < len; ++i) {
- if (str[i] & 0x80) {
- str_is_utf8 = g_utf8_validate(str, len, NULL);
- break;
- }
- }
- translit = settings_get_bool("recode_transliterate");
- autodetect = settings_get_bool("recode_autodetect_utf8");
- term_is_utf8 = recode_get_charset(&to);
-
- if (autodetect && str_is_utf8)
- if (term_is_utf8)
- return g_strdup(str);
- else
- from = "UTF-8";
-
- else {
- if (server != NULL && server->tag != NULL && target != NULL) {
- char *tagtarget = g_strdup_printf("%s/%s", server->tag, target);
- from = iconfig_get_str("conversions", tagtarget, NULL);
- g_free(tagtarget);
- }
-
- if (target != NULL && from == NULL)
- from = iconfig_get_str("conversions", target, NULL);
-
- if (from == NULL && server != NULL)
- from = iconfig_get_str("conversions", server->tag, NULL);
-
- }
-
- if (translit && !is_translit(to))
- to = translit_to = g_strconcat(to, "//TRANSLIT", NULL);
-
- if (from)
- recoded = g_convert_with_fallback(str, len, to, from, NULL, NULL, NULL, NULL);
-
- if (!recoded) {
- if (term_is_utf8) {
- if (!str_is_utf8)
- from = settings_get_str("recode_fallback");
-
- } else if (str_is_utf8)
- from = "UTF-8";
-
- if (from)
- recoded = g_convert_with_fallback(str, len, to, from, NULL, NULL, NULL, NULL);
-
- if (!recoded)
- recoded = g_strdup(str);
- }
- g_free(translit_to);
- return recoded;
-#else
- return g_strdup(str);
-#endif
-}
-
-char *recode_out(const SERVER_REC *server, const char *str, const char *target)
-{
-#ifdef HAVE_GLIB2
- char *recoded = NULL;
- const char *from = NULL;
- const char *to = NULL;
- char *translit_to = NULL;
- gboolean translit, term_is_utf8, recode;
- int len;
-
- if (!str)
- return NULL;
-
- recode = settings_get_bool("recode");
- if (!recode)
- return g_strdup(str);
-
- len = strlen(str);
-
- translit = settings_get_bool("recode_transliterate");
-
- if (server != NULL && server->tag != NULL && target != NULL) {
- char *tagtarget = g_strdup_printf("%s/%s", server->tag, target);
- to = iconfig_get_str("conversions", tagtarget, NULL);
- g_free(tagtarget);
- }
- if (to == NULL || *to == '\0')
- to = iconfig_get_str("conversions", target, NULL);
- if ((to == NULL || *to == '\0') && server != NULL)
- to = iconfig_get_str("conversions", server->tag, NULL);
- if (to == NULL || *to == '\0')
- /* default outgoing charset if set */
- to = settings_get_str("recode_out_default_charset");
-
- if (to && *to != '\0') {
- if (translit && !is_translit(to))
- to = translit_to = g_strconcat(to ,"//TRANSLIT", NULL);
-
- term_is_utf8 = recode_get_charset(&from);
- recoded = g_convert(str, len, to, from, NULL, NULL, NULL);
- }
- g_free(translit_to);
- if (!recoded)
- recoded = g_strdup(str);
-
- return recoded;
-#else
- return g_strdup(str);
-#endif
-}
-
-void recode_init(void)
-{
- settings_add_bool("misc", "recode", TRUE);
- settings_add_str("misc", "recode_fallback", "CP1252");
- settings_add_str("misc", "recode_out_default_charset", "");
- settings_add_bool("misc", "recode_transliterate", TRUE);
- settings_add_bool("misc", "recode_autodetect_utf8", TRUE);
-}
-
-void recode_deinit(void)
-{
-
-}
+++ /dev/null
-#ifndef __RECODE_H
-#define __RECODE_H
-
-char *recode_in (const SERVER_REC *server, const char *str, const char *target);
-char *recode_out (const SERVER_REC *server, const char *str, const char *target);
-gboolean is_valid_charset(const char *charset);
-gboolean is_utf8(void);
-
-void recode_init (void);
-void recode_deinit (void);
-
-#endif /* __RECODE_H */
char *username;
char *realname;
-char *ssl_cert;
-char *ssl_pkey;
-char *ssl_cafile;
-char *ssl_capath;
-
GIOChannel *connect_handle; /* connect using this handle */
/* when reconnecting, the old server status */
-unsigned int reconnection:1; /* we're trying to reconnect a connected server */
-unsigned int reconnecting:1; /* we're trying to reconnect any connection */
+unsigned int reconnection:1; /* we're trying to reconnect */
unsigned int no_autojoin_channels:1; /* don't autojoin any channels */
unsigned int unix_socket:1; /* Connect using named unix socket */
unsigned int use_ssl:1; /* this connection uses SSL */
-unsigned int ssl_verify:1;
-unsigned int no_connect:1; /* don't connect() at all, it's done by plugin */
char *channels;
char *away_reason;
channel keys etc. */
void (*channels_join)(SERVER_REC *server, const char *data, int automatic);
/* returns true if `flag' indicates a nick flag (op/voice/halfop) */
-int (*isnickflag)(SERVER_REC *server, char flag);
+int (*isnickflag)(char flag);
/* returns true if `data' indicates a channel */
int (*ischannel)(SERVER_REC *server, const char *data);
/* returns all nick flag characters in order op, voice, halfop. If some
of them aren't supported '\0' can be used. */
-const char *(*get_nick_flags)(SERVER_REC *server);
+const char *(*get_nick_flags)(void);
/* send public or private message to server */
void (*send_message)(SERVER_REC *server, const char *target,
const char *msg, int target_type);
int port;
char *password;
-char *ssl_cert;
-char *ssl_pkey;
-char *ssl_cafile;
-char *ssl_capath;
-
char *own_host; /* address to use when connecting this server */
IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */
unsigned int banned:1; /* if we're banned from this server */
unsigned int dns_error:1; /* DNS said the host doesn't exist */
unsigned int use_ssl:1; /* this connection uses SSL */
-unsigned int ssl_verify:1;
GHashTable *module_data;
rec->next_connect = next_connect;
rec->conn = conn;
- conn->reconnecting = TRUE;
server_connect_ref(conn);
reconnects = g_slist_append(reconnects, rec);
dest->no_autojoin_channels = src->no_autojoin_channels;
dest->use_ssl = src->use_ssl;
- dest->ssl_cert = g_strdup(src->ssl_cert);
- dest->ssl_pkey = g_strdup(src->ssl_pkey);
- dest->ssl_verify = src->ssl_verify;
- dest->ssl_cafile = g_strdup(src->ssl_cafile);
- dest->ssl_capath = g_strdup(src->ssl_capath);
return dest;
}
if (*data == '\0') {
/* reconnect to first server in reconnection list */
if (reconnects == NULL)
- cmd_param_error(CMDERR_NOT_CONNECTED);
+ cmd_return_error(CMDERR_NOT_CONNECTED);
rec = reconnects->data;
} else {
if (g_strncasecmp(data, "RECON-", 6) == 0)
static void read_settings(void)
{
- reconnect_time = settings_get_time("server_reconnect_time")/1000;
- connect_timeout = settings_get_time("server_connect_timeout")/1000;
+ reconnect_time = settings_get_int("server_reconnect_time");
+ connect_timeout = settings_get_int("server_connect_timeout");
}
void servers_reconnect_init(void)
{
- settings_add_time("server", "server_reconnect_time", "5min");
- settings_add_time("server", "server_connect_timeout", "5min");
+ settings_add_int("server", "server_reconnect_time", 300);
+ settings_add_int("server", "server_connect_timeout", 300);
reconnects = NULL;
last_reconnect_tag = 0;
conn->family = sserver->family;
if (sserver->port > 0 && conn->port <= 0)
conn->port = sserver->port;
-
conn->use_ssl = sserver->use_ssl;
- if (conn->ssl_cert == NULL && sserver->ssl_cert != NULL && sserver->ssl_cert[0] != '\0')
- conn->ssl_cert = g_strdup(sserver->ssl_cert);
- if (conn->ssl_pkey == NULL && sserver->ssl_pkey != NULL && sserver->ssl_pkey[0] != '\0')
- conn->ssl_pkey = g_strdup(sserver->ssl_pkey);
- conn->ssl_verify = sserver->ssl_verify;
- if (conn->ssl_cafile == NULL && sserver->ssl_cafile != NULL && sserver->ssl_cafile[0] != '\0')
- conn->ssl_cafile = g_strdup(sserver->ssl_cafile);
- if (conn->ssl_capath == NULL && sserver->ssl_capath != NULL && sserver->ssl_capath[0] != '\0')
- conn->ssl_capath = g_strdup(sserver->ssl_capath);
server_setup_fill_reconn(conn, sserver);
rec->address = g_strdup(server);
rec->password = g_strdup(config_node_get_str(node, "password", NULL));
rec->use_ssl = config_node_get_bool(node, "use_ssl", FALSE);
- rec->ssl_cert = g_strdup(config_node_get_str(node, "ssl_cert", NULL));
- rec->ssl_pkey = g_strdup(config_node_get_str(node, "ssl_pkey", NULL));
- rec->ssl_verify = config_node_get_bool(node, "ssl_verify", FALSE);
- rec->ssl_cafile = g_strdup(config_node_get_str(node, "ssl_cafile", NULL));
- rec->ssl_capath = g_strdup(config_node_get_str(node, "ssl_capath", NULL));
- if (rec->ssl_cafile || rec->ssl_capath)
- rec->ssl_verify = TRUE;
- if (rec->ssl_cert != NULL || rec->ssl_verify)
- rec->use_ssl = TRUE;
rec->port = port;
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
iconfig_node_set_int(node, "port", rec->port);
iconfig_node_set_str(node, "password", rec->password);
iconfig_node_set_bool(node, "use_ssl", rec->use_ssl);
- iconfig_node_set_str(node, "ssl_cert", rec->ssl_cert);
- iconfig_node_set_str(node, "ssl_pkey", rec->ssl_pkey);
- iconfig_node_set_bool(node, "ssl_verify", rec->ssl_verify);
- iconfig_node_set_str(node, "ssl_cafile", rec->ssl_cafile);
- iconfig_node_set_str(node, "ssl_capath", rec->ssl_capath);
iconfig_node_set_str(node, "own_host", rec->own_host);
iconfig_node_set_str(node, "family",
g_free_not_null(rec->own_ip6);
g_free_not_null(rec->chatnet);
g_free_not_null(rec->password);
- g_free_not_null(rec->ssl_cert);
- g_free_not_null(rec->ssl_pkey);
- g_free_not_null(rec->ssl_cafile);
- g_free_not_null(rec->ssl_capath);
g_free(rec->address);
g_free(rec);
}
settings_add_str("server", "user_name", NULL);
settings_add_str("server", "real_name", NULL);
- settings_add_bool("server", "use_ssl", FALSE);
- settings_add_str("server", "ssl_cert", NULL);
- settings_add_str("server", "ssl_pkey", NULL);
- settings_add_bool("server", "ssl_verify", FALSE);
- settings_add_str("server", "ssl_cafile", NULL);
- settings_add_str("server", "ssl_cacert", NULL);
-
settings_add_bool("proxy", "use_proxy", FALSE);
settings_add_str("proxy", "proxy_address", "");
settings_add_int("proxy", "proxy_port", 6667);
const char *unix_socket)
{
GIOChannel *handle;
- IPADDR *own_ip = NULL;
- const char *errmsg;
- char *errmsg2;
- char ipaddr[MAX_IP_LEN];
+ IPADDR *own_ip;
int port;
g_return_if_fail(ip != NULL || unix_socket != NULL);
signal_emit("server connecting", 2, server, ip);
- if (server->connrec->no_connect)
- return;
-
if (ip != NULL) {
own_ip = ip == NULL ? NULL :
(IPADDR_IS_V6(ip) ? server->connrec->own_ip6 :
port = server->connrec->proxy != NULL ?
server->connrec->proxy_port : server->connrec->port;
handle = server->connrec->use_ssl ?
- net_connect_ip_ssl(ip, port, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey,
-server->connrec->ssl_cafile, server->connrec->ssl_capath, server->connrec->ssl_verify) :
+ net_connect_ip_ssl(ip, port, own_ip) :
net_connect_ip(ip, port, own_ip);
} else {
handle = net_connect_unix(unix_socket);
if (handle == NULL) {
/* failed */
- errmsg = g_strerror(errno);
- errmsg2 = NULL;
- if (errno == EADDRNOTAVAIL) {
- if (own_ip != NULL) {
- /* show the IP which is causing the error */
- net_ip2host(own_ip, ipaddr);
- errmsg2 = g_strconcat(errmsg, ": ", ipaddr, NULL);
- }
- server->no_reconnect = TRUE;
- }
if (server->connrec->use_ssl && errno == ENOSYS)
server->no_reconnect = TRUE;
server->connection_lost = TRUE;
- server_connect_failed(server, errmsg2 ? errmsg2 : errmsg);
- g_free(errmsg2);
+ server_connect_failed(server, g_strerror(errno));
} else {
server->handle = net_sendbuffer_create(handle, 0);
server->connect_tag =
g_free_not_null(conn->username);
g_free_not_null(conn->realname);
- g_free_not_null(conn->ssl_cert);
- g_free_not_null(conn->ssl_pkey);
- g_free_not_null(conn->ssl_cafile);
- g_free_not_null(conn->ssl_capath);
-
g_free_not_null(conn->channels);
g_free_not_null(conn->away_reason);
#include "nicklist.h"
static char *session_file;
-char *irssi_binary = NULL;
+static char *irssi_binary;
static char **session_args;
-#ifndef HAVE_GLIB2
-static char *g_find_program_in_path(const char *path)
+void session_set_binary(const char *path)
{
const char *envpath;
char **paths, **tmp;
char *str;
- char *result = NULL;
+
+ g_free_and_null(irssi_binary);
if (g_path_is_absolute(path)) {
/* full path - easy */
- if(access(path, X_OK) == -1)
- return NULL;
- else
- return g_strdup(path);
+ irssi_binary = g_strdup(path);
+ return;
}
if (strchr(path, G_DIR_SEPARATOR) != NULL) {
/* relative path */
str = g_get_current_dir();
- result = g_strconcat(str, G_DIR_SEPARATOR_S, path, NULL);
+ irssi_binary = g_strconcat(str, G_DIR_SEPARATOR_S, path, NULL);
g_free(str);
- if (access(result, X_OK) == -1) {
- g_free(result);
- return NULL;
- }
- else
- return result;
+ return;
}
/* we'll need to find it from path. */
envpath = g_getenv("PATH");
- if (envpath == NULL) return NULL;
+ if (envpath == NULL) return;
paths = g_strsplit(envpath, ":", -1);
for (tmp = paths; *tmp != NULL; tmp++) {
str = g_strconcat(*tmp, G_DIR_SEPARATOR_S, path, NULL);
if (access(str, X_OK) == 0) {
- result = str;
+ irssi_binary = str;
break;
}
g_free(str);
}
g_strfreev(paths);
-
- return result;
-}
-#endif
-
-void session_set_binary(const char *path)
-{
- g_free_and_null(irssi_binary);
-
- irssi_binary = g_find_program_in_path(path);
}
void session_upgrade(void)
if (session_args == NULL)
return;
- execv(session_args[0], session_args);
+ execvp(session_args[0], session_args);
fprintf(stderr, "exec failed: %s: %s\n",
session_args[0], g_strerror(errno));
}
{
CONFIG_REC *session;
char *session_file, *str;
- char *binary;
if (*data == '\0')
data = irssi_binary;
-
- if ((binary = g_find_program_in_path(data)) == NULL)
- cmd_return_error(CMDERR_PROGRAM_NOT_FOUND);
+ if (data == NULL)
+ cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
/* save the session */
session_file = g_strdup_printf("%s/session", get_irssi_dir());
/* data may contain some other program as well, like
/UPGRADE /usr/bin/screen irssi */
str = g_strdup_printf("%s --noconnect --session=%s --home=%s --config=%s",
- binary, session_file, get_irssi_dir(), get_irssi_config());
- g_free(binary);
- g_free(session_file);
+ data, session_file, get_irssi_dir(), get_irssi_config());
session_args = g_strsplit(str, " ", -1);
g_free(str);
static void session_save_nick(CHANNEL_REC *channel, NICK_REC *nick,
CONFIG_REC *config, CONFIG_NODE *node)
{
- static char other[2];
node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
config_node_set_str(config, node, "nick", nick->nick);
config_node_set_bool(config, node, "op", nick->op);
config_node_set_bool(config, node, "halfop", nick->halfop);
config_node_set_bool(config, node, "voice", nick->voice);
-
- other[0] = nick->other;
- other[1] = '\0';
- config_node_set_str(config, node, "other", other);
signal_emit("session save nick", 4, channel, nick, config, node);
}
config_node_set_str(config, node, "chatnet", server->connrec->chatnet);
config_node_set_str(config, node, "password", server->connrec->password);
config_node_set_str(config, node, "nick", server->nick);
- config_node_set_str(config, node, "version", server->version);
config_node_set_bool(config, node, "use_ssl", server->connrec->use_ssl);
- config_node_set_str(config, node, "ssl_cert", server->connrec->ssl_cert);
- config_node_set_str(config, node, "ssl_pkey", server->connrec->ssl_pkey);
- config_node_set_bool(config, node, "ssl_verify", server->connrec->ssl_verify);
- config_node_set_str(config, node, "ssl_cafile", server->connrec->ssl_cafile);
- config_node_set_str(config, node, "ssl_capath", server->connrec->ssl_capath);
handle = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
config_node_set_int(config, node, "handle", handle);
conn->connect_handle = g_io_channel_unix_new(handle);
server = proto->server_init_connect(conn);
- server->version = g_strdup(config_node_get_str(node, "version", NULL));
server->session_reconnect = TRUE;
signal_emit("session restore server", 2, server, node);
void session_init(void)
{
static struct poptOption options[] = {
+#if 0 /* --session is not available in SILC Client */
{ "session", 0, POPT_ARG_STRING, &session_file, 0, "Used by /UPGRADE command", "PATH" },
+#endif
{ NULL, '\0', 0, NULL }
};
- session_file = NULL;
+ session_file = NULL;
args_register(options);
- command_bind("upgrade", NULL, (SIGNAL_FUNC) cmd_upgrade);
+ /*command_bind("upgrade", NULL, (SIGNAL_FUNC) cmd_upgrade);*/
signal_add("session save", (SIGNAL_FUNC) sig_session_save);
signal_add("session restore", (SIGNAL_FUNC) sig_session_restore);
{
g_free_not_null(irssi_binary);
- command_unbind("upgrade", (SIGNAL_FUNC) cmd_upgrade);
+ /*command_unbind("upgrade", (SIGNAL_FUNC) cmd_upgrade);*/
signal_remove("session save", (SIGNAL_FUNC) sig_session_save);
signal_remove("session restore", (SIGNAL_FUNC) sig_session_restore);
#ifndef __SESSION_H
#define __SESSION_H
-extern char *irssi_binary;
-
void session_set_binary(const char *path);
void session_upgrade(void);
#include "module.h"
#include "signals.h"
#include "commands.h"
-#include "levels.h"
#include "misc.h"
#include "lib-config/iconfig.h"
-#include "recode.h"
#include "settings.h"
#include "default-config.h"
#include <signal.h>
-#define SETTINGS_AUTOSAVE_TIMEOUT (1000*60*60) /* 1 hour */
-
CONFIG_REC *mainconfig;
static GString *last_errors;
return rec;
}
-static SETTINGS_REC *settings_get(const char *key, SettingType type)
+const char *settings_get_str(const char *key)
{
SETTINGS_REC *rec;
-
- g_return_val_if_fail(key != NULL, NULL);
+ CONFIG_NODE *setnode, *node;
rec = settings_find(key);
- if (rec == NULL) {
- g_warning("settings_get(%s) : not found", key);
- return NULL;
- }
- if (type != -1 && rec->type != type) {
- g_warning("settings_get(%s) : invalid type", key);
- return NULL;
- }
-
- return rec;
-}
+ g_return_val_if_fail(rec != NULL, NULL);
-static const char *
-settings_get_str_type(const char *key, SettingType type)
-{
- SETTINGS_REC *rec;
- CONFIG_NODE *node;
+ setnode = iconfig_node_traverse("settings", FALSE);
+ if (setnode == NULL)
+ return rec->def;
- rec = settings_get(key, type);
- if (rec == NULL) return NULL;
-
- node = iconfig_node_traverse("settings", FALSE);
- node = node == NULL ? NULL : config_node_section(node, rec->module, -1);
-
- return node == NULL ? rec->default_value.v_string :
- config_node_get_str(node, key, rec->default_value.v_string);
-}
-
-const char *settings_get_str(const char *key)
-{
- return settings_get_str_type(key, -1);
+ node = config_node_section(setnode, rec->module, -1);
+ return node == NULL ? rec->def :
+ config_node_get_str(node, key, rec->def);
}
int settings_get_int(const char *key)
{
SETTINGS_REC *rec;
- CONFIG_NODE *node;
+ CONFIG_NODE *setnode, *node;
+ int def;
- rec = settings_get(key, SETTING_TYPE_INT);
- if (rec == NULL) return 0;
+ rec = settings_find(key);
+ g_return_val_if_fail(rec != NULL, 0);
+ def = GPOINTER_TO_INT(rec->def);
- node = iconfig_node_traverse("settings", FALSE);
- node = node == NULL ? NULL : config_node_section(node, rec->module, -1);
+ setnode = iconfig_node_traverse("settings", FALSE);
+ if (setnode == NULL)
+ return def;
- return node == NULL ? rec->default_value.v_int :
- config_node_get_int(node, key, rec->default_value.v_int);
+ node = config_node_section(setnode, rec->module, -1);
+ return node == NULL ? def :
+ config_node_get_int(node, key, def);
}
int settings_get_bool(const char *key)
{
SETTINGS_REC *rec;
- CONFIG_NODE *node;
+ CONFIG_NODE *setnode, *node;
+ int def;
- rec = settings_get(key, SETTING_TYPE_BOOLEAN);
- if (rec == NULL) return FALSE;
+ rec = settings_find(key);
+ g_return_val_if_fail(rec != NULL, 0);
+ def = GPOINTER_TO_INT(rec->def);
- node = iconfig_node_traverse("settings", FALSE);
- node = node == NULL ? NULL : config_node_section(node, rec->module, -1);
+ setnode = iconfig_node_traverse("settings", FALSE);
+ if (setnode == NULL)
+ return def;
- return node == NULL ? rec->default_value.v_bool :
- config_node_get_bool(node, key, rec->default_value.v_bool);
+ node = config_node_section(setnode, rec->module, -1);
+ return node == NULL ? def :
+ config_node_get_bool(node, key, def);
}
-int settings_get_time(const char *key)
+void settings_add_str_module(const char *module, const char *section,
+ const char *key, const char *def)
{
- const char *str;
- int msecs;
-
- str = settings_get_str_type(key, SETTING_TYPE_TIME);
- if (str != NULL && !parse_time_interval(str, &msecs))
- g_warning("settings_get_time(%s) : Invalid time '%s'", key, str);
- return str == NULL ? 0 : msecs;
-}
+ SETTINGS_REC *rec;
-int settings_get_level(const char *key)
-{
- const char *str;
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(section != NULL);
- str = settings_get_str_type(key, SETTING_TYPE_LEVEL);
- return str == NULL ? 0 : level2bits(str);
-}
+ rec = g_hash_table_lookup(settings, key);
+ g_return_if_fail(rec == NULL);
-int settings_get_size(const char *key)
-{
- const char *str;
- int bytes;
+ rec = g_new0(SETTINGS_REC, 1);
+ rec->module = g_strdup(module);
+ rec->key = g_strdup(key);
+ rec->section = g_strdup(section);
+ rec->def = def == NULL ? NULL : g_strdup(def);
- str = settings_get_str_type(key, SETTING_TYPE_SIZE);
- if (str != NULL && !parse_size(str, &bytes))
- g_warning("settings_get_size(%s) : Invalid size '%s'", key, str);
- return str == NULL ? 0 : bytes;
+ g_hash_table_insert(settings, rec->key, rec);
}
-static void settings_add(const char *module, const char *section,
- const char *key, SettingType type,
- const SettingValue *default_value)
+void settings_add_int_module(const char *module, const char *section,
+ const char *key, int def)
{
SETTINGS_REC *rec;
g_return_if_fail(section != NULL);
rec = g_hash_table_lookup(settings, key);
- if (rec != NULL) {
- /* Already exists, make sure it's correct type */
- if (rec->type != type) {
- g_warning("Trying to add already existing "
- "setting '%s' with different type.", key);
- return;
- }
- } else {
- rec = g_new(SETTINGS_REC, 1);
- rec->module = g_strdup(module);
- rec->key = g_strdup(key);
- rec->section = g_strdup(section);
- rec->type = type;
-
- rec->default_value = *default_value;
- g_hash_table_insert(settings, rec->key, rec);
- }
+ g_return_if_fail(rec == NULL);
- rec->refcount++;
-}
-
-void settings_add_str_module(const char *module, const char *section,
- const char *key, const char *def)
-{
- SettingValue default_value;
-
- memset(&default_value, 0, sizeof(default_value));
- default_value.v_string = g_strdup(def);
- settings_add(module, section, key, SETTING_TYPE_STRING, &default_value);
-}
+ rec = g_new0(SETTINGS_REC, 1);
+ rec->module = g_strdup(module);
+ rec->type = SETTING_TYPE_INT;
+ rec->key = g_strdup(key);
+ rec->section = g_strdup(section);
+ rec->def = GINT_TO_POINTER(def);
-void settings_add_int_module(const char *module, const char *section,
- const char *key, int def)
-{
- SettingValue default_value;
-
- memset(&default_value, 0, sizeof(default_value));
- default_value.v_int = def;
- settings_add(module, section, key, SETTING_TYPE_INT, &default_value);
+ g_hash_table_insert(settings, rec->key, rec);
}
void settings_add_bool_module(const char *module, const char *section,
const char *key, int def)
{
- SettingValue default_value;
-
- memset(&default_value, 0, sizeof(default_value));
- default_value.v_bool = def;
- settings_add(module, section, key, SETTING_TYPE_BOOLEAN,
- &default_value);
-}
-
-void settings_add_time_module(const char *module, const char *section,
- const char *key, const char *def)
-{
- SettingValue default_value;
-
- memset(&default_value, 0, sizeof(default_value));
- default_value.v_string = g_strdup(def);
- settings_add(module, section, key, SETTING_TYPE_TIME, &default_value);
-}
+ SETTINGS_REC *rec;
-void settings_add_level_module(const char *module, const char *section,
- const char *key, const char *def)
-{
- SettingValue default_value;
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(section != NULL);
- memset(&default_value, 0, sizeof(default_value));
- default_value.v_string = g_strdup(def);
- settings_add(module, section, key, SETTING_TYPE_LEVEL, &default_value);
-}
+ rec = g_hash_table_lookup(settings, key);
+ g_return_if_fail(rec == NULL);
-void settings_add_size_module(const char *module, const char *section,
- const char *key, const char *def)
-{
- SettingValue default_value;
+ rec = g_new0(SETTINGS_REC, 1);
+ rec->module = g_strdup(module);
+ rec->type = SETTING_TYPE_BOOLEAN;
+ rec->key = g_strdup(key);
+ rec->section = g_strdup(section);
+ rec->def = GINT_TO_POINTER(def);
- memset(&default_value, 0, sizeof(default_value));
- default_value.v_string = g_strdup(def);
- settings_add(module, section, key, SETTING_TYPE_SIZE, &default_value);
+ g_hash_table_insert(settings, rec->key, rec);
}
static void settings_destroy(SETTINGS_REC *rec)
{
- if (rec->type != SETTING_TYPE_INT &&
- rec->type != SETTING_TYPE_BOOLEAN)
- g_free(rec->default_value.v_string);
+ if (rec->type == SETTING_TYPE_STRING)
+ g_free_not_null(rec->def);
g_free(rec->module);
g_free(rec->section);
g_free(rec->key);
g_free(rec);
}
-static void settings_unref(SETTINGS_REC *rec, int remove_hash)
-{
- if (--rec->refcount == 0) {
- if (remove_hash)
- g_hash_table_remove(settings, rec->key);
- settings_destroy(rec);
- }
-}
-
void settings_remove(const char *key)
{
SETTINGS_REC *rec;
g_return_if_fail(key != NULL);
rec = g_hash_table_lookup(settings, key);
- if (rec != NULL)
- settings_unref(rec, TRUE);
+ if (rec == NULL) return;
+
+ g_hash_table_remove(settings, key);
+ settings_destroy(rec);
}
static int settings_remove_hash(const char *key, SETTINGS_REC *rec,
const char *module)
{
if (strcmp(rec->module, module) == 0) {
- settings_unref(rec, FALSE);
+ settings_destroy(rec);
return TRUE;
}
g_return_val_if_fail(key != NULL, NULL);
rec = g_hash_table_lookup(settings, key);
- if (rec == NULL) {
- g_warning("Changing unknown setting '%s'", key);
- return NULL;
- }
+ g_return_val_if_fail(rec != NULL, NULL);
node = iconfig_node_traverse("settings", TRUE);
return config_node_section(node, rec->module, NODE_TYPE_BLOCK);
iconfig_node_set_bool(settings_get_node(key), key, value);
}
-int settings_set_time(const char *key, const char *value)
-{
- int msecs;
-
- if (!parse_time_interval(value, &msecs))
- return FALSE;
-
- iconfig_node_set_str(settings_get_node(key), key, value);
- return TRUE;
-}
-
-int settings_set_level(const char *key, const char *value)
-{
- iconfig_node_set_str(settings_get_node(key), key, value);
- return TRUE;
-}
-
-int settings_set_size(const char *key, const char *value)
-{
- int size;
-
- if (!parse_size(value, &size))
- return FALSE;
-
- iconfig_node_set_str(settings_get_node(key), key, value);
- return TRUE;
-}
-
-SettingType settings_get_type(const char *key)
+int settings_get_type(const char *key)
{
SETTINGS_REC *rec;
if (config_changed) {
/* some backwards compatibility changes were made to
config file, reload it */
- g_warning("Some settings were automatically "
- "updated, please /SAVE");
signal_emit("setup changed", 0);
}
}
settings_clean_invalid_module(module);
+ g_free(module);
last_invalid_modules =
g_slist_remove(last_invalid_modules, module);
- g_free(module);
- }
-}
-
-static int backwards_compatibility(const char *module, CONFIG_NODE *node,
- CONFIG_NODE *parent)
-{
- const char *new_key, *new_module;
- CONFIG_NODE *new_node;
- char *new_value;
- int old_value;
-
- new_value = NULL; new_key = NULL; new_module = NULL;
-
- /* fe-text term_type -> fe-common/core term_charset - for 0.8.10-> */
- if (strcmp(module, "fe-text") == 0) {
- if (strcasecmp(node->key, "term_type") == 0 ||
- /* kludge for cvs-version where term_charset was in fe-text */
- strcasecmp(node->key, "term_charset") == 0) {
- new_module = "fe-common/core";
- new_key = "term_charset";
- new_value = !is_valid_charset(node->value) ? NULL :
- g_strdup(node->value);
- new_node = iconfig_node_traverse("settings", FALSE);
- new_node = new_node == NULL ? NULL :
- config_node_section(new_node, new_module, -1);
-
- config_node_set_str(mainconfig, new_node,
- new_key, new_value);
- /* remove old */
- config_node_set_str(mainconfig, parent,
- node->key, NULL);
- g_free(new_value);
- config_changed = TRUE;
- return new_key != NULL;
- }
- }
- new_value = NULL, new_key = NULL;
- /* FIXME: remove later - for 0.8.6 -> */
- if (node->value == NULL || !is_numeric(node->value, '\0'))
- return FALSE;
-
- old_value = atoi(node->value);
-
- if (strcmp(module, "fe-text") == 0) {
- if (strcasecmp(node->key, "lag_min_show") == 0)
- new_value = g_strdup_printf("%dms", old_value*10);
- else if (strcasecmp(node->key, "scrollback_hours") == 0) {
- new_value = g_strdup_printf("%dh", old_value);
- new_key = "scrollback_time";
- }
- } else if (strcmp(module, "irc/core") == 0) {
- if (strcasecmp(node->key, "cmd_queue_speed") == 0)
- new_value = g_strdup_printf("%dms", old_value);
- } else if (strcmp(module, "irc/dcc") == 0) {
- if (strcasecmp(node->key, "dcc_autoget_max_size") == 0)
- new_value = g_strdup_printf("%dk", old_value);
- } else if (strcmp(module, "irc/notify") == 0) {
- if (strcasecmp(node->key, "notify_idle_time") == 0)
- new_value = g_strdup_printf("%dmin", old_value);
- } else if (strcmp(module, "core") == 0) {
- if (strcasecmp(node->key, "write_buffer_mins") == 0) {
- new_value = g_strdup_printf("%dmin", old_value);
- new_key = "write_buffer_timeout";
- } else if (strcasecmp(node->key, "write_buffer_kb") == 0) {
- new_value = g_strdup_printf("%dk", old_value);
- new_key = "write_buffer_size";
- }
- }
-
- if (new_key != NULL || new_value != NULL) {
- config_node_set_str(mainconfig, parent,
- new_key != NULL ? new_key : node->key,
- new_value != NULL ?
- new_value : node->value);
- if (new_key != NULL) {
- /* remove old */
- config_node_set_str(mainconfig, parent,
- node->key, NULL);
- }
- config_changed = TRUE;
- g_free(new_value);
}
- return new_key != NULL;
}
/* verify that all settings in config file for `module' are actually found
void settings_check_module(const char *module)
{
SETTINGS_REC *set;
- CONFIG_NODE *node, *parent;
+ CONFIG_NODE *node;
GString *errors;
- GSList *tmp, *next;
+ GSList *tmp;
int count;
g_return_if_fail(module != NULL);
"file for module %s:", module);
count = 0;
- parent = node;
tmp = config_node_first(node->value);
- for (; tmp != NULL; tmp = next) {
+ for (; tmp != NULL; tmp = config_node_next(tmp)) {
node = tmp->data;
- next = config_node_next(tmp);
set = g_hash_table_lookup(settings, node->key);
- if (backwards_compatibility(module, node, parent))
- continue;
-
if (set == NULL || strcmp(set->module, module) != 0) {
g_string_sprintfa(errors, " %s", node->key);
count++;
config = config_open(NULL, -1);
}
- if (config->fname != NULL)
+ if (path != NULL)
config_parse(config);
else
config_parse_data(config, default_config, "internal");
init_configfile();
settings_add_bool("misc", "settings_autosave", TRUE);
- timeout_tag = g_timeout_add(SETTINGS_AUTOSAVE_TIMEOUT,
- (GSourceFunc) sig_autosave, NULL);
+ timeout_tag = g_timeout_add(1000*60*60, (GSourceFunc) sig_autosave, NULL);
signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
signal_add("gui exit", (SIGNAL_FUNC) sig_autosave);
}
#ifndef __SETTINGS_H
#define __SETTINGS_H
-typedef enum {
+enum {
SETTING_TYPE_STRING,
SETTING_TYPE_INT,
- SETTING_TYPE_BOOLEAN,
- SETTING_TYPE_TIME,
- SETTING_TYPE_LEVEL,
- SETTING_TYPE_SIZE
-} SettingType;
+ SETTING_TYPE_BOOLEAN
+};
typedef struct {
- char *v_string;
- int v_int;
- unsigned int v_bool:1;
-} SettingValue;
-
-typedef struct {
- int refcount;
-
- char *module;
+ char *module;
+ int type;
char *key;
char *section;
-
- SettingType type;
- SettingValue default_value;
+ void *def;
} SETTINGS_REC;
/* macros for handling the default Irssi configuration */
const char *settings_get_str(const char *key);
int settings_get_int(const char *key);
int settings_get_bool(const char *key);
-int settings_get_time(const char *key); /* as milliseconds */
-int settings_get_level(const char *key);
-int settings_get_size(const char *key); /* as bytes */
/* Functions to add/remove settings */
void settings_add_str_module(const char *module, const char *section,
const char *key, int def);
void settings_add_bool_module(const char *module, const char *section,
const char *key, int def);
-void settings_add_time_module(const char *module, const char *section,
- const char *key, const char *def);
-void settings_add_level_module(const char *module, const char *section,
- const char *key, const char *def);
-void settings_add_size_module(const char *module, const char *section,
- const char *key, const char *def);
void settings_remove(const char *key);
void settings_remove_module(const char *module);
settings_add_int_module(MODULE_NAME, section, key, def)
#define settings_add_bool(section, key, def) \
settings_add_bool_module(MODULE_NAME, section, key, def)
-#define settings_add_time(section, key, def) \
- settings_add_time_module(MODULE_NAME, section, key, def)
-#define settings_add_level(section, key, def) \
- settings_add_level_module(MODULE_NAME, section, key, def)
-#define settings_add_size(section, key, def) \
- settings_add_size_module(MODULE_NAME, section, key, def)
void settings_set_str(const char *key, const char *value);
void settings_set_int(const char *key, int value);
void settings_set_bool(const char *key, int value);
-int settings_set_time(const char *key, const char *value);
-int settings_set_level(const char *key, const char *value);
-int settings_set_size(const char *key, const char *value);
/* Get the type (SETTING_TYPE_xxx) of `key' */
-SettingType settings_get_type(const char *key);
+int settings_get_type(const char *key);
/* Get all settings sorted by section. Free the result with g_slist_free() */
GSList *settings_get_sorted(void);
/* Get the record of the setting */
static void read_settings(void)
{
+ int msecs;
+
write_buffer_flush();
- write_buffer_max_blocks =
- settings_get_size("write_buffer_size") / BUFFER_BLOCK_SIZE;
+ write_buffer_max_blocks = settings_get_int("write_buffer_kb") *
+ 1024/BUFFER_BLOCK_SIZE;
- if (settings_get_time("write_buffer_timeout") > 0) {
+ if (settings_get_int("write_buffer_mins") > 0) {
+ msecs = settings_get_int("write_buffer_mins")*60*1000;
if (timeout_tag == -1) {
- timeout_tag = g_timeout_add(settings_get_time("write_buffer_timeout"),
+ timeout_tag = g_timeout_add(msecs,
(GSourceFunc) flush_timeout,
NULL);
}
void write_buffer_init(void)
{
- settings_add_time("misc", "write_buffer_timeout", "0");
- settings_add_size("misc", "write_buffer_size", "0");
+ settings_add_int("misc", "write_buffer_mins", 0);
+ settings_add_int("misc", "write_buffer_kb", 0);
buffers = g_hash_table_new((GHashFunc) g_direct_hash,
(GCompareFunc) g_direct_equal);
fe-queries.c \
fe-server.c \
fe-settings.c \
- utf8.c \
formats.c \
hilight-text.c \
keyboard.c \
module-formats.c \
printtext.c \
- fe-recode.c \
themes.c \
translation.c \
window-activity.c \
fe-exec.h \
fe-messages.h \
fe-queries.h \
- utf8.h \
formats.h \
hilight-text.h \
keyboard.h \
module-formats.h \
module.h \
printtext.h \
- fe-recode.h \
themes.h \
translation.h \
window-activity.h \
}
}
-static void last_msg_destroy(GSList **list, LAST_MSG_REC *rec)
-{
- *list = g_slist_remove(*list, rec);
-
- g_free(rec->nick);
- g_free(rec);
-}
-
static void last_msg_add(GSList **list, const char *nick, int own, int max)
{
LAST_MSG_REC *rec;
- if (max <= 0)
- return;
-
rec = last_msg_find(*list, nick);
if (rec != NULL) {
/* msg already exists, update it */
rec = g_new(LAST_MSG_REC, 1);
rec->nick = g_strdup(nick);
- while ((int)g_slist_length(*list) >= max) {
- last_msg_destroy(list, g_slist_last(*list)->data);
+ if ((int)g_slist_length(*list) == max) {
+ *list = g_slist_remove(*list,
+ g_slist_last(*list)->data);
}
rec->own = own ? max : 0;
*list = g_slist_prepend(*list, rec);
}
+static void last_msg_destroy(GSList **list, LAST_MSG_REC *rec)
+{
+ *list = g_slist_remove(*list, rec);
+
+ g_free(rec->nick);
+ g_free(rec);
+}
+
void completion_last_message_add(const char *nick)
{
g_return_if_fail(nick != NULL);
const char *target, const char *origtarget)
{
g_return_if_fail(server != NULL);
+ g_return_if_fail(target != NULL);
if (target != NULL && query_find(server, target) == NULL)
SERVER_LAST_MSG_ADD(server, target);
return list;
}
-GList *completion_get_targets(const char *word)
-{
- CONFIG_NODE *node;
- GList *list;
- GSList *tmp;
- int len;
-
- g_return_val_if_fail(word != NULL, NULL);
-
- len = strlen(word);
- list = NULL;
-
- /* get the list of all conversion targets */
- node = iconfig_node_traverse("conversions", FALSE);
- tmp = node == NULL ? NULL : config_node_first(node->value);
- for (; tmp != NULL; tmp = config_node_next(tmp)) {
- node = tmp->data;
-
- if (node->type != NODE_TYPE_KEY)
- continue;
-
- if (len != 0 && g_strncasecmp(node->key, word, len) != 0)
- continue;
-
- list = g_list_append(list, g_strdup(node->key));
- }
-
- return list;
-}
-
static void sig_complete_connect(GList **list, WINDOW_REC *window,
const char *word, const char *line,
int *want_space)
}
}
+
static void sig_complete_channel(GList **list, WINDOW_REC *window,
const char *word, const char *line,
int *want_space)
if (*list != NULL) signal_stop();
}
-static void sig_complete_target(GList **list, WINDOW_REC *window,
- const char *word, const char *line,
- int *want_space)
-{
- const char *definition;
-
- g_return_if_fail(list != NULL);
- g_return_if_fail(word != NULL);
- g_return_if_fail(line != NULL);
-
- if (*line != '\0') {
- if ((definition = iconfig_get_str("conversions", line ,NULL)) != NULL) {
- *list = g_list_append(NULL, g_strdup(definition));
- signal_stop();
- }
- } else {
- *list = completion_get_targets(word);
- if (*list != NULL) signal_stop();
- }
-}
-
/* expand \n, \t and \\ */
static char *expand_escapes(const char *line, SERVER_REC *server,
WI_ITEM_REC *item)
signal_add("complete command window item move", (SIGNAL_FUNC) sig_complete_channel);
signal_add("complete command server add", (SIGNAL_FUNC) sig_complete_server);
signal_add("complete command server remove", (SIGNAL_FUNC) sig_complete_server);
- signal_add("complete command recode remove", (SIGNAL_FUNC) sig_complete_target);
signal_add("message public", (SIGNAL_FUNC) sig_message_public);
signal_add("message join", (SIGNAL_FUNC) sig_message_join);
signal_add("message private", (SIGNAL_FUNC) sig_message_private);
signal_remove("complete command window item move", (SIGNAL_FUNC) sig_complete_channel);
signal_remove("complete command server add", (SIGNAL_FUNC) sig_complete_server);
signal_remove("complete command server remove", (SIGNAL_FUNC) sig_complete_server);
- signal_remove("complete command recode remove", (SIGNAL_FUNC) sig_complete_target);
signal_remove("message public", (SIGNAL_FUNC) sig_message_public);
signal_remove("message join", (SIGNAL_FUNC) sig_message_join);
signal_remove("message private", (SIGNAL_FUNC) sig_message_private);
((c) == ',')
#define isseparator(c) \
- ((c) == ' ' || isseparator_notspace(c))
+ (i_isspace(c) || isseparator_notspace(c))
void chat_completion_init(void);
void chat_completion_deinit(void);
} else {
checkcmd = g_strndup(line, (int) (ptr-line));
- while (*ptr == ' ') ptr++;
+ while (i_isspace(*ptr)) ptr++;
cmdargs = ptr;
}
fe_channels_nicklist(channel, CHANNEL_NICKLIST_FLAG_ALL);
}
-static void cmd_wjoin_pre(const char *data, SERVER_REC *server)
+static void cmd_wjoin_pre(const char *data)
{
GHashTable *optlist;
char *nick;
"join", &optlist, &nick))
return;
- /* kludge for /join -invite -window if there is no invite */
- if (g_hash_table_lookup(optlist, "invite") &&
- server != NULL && server->last_invite == NULL) {
- cmd_params_free(free_arg);
- return;
- }
if (g_hash_table_lookup(optlist, "window") != NULL) {
signal_add("channel created",
(SIGNAL_FUNC) signal_channel_created_curwin);
{
WINDOW_REC *window;
CHANNEL_REC *channel;
- GHashTable *optlist;
- char *channelname;
- void *free_arg;
- if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
- PARAM_FLAG_UNKNOWN_OPTIONS,
- "join", &optlist, &channelname))
+ if (strchr(data, ' ') != NULL || strchr(data, ',') != NULL)
+ return;
+
+ channel = channel_find(server, data);
+ if (channel == NULL)
return;
- /* -<server tag> */
- server = cmd_options_get_server("join", optlist, server);
-
- channel = channel_find(server, channelname);
- if (channel != NULL) {
- /* already joined to channel, set it active */
- window = window_item_window(channel);
- if (window != active_win)
- window_set_active(window);
-
- window_item_set_active(active_win, (WI_ITEM_REC *) channel);
- }
- cmd_params_free(free_arg);
+ /* already joined to channel, set it active */
+ window = window_item_window(channel);
+ if (window != active_win)
+ window_set_active(window);
+
+ window_item_set_active(active_win, (WI_ITEM_REC *) channel);
}
static void cmd_wjoin_post(const char *data)
}
/* SYNTAX: CHANNEL ADD [-auto | -noauto] [-bots <masks>] [-botcmd <command>]
- <channel> <network> [<password>] */
+ <channel> <chatnet> [<password>] */
static void cmd_channel_add(const char *data)
{
GHashTable *optlist;
cmd_params_free(free_arg);
}
-/* SYNTAX: CHANNEL REMOVE <channel> <network> */
+/* SYNTAX: CHANNEL REMOVE <channel> <chatnet> */
static void cmd_channel_remove(const char *data)
{
CHANNEL_SETUP_REC *rec;
for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
NICK_REC *rec = tmp->data;
- if (rec->other)
- nickmode[0] = rec->other;
- else if (rec->op)
+ if (rec->op)
nickmode[0] = '@';
else if (rec->halfop)
nickmode[0] = '%';
NICK_REC *nick;
GSList *tmp, *nicklist, *sorted;
int nicks, normal, voices, halfops, ops;
- const char *nick_flags;
nicks = normal = voices = halfops = ops = 0;
nicklist = nicklist_getnicks(channel);
sorted = NULL;
- nick_flags = channel->server->get_nick_flags(channel->server);
- /* filter (for flags) and count ops, halfops, voices */
+ /* sort the nicklist */
for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
nick = tmp->data;
continue;
}
- sorted = g_slist_prepend(sorted, nick);
+ sorted = g_slist_insert_sorted(sorted, nick, (GCompareFunc)
+ nicklist_compare);
}
g_slist_free(nicklist);
- /* sort the nicklist */
-#if GLIB_MAJOR_VERSION < 2
- /* glib1 doesn't have g_slist_sort_with_data, so non-standard prefixes won't be sorted correctly */
- sorted = g_slist_sort(sorted, (GCompareFunc)nicklist_compare_glib1);
-#else
- sorted = g_slist_sort_with_data(sorted, (GCompareDataFunc) nicklist_compare, (void *)nick_flags);
-#endif
-
/* display the nicks */
if ((flags & CHANNEL_NICKLIST_FLAG_COUNT) == 0) {
printformat(channel->server, channel->visible_name,
#include "levels.h"
#include "settings.h"
#include "irssi-version.h"
-#ifdef HAVE_NL_LANGINFO
-# include <langinfo.h>
-#endif
#include "servers.h"
#include "channels.h"
#include "servers-setup.h"
-#include "recode.h"
#include "autorun.h"
#include "fe-core-commands.h"
#include "window-activity.h"
#include "window-items.h"
#include "windows-layout.h"
-#include "fe-recode.h"
#include <signal.h>
void window_commands_init(void);
void window_commands_deinit(void);
-static void sig_setup_changed(void);
-
static void print_version(void)
{
printf(PACKAGE" " IRSSI_VERSION" (%d %04d)\n",
static void sig_disconnected(SERVER_REC *server)
{
- void *data = MODULE_DATA(server);
- g_free(data);
+ g_free(MODULE_DATA(server));
MODULE_DATA_UNSET(server);
}
static void sig_channel_destroyed(CHANNEL_REC *channel)
{
- void *data = MODULE_DATA(channel);
-
- g_free(data);
+ g_free(MODULE_DATA(channel));
MODULE_DATA_UNSET(channel);
}
static struct poptOption options[] = {
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, version_options, 0, NULL, NULL },
POPT_AUTOHELP
- { "connect", 'c', POPT_ARG_STRING, &autocon_server, 0, "Automatically connect to server/network", "SERVER" },
+ { "connect", 'c', POPT_ARG_STRING, &autocon_server, 0, "Automatically connect to server", "SERVER" },
{ "password", 'w', POPT_ARG_STRING, &autocon_password, 0, "Autoconnect password", "PASSWORD" },
{ "port", 'p', POPT_ARG_INT, &autocon_port, 0, "Autoconnect port", "PORT" },
{ "noconnect", '!', POPT_ARG_NONE, &no_autoconnect, 0, "Disable autoconnecting", NULL },
args_register(options);
settings_add_bool("lookandfeel", "timestamps", TRUE);
- settings_add_level("lookandfeel", "timestamp_level", "ALL");
- settings_add_time("lookandfeel", "timestamp_timeout", "0");
+ settings_add_str("lookandfeel", "timestamp_level", "ALL");
+ settings_add_int("lookandfeel", "timestamp_timeout", 0);
settings_add_bool("lookandfeel", "bell_beeps", FALSE);
- settings_add_level("lookandfeel", "beep_msg_level", "");
+ settings_add_str("lookandfeel", "beep_msg_level", "");
settings_add_bool("lookandfeel", "beep_when_window_active", TRUE);
settings_add_bool("lookandfeel", "beep_when_away", TRUE);
settings_add_bool("lookandfeel", "use_status_window", TRUE);
settings_add_bool("lookandfeel", "use_msgs_window", FALSE);
-#if defined (HAVE_NL_LANGINFO) && defined(CODESET)
- settings_add_str("lookandfeel", "term_charset",
- *nl_langinfo(CODESET) != '\0' ?
- nl_langinfo(CODESET) : "ISO8859-1");
-#else
- settings_add_str("lookandfeel", "term_charset", "ISO8859-1");
-#endif
+
themes_init();
theme_register(fecommon_core_formats);
fe_messages_init();
hilight_text_init();
fe_ignore_messages_init();
- fe_recode_init();
settings_check();
fe_messages_deinit();
fe_ignore_messages_deinit();
- fe_recode_deinit();
theme_unregister();
themes_deinit();
- signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created);
static void create_windows(void)
{
WINDOW_REC *window;
- int have_status = settings_get_bool("use_status_window");
-
- window = window_find_name("(status)");
- if (have_status) {
- if (window == NULL) {
- window = window_create(NULL, TRUE);
- window_set_refnum(window, 1);
- window_set_name(window, "(status)");
- window_set_level(window, MSGLEVEL_ALL ^
- (settings_get_bool("use_msgs_window") ?
- MSGS_WINDOW_LEVELS : 0));
- window_set_immortal(window, TRUE);
- }
- } else {
- if (window != NULL) {
- window_set_name(window, NULL);
- window_set_level(window, 0);
- window_set_immortal(window, FALSE);
- }
+
+ windows_layout_restore();
+ if (windows != NULL)
+ return;
+
+ if (settings_get_bool("use_status_window")) {
+ window = window_create(NULL, TRUE);
+ window_set_name(window, "(status)");
+ window_set_level(window, MSGLEVEL_ALL ^
+ (settings_get_bool("use_msgs_window") ?
+ MSGS_WINDOW_LEVELS : 0));
+ window_set_immortal(window, TRUE);
}
- window = window_find_name("(msgs)");
if (settings_get_bool("use_msgs_window")) {
- if (window == NULL) {
- window = window_create(NULL, TRUE);
- window_set_refnum(window, have_status ? 2 : 1);
- window_set_name(window, "(msgs)");
- window_set_level(window, MSGS_WINDOW_LEVELS);
- window_set_immortal(window, TRUE);
- }
- } else {
- if (window != NULL) {
- window_set_name(window, NULL);
- window_set_level(window, 0);
- window_set_immortal(window, FALSE);
- }
+ window = window_create(NULL, TRUE);
+ window_set_name(window, "(msgs)");
+ window_set_level(window, MSGS_WINDOW_LEVELS);
+ window_set_immortal(window, TRUE);
}
if (windows == NULL) {
g_slist_free(chatnets);
}
-static void sig_setup_changed(void)
-{
- static int firsttime = TRUE;
- static int status_window = FALSE, msgs_window = FALSE;
- int changed = FALSE;
-
- if (settings_get_bool("use_status_window") != status_window) {
- status_window = !status_window;
- changed = TRUE;
- }
- if (settings_get_bool("use_msgs_window") != msgs_window) {
- msgs_window = !msgs_window;
- changed = TRUE;
- }
-
- if (firsttime) {
- firsttime = FALSE;
- changed = TRUE;
-
- windows_layout_restore();
- if (windows != NULL)
- return;
- }
-
- if (changed)
- create_windows();
-}
-
void fe_common_core_finish_init(void)
{
int setup_changed;
#endif
setup_changed = FALSE;
- if (cmdline_nick != NULL && *cmdline_nick != '\0') {
+ if (cmdline_nick != NULL) {
/* override nick found from setup */
settings_set_str("nick", cmdline_nick);
setup_changed = TRUE;
setup_changed = TRUE;
}
- sig_setup_changed();
- signal_add_first("setup changed", (SIGNAL_FUNC) sig_setup_changed);
+ create_windows();
/* _after_ windows are created.. */
-#if GLIB_CHECK_VERSION(2,6,0)
- g_log_set_default_handler((GLogFunc) glog_func, NULL);
-#else
g_log_set_handler(G_LOG_DOMAIN,
(GLogLevelFlags) (G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_WARNING),
(GLogFunc) glog_func, NULL);
- g_log_set_handler("GLib",
- (GLogLevelFlags) (G_LOG_LEVEL_CRITICAL |
- G_LOG_LEVEL_WARNING),
- (GLogFunc) glog_func, NULL); /* send glib errors to the same place */
-#endif
if (setup_changed)
signal_emit("setup changed", 0);
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "core.h"
#include "module.h"
#include "module-formats.h"
#include "signals.h"
TXT_CHAN_NOT_FOUND,
TXT_CHAN_NOT_SYNCED,
TXT_ILLEGAL_PROTO,
- TXT_NOT_GOOD_IDEA,
- TXT_INVALID_TIME,
- TXT_INVALID_CHARSET,
- TXT_EVAL_MAX_RECURSE,
- TXT_PROGRAM_NOT_FOUND
+ TXT_NOT_GOOD_IDEA
};
int command_hide_output;
cmd_params_free(free_arg);
}
-/* SYNTAX: UPTIME */
-static void cmd_uptime(char *data)
-{
- time_t uptime;
-
- g_return_if_fail(data != NULL);
-
- if (*data == '\0') {
- uptime = time(NULL) - client_start_time;
- printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- "Uptime: %ldd %ldh %ldm %lds",
- uptime/3600/24, uptime/3600%24,
- uptime/60%60, uptime%60);
- }
-}
-
static void sig_stop(void)
{
signal_stop();
cmdchar = *data == '\0' ? NULL :
strchr(settings_get_str("cmdchars"), *data);
if (cmdchar != NULL && (data[1] == '^' ||
- (data[1] == *cmdchar && data[2] == '^'))
- && !command_hide_output++) {
+ (data[1] == *cmdchar && data[2] == '^'))) {
+ command_hide_output = TRUE;
signal_add_first("print starting", (SIGNAL_FUNC) sig_stop);
signal_add_first("print format", (SIGNAL_FUNC) sig_stop);
signal_add_first("print text", (SIGNAL_FUNC) sig_stop);
static void event_command_last(const char *data)
{
- if (command_hide_output && !--command_hide_output) {
+ if (command_hide_output) {
+ command_hide_output = FALSE;
signal_remove("print starting", (SIGNAL_FUNC) sig_stop);
signal_remove("print format", (SIGNAL_FUNC) sig_stop);
signal_remove("print text", (SIGNAL_FUNC) sig_stop);
void fe_core_commands_init(void)
{
- command_hide_output = 0;
+ command_hide_output = FALSE;
command_cmd = FALSE;
memset(&time_command_now, 0, sizeof(GTimeVal));
command_bind("version", NULL, (SIGNAL_FUNC) cmd_version);
command_bind("cat", NULL, (SIGNAL_FUNC) cmd_cat);
command_bind("beep", NULL, (SIGNAL_FUNC) cmd_beep);
- command_bind("uptime", NULL, (SIGNAL_FUNC) cmd_uptime);
command_bind_first("nick", NULL, (SIGNAL_FUNC) cmd_nick);
command_bind_first("join", NULL, (SIGNAL_FUNC) cmd_join);
command_unbind("version", (SIGNAL_FUNC) cmd_version);
command_unbind("cat", (SIGNAL_FUNC) cmd_cat);
command_unbind("beep", (SIGNAL_FUNC) cmd_beep);
- command_unbind("uptime", (SIGNAL_FUNC) cmd_uptime);
command_unbind("nick", (SIGNAL_FUNC) cmd_nick);
command_unbind("join", (SIGNAL_FUNC) cmd_join);
#include "misc.h"
#include "levels.h"
-#include "servers.h"
#include "channels.h"
#include "queries.h"
g_free_not_null(rec->name);
g_free_not_null(rec->target);
- g_free_not_null(rec->target_server);
g_free(rec->args);
g_free(rec);
}
static void sig_exec_input_reader(PROCESS_REC *rec)
{
char tmpbuf[512], *str;
- gsize recvlen;
+ unsigned int recvlen;
int err, ret;
g_return_if_fail(rec != NULL);
}
static void handle_exec(const char *args, GHashTable *optlist,
- SERVER_REC *server, WI_ITEM_REC *item)
+ WI_ITEM_REC *item)
{
PROCESS_REC *rec;
- SERVER_REC *target_server;
char *target, *level;
int notice, signum, interactive, target_nick, target_channel;
}
target = NULL;
- target_server = NULL;
notice = FALSE;
if (g_hash_table_lookup(optlist, "in") != NULL) {
if (item == NULL)
cmd_return_error(CMDERR_NOT_JOINED);
target = (char *) window_item_get_target(item);
- target_server = item->server;
target_channel = IS_CHANNEL(item);
target_nick = IS_QUERY(item);
} else if (g_hash_table_lookup(optlist, "msg") != NULL) {
/* redirect output to /msg <nick> */
target = g_hash_table_lookup(optlist, "msg");
- target_server = server;
} else if (g_hash_table_lookup(optlist, "notice") != NULL) {
target = g_hash_table_lookup(optlist, "notice");
- target_server = server;
notice = TRUE;
}
/* redirect output to target */
g_free_and_null(rec->target);
rec->target = g_strdup(target);
- rec->target_server = target_server == NULL ? NULL :
- g_strdup(target_server->tag);
rec->notice = notice;
}
rec->id = process_get_new_id();
rec->target = g_strdup(target);
- rec->target_server = target_server == NULL ? NULL :
- g_strdup(target_server->tag);
rec->target_win = active_win;
rec->target_channel = target_channel;
rec->target_nick = target_nick;
if (cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
"exec", &optlist, &args)) {
- handle_exec(args, optlist, server, item);
+ handle_exec(args, optlist, item);
cmd_params_free(free_arg);
}
}
server = NULL;
if (rec->target != NULL) {
- if (rec->target_server != NULL) {
- server = server_find_tag(rec->target_server);
- if (server == NULL) {
- /* disconnected - target is lost */
- return;
- }
- item = NULL;
- } else {
- item = window_item_find(NULL, rec->target);
- server = item != NULL ? item->server :
- active_win->active_server;
- }
+ item = window_item_find(NULL, rec->target);
+ server = item != NULL ? item->server :
+ active_win->active_server;
str = g_strconcat(rec->target_nick ? "-nick " :
rec->target_channel ? "-channel " : "",
int level; /* what level to use when printing the text */
char *target; /* send text with /msg <target> ... */
- char *target_server;
WINDOW_REC *target_win; /* print text to this window */
EXEC_WI_REC *target_item; /* print text to this exec window item */
ptr = cmd+strlen(cmd);
while (ptr[-1] == ' ') ptr--; *ptr = '\0';
- g_strdown(cmd);
show_help(cmd);
g_free(cmd);
}
}
if (rec->fullword) g_string_append(options, "-full ");
if (rec->replies) g_string_append(options, "-replies ");
- if (rec->servertag != NULL)
- g_string_sprintfa(options, "-network %s ", rec->servertag);
if (rec->pattern != NULL)
g_string_sprintfa(options, "-pattern %s ", rec->pattern);
}
/* SYNTAX: IGNORE [-regexp | -full] [-pattern <pattern>] [-except] [-replies]
- [-network <network>] [-channels <channel>] [-time <secs>] <mask> [<levels>]
+ [-channels <channel>] [-time <secs>] <mask> [<levels>]
IGNORE [-regexp | -full] [-pattern <pattern>] [-except] [-replies]
- [-network <network>] [-time <secs>] <channels> [<levels>] */
-/* NOTE: -network replaces the old -ircnet flag. */
+ [-time <secs>] <channels> [<levels>] */
static void cmd_ignore(const char *data)
{
GHashTable *optlist;
IGNORE_REC *rec;
- char *patternarg, *chanarg, *mask, *levels, *timestr, *servertag;
+ char *patternarg, *chanarg, *mask, *levels, *timestr;
char **channels;
void *free_arg;
- int new_ignore, msecs;
+ int new_ignore;
if (*data == '\0') {
cmd_ignore_show();
patternarg = g_hash_table_lookup(optlist, "pattern");
chanarg = g_hash_table_lookup(optlist, "channels");
- servertag = g_hash_table_lookup(optlist, "network");
- /* Allow -ircnet for backwards compatibility */
- if (!servertag)
- servertag = g_hash_table_lookup(optlist, "ircnet");
-
+
if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (*levels == '\0') levels = "ALL";
- msecs = 0;
- timestr = g_hash_table_lookup(optlist, "time");
- if (timestr != NULL) {
- if (!parse_time_interval(timestr, &msecs))
- cmd_param_error(CMDERR_INVALID_TIME);
- }
-
if (active_win->active_server != NULL &&
server_ischannel(active_win->active_server, mask)) {
chanarg = mask;
cmd_params_free(free_arg);
return;
}
- rec->servertag = (servertag == NULL || *servertag == '\0') ?
- NULL : g_strdup(servertag);
+
rec->pattern = (patternarg == NULL || *patternarg == '\0') ?
NULL : g_strdup(patternarg);
rec->exception = g_hash_table_lookup(optlist, "except") != NULL;
rec->regexp = g_hash_table_lookup(optlist, "regexp") != NULL;
rec->fullword = g_hash_table_lookup(optlist, "full") != NULL;
rec->replies = g_hash_table_lookup(optlist, "replies") != NULL;
- if (msecs != 0)
- rec->unignore_time = time(NULL)+msecs/1000;
+ timestr = g_hash_table_lookup(optlist, "time");
+ if (timestr != NULL)
+ rec->unignore_time = time(NULL)+atoi(timestr);
if (new_ignore)
ignore_add_rec(rec);
return;
if (*mask == '\0')
- cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+ cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
if (is_numeric(mask, ' ')) {
/* with index number */
signal_add("ignore created", (SIGNAL_FUNC) sig_ignore_created);
signal_add("ignore changed", (SIGNAL_FUNC) sig_ignore_created);
- command_set_options("ignore", "regexp full except replies -network -ircnet -time -pattern -channels");
+ command_set_options("ignore", "regexp full except replies -time -pattern -channels");
}
void fe_ignore_deinit(void)
targetarg = g_hash_table_lookup(optlist, "targets");
if (targetarg != NULL && *targetarg != '\0')
log_add_targets(log, targetarg, servertag);
- else if (servertag != NULL)
- log_add_targets(log, "*", servertag);
}
if (g_hash_table_lookup(optlist, "autoopen"))
GSList *tmp;
GString *str;
char *ret;
- LOG_ITEM_REC *rec = NULL;
g_return_val_if_fail(log != NULL, NULL);
g_return_val_if_fail(log->items != NULL, NULL);
str = g_string_new(NULL);
for (tmp = log->items; tmp != NULL; tmp = tmp->next) {
- rec = tmp->data;
+ LOG_ITEM_REC *rec = tmp->data;
g_string_sprintfa(str, "%s, ", rec->name);
}
g_string_truncate(str, str->len-2);
- if(rec->servertag != NULL)
- g_string_sprintfa(str, " (%s)", rec->servertag);
ret = str->str;
g_string_free(str, FALSE);
autolog_path = settings_get_str("autolog_path");
autolog_level = !settings_get_bool("autolog") ? 0 :
- settings_get_level("autolog_level");
+ level2bits(settings_get_str("autolog_level"));
if (old_autolog && !autolog_level)
autologs_close_all();
settings_add_bool("log", "autolog", FALSE);
settings_add_bool("log", "autolog_colors", FALSE);
settings_add_str("log", "autolog_path", "~/irclogs/$tag/$0.log");
- settings_add_level("log", "autolog_level", "all -crap -clientcrap -ctcps");
+ settings_add_str("log", "autolog_level", "all -crap -clientcrap -ctcps");
settings_add_str("log", "log_theme", "");
autolog_level = 0;
#include "channels.h"
#include "nicklist.h"
#include "ignore.h"
-#include "recode.h"
#include "window-items.h"
#include "fe-queries.h"
#include "printtext.h"
#define ishighalnum(c) ((unsigned char) (c) >= 128 || i_isalnum(c))
-#define isnickchar(a) \
- (i_isalnum(a) || (a) == '`' || (a) == '-' || (a) == '_' || \
- (a) == '[' || (a) == ']' || (a) == '{' || (a) == '}' || \
- (a) == '|' || (a) == '\\' || (a) == '^')
GHashTable *printnicks;
/* check that the beginning marker starts a word, and
that the matching end marker ends a word */
- if ((pos > 0 && bgn[-1] != ' ') || !ishighalnum(bgn[1]))
+ if ((pos > 0 && !i_isspace(bgn[-1])) || !ishighalnum(bgn[1]))
continue;
if ((end = strchr(bgn+1, *bgn)) == NULL)
continue;
use emphasis on them. */
int found;
char c;
- char *end2;
- /* check if _foo_ is a nick */
c = end[1];
end[1] = '\0';
found = nicklist_find(CHANNEL(item), bgn) != NULL;
end[1] = c;
if (found) continue;
-
- /* check if the whole 'word' (e.g. "_foo_^") is a nick
- in "_foo_^ ", end will be the second _, end2 the ^ */
- end2 = end;
- while (isnickchar(end2[1]))
- end2++;
- c = end2[1];
- end2[1] = '\0';
- found = nicklist_find(CHANNEL(item), bgn) != NULL;
- end2[1] = c;
- if (found) continue;
}
/* allow only *word* emphasis, not *multiple words* */
static char *channel_get_nickmode_rec(NICK_REC *nickrec)
{
char *emptystr;
- static char nickmode[2]; /* FIXME: bad */
if (!settings_get_bool("show_nickmode"))
return "";
emptystr = settings_get_bool("show_nickmode_empty") ? " " : "";
- if (nickrec != NULL && nickrec->other) {
- nickmode[0] = nickrec->other;
- nickmode[1] = '\0';
- return nickmode;
- }
-
return nickrec == NULL ? emptystr :
nickrec->op ? "@" :
nickrec->halfop ? "%" :
const char *nickmode, *printnick;
int for_me, print_channel, level;
char *color, *freemsg = NULL;
- HILIGHT_REC *hilight;
/* NOTE: this may return NULL if some channel is just closed with
/WINDOW CLOSE and server still sends the few last messages */
for_me = !settings_get_bool("hilight_nick_matches") ? FALSE :
nick_match_msg(chanrec, msg, server->nick);
- hilight = for_me ? NULL :
+ color = for_me ? NULL :
hilight_match_nick(server, target, nick, address, MSGLEVEL_PUBLIC, msg);
- color = (hilight == NULL) ? NULL : hilight_get_color(hilight);
print_channel = chanrec == NULL ||
!window_item_is_active((WI_ITEM_REC *) chanrec);
print_channel = TRUE;
level = MSGLEVEL_PUBLIC;
- if (for_me)
+ if (for_me || color != NULL)
level |= MSGLEVEL_HILIGHT;
if (settings_get_bool("emphasis"))
if (printnick == NULL)
printnick = nick;
- if (color != NULL) {
- /* highlighted nick */
- TEXT_DEST_REC dest;
- format_create_dest(&dest, server, target, level, NULL);
- hilight_update_text_dest(&dest,hilight);
- if (!print_channel) /* message to active channel in window */
- printformat_dest(&dest, TXT_PUBMSG_HILIGHT, color,
- printnick, msg, nickmode);
- else /* message to not existing/active channel */
- printformat_dest(&dest, TXT_PUBMSG_HILIGHT_CHANNEL,
- color, printnick, target, msg,
- nickmode);
- } else {
- if (!print_channel)
+ if (!print_channel) {
+ /* message to active channel in window */
+ if (color != NULL) {
+ /* highlighted nick */
+ printformat(server, target, level,
+ TXT_PUBMSG_HILIGHT,
+ color, printnick, msg, nickmode);
+ } else {
printformat(server, target, level,
for_me ? TXT_PUBMSG_ME : TXT_PUBMSG,
printnick, msg, nickmode);
- else
+ }
+ } else {
+ /* message to not existing/active channel */
+ if (color != NULL) {
+ /* highlighted nick */
+ printformat(server, target, level,
+ TXT_PUBMSG_HILIGHT_CHANNEL,
+ color, printnick, target, msg, nickmode);
+ } else {
printformat(server, target, level,
for_me ? TXT_PUBMSG_ME_CHANNEL :
TXT_PUBMSG_CHANNEL,
printnick, target, msg, nickmode);
- }
+ }
+ }
- g_free_not_null(freemsg);
+ g_free_not_null(freemsg);
g_free_not_null(color);
}
WINDOW_REC *window;
CHANNEL_REC *channel;
const char *nickmode;
- char *freemsg = NULL, *recoded;
+ char *freemsg = NULL;
int print_channel;
+
channel = channel_find(server, target);
if (channel != NULL)
target = channel->visible_name;
if (settings_get_bool("emphasis"))
msg = freemsg = expand_emphasis((WI_ITEM_REC *) channel, msg);
- /* ugly: recode the sent message back for printing */
- recoded = recode_in(server, msg, target);
-
if (!print_channel) {
printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT,
- TXT_OWN_MSG, server->nick, recoded, nickmode);
+ TXT_OWN_MSG, server->nick, msg, nickmode);
} else {
printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT,
- TXT_OWN_MSG_CHANNEL, server->nick, target, recoded, nickmode);
+ TXT_OWN_MSG_CHANNEL, server->nick, target, msg, nickmode);
}
- g_free(recoded);
g_free_not_null(freemsg);
}
const char *target, const char *origtarget)
{
QUERY_REC *query;
- char *freemsg = NULL, *recoded;
+ char *freemsg = NULL;
g_return_if_fail(server != NULL);
g_return_if_fail(msg != NULL);
+
if (target == NULL) {
/* this should only happen if some special target failed and
we should display some error message. currently the special
if (settings_get_bool("emphasis"))
msg = freemsg = expand_emphasis((WI_ITEM_REC *) query, msg);
- /* ugly: recode the sent message back for printing */
- recoded = recode_in(server, msg, target);
-
printformat(server, target,
MSGLEVEL_MSGS | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT,
query == NULL ? TXT_OWN_MSG_PRIVATE :
- TXT_OWN_MSG_PRIVATE_QUERY, target, recoded, server->nick);
+ TXT_OWN_MSG_PRIVATE_QUERY, target, msg, server->nick);
- g_free(recoded);
g_free_not_null(freemsg);
}
WINDOW_REC *window;
GString *chans;
GSList *tmp, *windows;
- char *print_channel, *recoded;
+ char *print_channel;
int once, count;
if (ignore_check(server, nick, address, NULL, reason, MSGLEVEL_QUITS))
window = window_item_window((WI_ITEM_REC *) rec);
if (g_slist_find(windows, window) == NULL) {
windows = g_slist_append(windows, window);
- recoded = recode_in(server, reason, rec->visible_name);
printformat(server, rec->visible_name,
MSGLEVEL_QUITS,
- TXT_QUIT, nick, address, recoded,
+ TXT_QUIT, nick, address, reason,
rec->visible_name);
- g_free(recoded);
}
}
count++;
display the quit there too */
QUERY_REC *query = query_find(server, nick);
if (query != NULL) {
- recoded = recode_in(server, reason, nick);
printformat(server, nick, MSGLEVEL_QUITS,
- TXT_QUIT, nick, address, recoded, "");
- g_free(recoded);
+ TXT_QUIT, nick, address, reason, "");
}
}
if (once || count == 0) {
if (chans->len > 0)
g_string_truncate(chans, chans->len-1);
- /* at least recode_fallback will be used */
- recoded = recode_in(server, reason, nick);
printformat(server, print_channel, MSGLEVEL_QUITS,
count <= 1 ? TXT_QUIT : TXT_QUIT_ONCE,
- nick, address, recoded, chans->str);
- g_free(recoded);
+ nick, address, reason, chans->str);
}
g_string_free(chans, TRUE);
}
char **list, *name;
int count;
- list = g_new(char *, 2 + 3*g_slist_length(chat_protocols));
+ list = g_new(char *, 2 + 2*g_slist_length(chat_protocols));
list[0] = "fe";
count = 1;
list[count++] = name;
list[count++] = g_strconcat("fe_", name, NULL);
- list[count++] = g_strconcat("fe_common_", name, NULL);
}
list[count] = NULL;
now-rec->last_unread_msg > query_auto_close)
query_destroy(rec);
}
- return 1;
+ return 1;
}
static void sig_message_private(SERVER_REC *server, const char *msg,
static void read_settings(void)
{
- querycreate_level = settings_get_level("autocreate_query_level");
- query_auto_close = settings_get_time("autoclose_query")/1000;
+ querycreate_level = level2bits(settings_get_str("autocreate_query_level"));
+ query_auto_close = settings_get_int("autoclose_query");
if (query_auto_close > 0 && queryclose_tag == -1)
queryclose_tag = g_timeout_add(5000, (GSourceFunc) sig_query_autoclose, NULL);
else if (query_auto_close <= 0 && queryclose_tag != -1) {
void fe_queries_init(void)
{
- settings_add_level("lookandfeel", "autocreate_query_level", "MSGS DCCMSGS");
+ settings_add_str("lookandfeel", "autocreate_query_level", "MSGS DCCMSGS");
settings_add_bool("lookandfeel", "autocreate_own_query", TRUE);
- settings_add_time("lookandfeel", "autoclose_query", "0");
+ settings_add_int("lookandfeel", "autoclose_query", 0);
queryclose_tag = -1;
read_settings();
+++ /dev/null
-/*
- fe-recode.c : irssi
-
- Copyright (C) 1999-2000 Timo Sirainen
-
- 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.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "module.h"
-#include "modules.h"
-#include "module-formats.h"
-#include "commands.h"
-#include "levels.h"
-#include "lib-config/iconfig.h"
-#include "settings.h"
-#include "printtext.h"
-#include "formats.h"
-#include "recode.h"
-
-#ifdef HAVE_NL_LANGINFO
-# include <langinfo.h>
-#endif
-
-#define SLIST_FOREACH(var, head) \
-for ((var) = (head); \
- (var); \
- (var) = g_slist_next((var)))
-
-#ifdef HAVE_GLIB2
-char *recode_fallback = NULL;
-char *recode_out_default = NULL;
-char *term_charset = NULL;
-
-static const char *fe_recode_get_target (WI_ITEM_REC *witem)
-{
- if (witem && (witem->type == module_get_uniq_id_str("WINDOW ITEM TYPE", "QUERY")
- || witem->type == module_get_uniq_id_str("WINDOW ITEM TYPE", "CHANNEL")))
- return window_item_get_target(witem);
-
- printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_CHANNEL_OR_QUERY);
- return NULL;
-}
-
-static int fe_recode_compare_func (CONFIG_NODE *node1, CONFIG_NODE *node2)
-{
- return strcmp(node1->key, node2->key);
-}
-
-/* SYNTAX: RECODE */
-static void fe_recode_cmd (const char *data, SERVER_REC *server, WI_ITEM_REC *witem)
-{
- if (*data)
- command_runsub("recode", data, server, witem);
- else {
- CONFIG_NODE *conversions;
- GSList *tmp;
- GSList *sorted = NULL;
-
- conversions = iconfig_node_traverse("conversions", FALSE);
-
- for (tmp = conversions ? config_node_first(conversions->value) : NULL;
- tmp != NULL;
- tmp = config_node_next(tmp)) {
- CONFIG_NODE *node = tmp->data;
-
- if (node->type == NODE_TYPE_KEY)
- sorted = g_slist_insert_sorted(sorted, node, (GCompareFunc) fe_recode_compare_func);
- }
-
- printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_RECODE_HEADER);
- SLIST_FOREACH(tmp, sorted)
- {
- CONFIG_NODE *node = tmp->data;
- printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_RECODE_LINE, node->key, node->value);
- }
-
- g_slist_free(sorted);
- }
-}
-
-/* SYNTAX: RECODE ADD [[<tag>/]<target>] <charset> */
-static void fe_recode_add_cmd (const char *data, SERVER_REC *server, WI_ITEM_REC *witem)
-{
- const char *first;
- const char *second;
- const char *target;
- const char *charset;
- void *free_arg;
-
- if (! cmd_get_params(data, &free_arg, 2, &first, &second))
- return;
-
- if (! *first)
- cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
-
- if (*second) {
- target = first;
- charset = second;
- } else {
- target = fe_recode_get_target(witem);
- charset = first;
- if (! target)
- goto end;
- }
- if (is_valid_charset(charset)) {
- iconfig_set_str("conversions", target, charset);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONVERSION_ADDED, target, charset);
- } else
- signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_INVALID_CHARSET), charset);
- end:
- cmd_params_free(free_arg);
-}
-
-/* SYNTAX: RECODE REMOVE [<target>] */
-static void fe_recode_remove_cmd (const char *data, SERVER_REC *server, WI_ITEM_REC *witem)
-{
- const char *target;
- void *free_arg;
-
- if (! cmd_get_params(data, &free_arg, 1, &target))
- return;
-
- if (! *target) {
- target = fe_recode_get_target(witem);
- if (! target)
- goto end;
- }
-
- if (iconfig_get_str("conversions", target, NULL) == NULL)
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONVERSION_NOT_FOUND, target);
- else {
- iconfig_set_str("conversions", target, NULL);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONVERSION_REMOVED, target);
- }
-
- end:
- cmd_params_free(free_arg);
-}
-
-static void read_settings(void)
-{
- /* preserve the valid values */
- char *old_term_charset = g_strdup(term_charset);
- char *old_recode_fallback = g_strdup(recode_fallback);
- char *old_recode_out_default = g_strdup(recode_out_default);
-
- if (settings_get_bool("recode_transliterate")) {
- /* check if transliterations are supported in this system */
- if (!is_valid_charset("ASCII")) {
- printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_CONVERSION_NO_TRANSLITS);
- settings_set_bool("recode_transliterate", FALSE);
- }
- }
-
- if (recode_fallback)
- g_free(recode_fallback);
- recode_fallback = g_strdup(settings_get_str("recode_fallback"));
- if (!is_valid_charset(recode_fallback)) {
- signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_INVALID_CHARSET), recode_fallback);
- g_free(recode_fallback);
- recode_fallback = is_valid_charset(old_recode_fallback) ? g_strdup(old_recode_fallback) : "ISO8859-1";
- settings_set_str("recode_fallback", recode_fallback);
- }
-
- if (term_charset)
- g_free(term_charset);
- term_charset = g_strdup(settings_get_str("term_charset"));
- if (!is_valid_charset(term_charset)) {
- g_free(term_charset);
-#if defined (HAVE_NL_LANGINFO) && defined(CODESET)
- term_charset = is_valid_charset(old_term_charset) ? g_strdup(old_term_charset) :
- *nl_langinfo(CODESET) != '\0' ? g_strdup(nl_langinfo(CODESET)) :
- "ISO8859-1";
-#else
- term_charset = is_valid_charset(old_term_charset) ? g_strdup(old_term_charset) : "ISO8859-1";
-#endif
- settings_set_str("term_charset", term_charset);
- /* FIXME: move the check of term_charset into fe-text/term.c
- it breaks the proper term_input_type
- setup and reemitting of the signal is kludgy */
- if (g_strcasecmp(term_charset, old_term_charset) != 0)
- signal_emit("setup changed", 0);
- }
-
- if (recode_out_default)
- g_free(recode_out_default);
- recode_out_default = g_strdup(settings_get_str("recode_out_default_charset"));
- if (recode_out_default != NULL && *recode_out_default != '\0' &&
- !is_valid_charset(recode_out_default)) {
- signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_INVALID_CHARSET), recode_out_default);
- g_free(recode_out_default);
- recode_out_default = is_valid_charset(old_recode_out_default) ? g_strdup(old_recode_out_default) : NULL;
- settings_set_str("recode_out_default_charset", recode_out_default);
- }
-
- g_free(old_term_charset);
- g_free(old_recode_fallback);
- g_free(old_recode_out_default);
-}
-#endif
-
-void fe_recode_init (void)
-{
-/* FIXME: print this is not supported instead */
-#ifdef HAVE_GLIB2
- command_bind("recode", NULL, (SIGNAL_FUNC) fe_recode_cmd);
- command_bind("recode add", NULL, (SIGNAL_FUNC) fe_recode_add_cmd);
- command_bind("recode remove", NULL, (SIGNAL_FUNC) fe_recode_remove_cmd);
- signal_add("setup changed", (SIGNAL_FUNC) read_settings);
- read_settings();
-#endif
-}
-
-void fe_recode_deinit (void)
-{
-/* FIXME: print this is not supported instead */
-#ifdef HAVE_GLIB2
- command_unbind("recode", (SIGNAL_FUNC) fe_recode_cmd);
- command_unbind("recode add", (SIGNAL_FUNC) fe_recode_add_cmd);
- command_unbind("recode remove", (SIGNAL_FUNC) fe_recode_remove_cmd);
- signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
-#endif
-}
+++ /dev/null
-#ifndef __FE_RECODE_H
-#define __FE_RECODE_H
-
-void fe_recode_init (void);
-void fe_recode_deinit (void);
-
-#endif /* __FE_RECODE_H */
if (g_hash_table_lookup(optlist, "ssl"))
rec->use_ssl = TRUE;
- value = g_hash_table_lookup(optlist, "ssl_cert");
- if (value != NULL && *value != '\0')
- rec->ssl_cert = g_strdup(value);
-
- value = g_hash_table_lookup(optlist, "ssl_pkey");
- if (value != NULL && *value != '\0')
- rec->ssl_pkey = g_strdup(value);
-
- if (g_hash_table_lookup(optlist, "ssl_verify"))
- rec->ssl_verify = TRUE;
-
- value = g_hash_table_lookup(optlist, "ssl_cafile");
- if (value != NULL && *value != '\0')
- rec->ssl_cafile = g_strdup(value);
-
- value = g_hash_table_lookup(optlist, "ssl_capath");
- if (value != NULL && *value != '\0')
- rec->ssl_capath = g_strdup(value);
-
- if ((rec->ssl_cafile != NULL && rec->ssl_cafile[0] != '\0')
- || (rec->ssl_capath != NULL && rec->ssl_capath[0] != '\0'))
- rec->ssl_verify = TRUE;
-
- if ((rec->ssl_cert != NULL && rec->ssl_cert[0] != '\0') || rec->ssl_verify == TRUE)
- rec->use_ssl = TRUE;
-
if (g_hash_table_lookup(optlist, "auto")) rec->autoconnect = TRUE;
if (g_hash_table_lookup(optlist, "noauto")) rec->autoconnect = FALSE;
if (g_hash_table_lookup(optlist, "proxy")) rec->no_proxy = FALSE;
else
net_ip2host(ip, ipaddr);
- printformat(server, NULL, MSGLEVEL_CLIENTNOTICE,
- !server->connrec->reconnecting ?
- TXT_CONNECTING : TXT_RECONNECTING,
+ printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONNECTING,
server->connrec->address, ipaddr, server->connrec->port);
}
command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove);
command_bind_first("server", NULL, (SIGNAL_FUNC) server_command);
command_bind_first("disconnect", NULL, (SIGNAL_FUNC) server_command);
- command_set_options("server add", "4 6 ssl +ssl_cert +ssl_pkey ssl_verify +ssl_cafile +ssl_capath auto noauto proxy noproxy -host -port");
+ command_set_options("server add", "4 6 ssl auto noauto proxy noproxy -host -port");
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting);
value = value_int;
break;
case SETTING_TYPE_STRING:
- case SETTING_TYPE_TIME:
- case SETTING_TYPE_LEVEL:
- case SETTING_TYPE_SIZE:
value = settings_get_str(rec->key);
break;
default:
clear = g_hash_table_lookup(optlist, "clear") != NULL;
set_default = g_hash_table_lookup(optlist, "default") != NULL;
- if (*key == '\0')
- clear = set_default = FALSE;
-
last_section = ""; found = 0;
sets = settings_get_sorted();
for (tmp = sets; tmp != NULL; tmp = tmp->next) {
SETTINGS_REC *rec = tmp->data;
- if (((clear || set_default || *value != '\0') && g_strcasecmp(rec->key, key) != 0) ||
+ if (((clear || *value != '\0') && g_strcasecmp(rec->key, key) != 0) ||
(*value == '\0' && *key != '\0' && stristr(rec->key, key) == NULL))
continue;
if (clear)
settings_set_bool(key, FALSE);
else if (set_default)
- settings_set_bool(key, rec->default_value.v_bool);
+ settings_set_bool(key, GPOINTER_TO_INT(rec->def));
else
set_boolean(key, value);
break;
case SETTING_TYPE_INT:
settings_set_int(key, clear ? 0 :
- set_default ? rec->default_value.v_int :
+ set_default ? GPOINTER_TO_INT(rec->def) :
atoi(value));
break;
case SETTING_TYPE_STRING:
settings_set_str(key, clear ? "" :
- set_default ? rec->default_value.v_string :
+ set_default ? rec->def :
value);
break;
- case SETTING_TYPE_TIME:
- if (!settings_set_time(key, clear ? "0" :
- set_default ? rec->default_value.v_string : value))
- printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_INVALID_TIME);
- break;
- case SETTING_TYPE_LEVEL:
- if (!settings_set_level(key, clear ? "" :
- set_default ? rec->default_value.v_string : value))
- printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_INVALID_LEVEL);
- break;
- case SETTING_TYPE_SIZE:
- if (!settings_set_size(key, clear ? "0" :
- set_default ? rec->default_value.v_string : value))
- printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_INVALID_SIZE);
- break;
}
signal_emit("setup changed", 0);
}
rec = g_new0(WINDOW_REC, 1);
rec->refnum = window_get_new_refnum();
- rec->level = settings_get_level("window_default_level");
+ rec->level = level2bits(settings_get_str("window_default_level"));
windows = g_slist_prepend(windows, rec);
signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic));
/* match, but if multiple windows have the same level
we could be choosing a bad one here, eg.
name=nick1 would get nick2's query instead of
- generic msgs window.
-
- And check for prefixed !channel name --Borys */
- if (g_strcasecmp(name, item->visible_name) == 0 ||
- g_strcasecmp(name, (char *) window_item_get_target((WI_ITEM_REC *) item)) == 0)
+ generic msgs window. */
+ if (g_strcasecmp(name, item->visible_name) == 0)
return namewindow;
}
}
settings_add_bool("lookandfeel", "window_auto_change", FALSE);
settings_add_bool("lookandfeel", "windows_auto_renumber", TRUE);
settings_add_bool("lookandfeel", "window_check_level_first", FALSE);
- settings_add_level("lookandfeel", "window_default_level", "NONE");
+ settings_add_str("lookandfeel", "window_default_level", "NONE");
read_settings();
signal_add("server looking", (SIGNAL_FUNC) sig_server_connected);
#include "formats.h"
#include "themes.h"
#include "translation.h"
-#ifdef HAVE_GLIB2
-#include "recode.h"
-#include "utf8.h"
-#endif
static const char *format_backs = "04261537";
static const char *format_fores = "kbgcrmyw";
int set;
if (flags == NULL) {
- /* flags are being ignored - skip the code */
+ /* flags are being ignored - skip the code */
while (**format != ']')
(*format)++;
- return;
+ return;
}
- set = TRUE;
+ set = TRUE;
(*format)++;
while (**format != ']' && **format != '\0') {
if (**format == '+')
(*format)++;
}
g_string_append_c(out, ',');
- (*format)--;
+ (*format)--;
break;
case 's':
case 'S':
break;
case 't':
*flags |= set ? PRINT_FLAG_SET_TIMESTAMP :
- PRINT_FLAG_UNSET_TIMESTAMP;
- break;
+ PRINT_FLAG_UNSET_TIMESTAMP;
+ break;
case 'T':
*flags |= set ? PRINT_FLAG_SET_SERVERTAG :
- PRINT_FLAG_UNSET_SERVERTAG;
- break;
+ PRINT_FLAG_UNSET_SERVERTAG;
+ break;
}
(*format)++;
{
char *p, fmt;
- fmt = **format;
+ fmt = **format;
switch (fmt) {
case '{':
case '}':
case '%':
- /* escaped char */
+ /* escaped char */
g_string_append_c(out, fmt);
break;
case 'U':
g_string_append_c(out, FORMAT_STYLE_DEFAULTS);
break;
case '>':
- /* clear to end of line */
+ /* clear to end of line */
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_CLRTOEOL);
break;
break;
case '[':
/* code */
- format_expand_code(format, out, flags);
+ format_expand_code(format, out, flags);
break;
default:
/* check if it's a background color */
{
int num, len, bufpos;
- g_return_if_fail(format->params < arglist_size);
+ g_return_if_fail(format->params < arglist_size);
bufpos = 0;
- arglist[format->params] = NULL;
+ arglist[format->params] = NULL;
for (num = 0; num < format->params; num++) {
switch (format->paramtypes[num]) {
case FORMAT_STRING:
arglist[num] = buffer+bufpos;
len = g_snprintf(buffer+bufpos, buffer_size-bufpos,
"%ld", l);
- bufpos += len+1;
+ bufpos += len+1;
break;
}
case FORMAT_FLOAT: {
}
}
}
+
void format_create_dest(TEXT_DEST_REC *dest,
void *server, const char *target,
int level, WINDOW_REC *window)
{
- format_create_dest_tag(dest, server, NULL, target, level, window);
+ format_create_dest_tag(dest, server, NULL, target, level, window);
}
void format_create_dest_tag(TEXT_DEST_REC *dest, void *server,
const char *server_tag, const char *target,
int level, WINDOW_REC *window)
{
- memset(dest, 0, sizeof(TEXT_DEST_REC));
+ memset(dest, 0, sizeof(TEXT_DEST_REC));
dest->server = server;
dest->server_tag = server != NULL ? SERVER(server)->tag : server_tag;
dest->window = window != NULL ? window :
window_find_closest(server, target, level);
}
-#ifdef HAVE_GLIB2
-static int advance (char const **str, gboolean utf8)
-{
- if (utf8) {
- gunichar c;
-
- c = g_utf8_get_char(*str);
- *str = g_utf8_next_char(*str);
- return utf8_width(c);
- } else {
- *str += 1;
-
- return 1;
- }
-}
-#endif
/* Return length of text part in string (ie. without % codes) */
int format_get_length(const char *str)
{
- GString *tmp;
+ GString *tmp;
int len;
-#ifdef HAVE_GLIB2
- gboolean utf8;
-#endif
- g_return_val_if_fail(str != NULL, 0);
+ g_return_val_if_fail(str != NULL, 0);
-#ifdef HAVE_GLIB2
- utf8 = is_utf8() && g_utf8_validate(str, -1, NULL);
-#endif
-
- tmp = g_string_new(NULL);
+ tmp = g_string_new(NULL);
len = 0;
while (*str != '\0') {
if (*str == '%' && str[1] != '\0') {
str++;
if (*str != '%' &&
format_expand_styles(tmp, &str, NULL)) {
- str++;
+ str++;
continue;
}
if (*str != '%')
len++;
}
-#ifdef HAVE_GLIB2
- len += advance(&str, utf8);
-#else
- len++;
+
+ len++;
str++;
-#endif
}
g_string_free(tmp, TRUE);
- return len;
+ return len;
}
/* Return how many characters in `str' must be skipped before `len'
{
GString *tmp;
const char *start;
-#ifdef HAVE_GLIB2
- gboolean utf8;
-#endif
- g_return_val_if_fail(str != NULL, 0);
- g_return_val_if_fail(len >= 0, 0);
-
-#ifdef HAVE_GLIB2
- utf8 = is_utf8() && g_utf8_validate(str, -1, NULL);
-#endif
-
- start = str;
- tmp = g_string_new(NULL);
+
+ g_return_val_if_fail(str != NULL, 0);
+ g_return_val_if_fail(len >= 0, 0);
+
+ start = str;
+ tmp = g_string_new(NULL);
while (*str != '\0' && len > 0) {
if (*str == '%' && str[1] != '\0') {
str++;
if (*str != '%' &&
format_expand_styles(tmp, &str, NULL)) {
- str++;
+ str++;
continue;
}
/* %% or unknown %code, written as-is */
if (*str != '%') {
if (--len == 0)
- break;
+ break;
}
}
-#ifdef HAVE_GLIB2
- len -= advance(&str, utf8);
-#else
- len--;
+ len--;
str++;
-#endif
}
g_string_free(tmp, TRUE);
- return (int) (str-start);
+ return (int) (str-start);
}
char *format_string_expand(const char *text, int *flags)
GString *out;
char code, *ret;
- g_return_val_if_fail(text != NULL, NULL);
+ g_return_val_if_fail(text != NULL, NULL);
out = g_string_new(NULL);
if (ret != NULL) {
/* string shouldn't end with \003 or it could
mess up the next one or two characters */
- int diff;
+ int diff;
int len = strlen(ret);
while (len > 0 && ret[len-1] == 3) len--;
diff = strlen(ret)-len;
if (module_theme == NULL)
return NULL;
- text = module_theme->expanded_formats[formatnum];
+ text = module_theme->expanded_formats[formatnum];
return format_get_text_args(dest, text, args);
}
ret = str->str;
g_string_free(str, FALSE);
- return ret;
+ return ret;
}
char *format_add_lineend(const char *text, const char *linestart)
ret = str->str;
g_string_free(str, FALSE);
- return ret;
+ return ret;
}
#define LINE_START_IRSSI_LEVEL \
{
int format;
- /* check for flags if we want to override defaults */
+ /* check for flags if we want to override defaults */
if (dest->flags & PRINT_FLAG_UNSET_LINE_START)
return NULL;
if (dest->flags & PRINT_FLAG_SET_LINE_START)
format = TXT_LINE_START;
- else if (dest->flags & PRINT_FLAG_SET_LINE_START_IRSSI)
+ else if (dest->flags & PRINT_FLAG_SET_LINE_START_IRSSI)
format = TXT_LINE_START_IRSSI;
else {
- /* use defaults */
+ /* use defaults */
if (dest->level & LINE_START_IRSSI_LEVEL)
format = TXT_LINE_START_IRSSI;
else if ((dest->level & NOT_LINE_START_LEVEL) == 0)
static char *get_timestamp(THEME_REC *theme, TEXT_DEST_REC *dest, time_t t)
{
- char *format, str[256];
+ char *format, str[256];
struct tm *tm;
int diff;
if ((timestamp_level & dest->level) == 0)
return NULL;
- /* check for flags if we want to override defaults */
+ /* check for flags if we want to override defaults */
if (dest->flags & PRINT_FLAG_UNSET_TIMESTAMP)
return NULL;
if ((dest->flags & PRINT_FLAG_SET_TIMESTAMP) == 0 &&
(dest->level & (MSGLEVEL_NEVER|MSGLEVEL_LASTLOG)) != 0)
- return NULL;
+ return NULL;
if (timestamp_timeout > 0) {
format = format_get_text_theme(theme, MODULE_NAME, dest,
TXT_TIMESTAMP);
if (strftime(str, sizeof(str), format, tm) <= 0)
- str[0] = '\0';
+ str[0] = '\0';
g_free(format);
return g_strdup(str);
}
int count = 0;
if (dest->server_tag == NULL || hide_server_tags)
- return NULL;
+ return NULL;
- /* check for flags if we want to override defaults */
+ /* check for flags if we want to override defaults */
if (dest->flags & PRINT_FLAG_UNSET_SERVERTAG)
return NULL;
}
if (count < 2)
- return NULL;
+ return NULL;
}
return format_get_text_theme(theme, MODULE_NAME, dest,
/* foreground color */
if (**str != ',') {
fg = **str-'0';
- (*str)++;
+ (*str)++;
if (i_isdigit(**str)) {
fg = fg*10 + (**str-'0');
(*str)++;
{
const char *start = str;
- if (last_color_pos != NULL)
+ if (last_color_pos != NULL)
*last_color_pos = -1;
if (last_color_len != NULL)
*last_color_len = -1;
if (last_color_pos != NULL)
*last_color_pos = (int) (str-start);
- str++;
+ str++;
get_mirc_color(&str, NULL, NULL);
- if (last_color_len != NULL)
+ if (last_color_len != NULL)
*last_color_len = (int) (str-mircstart);
} else if (*str == 4 && str[1] != '\0') {
if (str[1] < FORMAT_STYLE_SPECIAL && str[2] != '\0') {
if (last_color_pos != NULL)
*last_color_pos = (int) (str-start);
- if (last_color_len != NULL)
- *last_color_len = 3;
+ if (last_color_len != NULL)
+ *last_color_len = 3;
str++;
} else if (str[1] == FORMAT_STYLE_DEFAULTS) {
if (last_color_pos != NULL)
*last_color_pos = (int) (str-start);
- if (last_color_len != NULL)
- *last_color_len = 2;
+ if (last_color_len != NULL)
+ *last_color_len = 2;
}
- str += 2;
+ str += 2;
} else {
if (!IS_COLOR_CODE(*str)) {
if (len-- == 0)
char *strip_codes(const char *input)
{
- const char *p;
- char *str, *out;
-
- out = str = g_strdup(input);
- for (p = input; *p != '\0'; p++) {
- if (*p == 3) {
- p++;
-
- /* mirc color */
- get_mirc_color(&p, NULL, NULL);
- p--;
- continue;
- }
-
- if (*p == 4 && p[1] != '\0') {
- if (p[1] >= FORMAT_STYLE_SPECIAL) {
- p++;
- continue;
- }
-
- /* irssi color */
- if (p[2] != '\0') {
- p += 2;
- continue;
- }
+ const char *p;
+ char *str, *out;
+
+ out = str = g_strdup(input);
+ for (p = input; *p != '\0'; p++) {
+ if (*p == 3) {
+ p++;
+
+ /* mirc color */
+ get_mirc_color(&p, NULL, NULL);
+ p--;
+ continue;
+ }
+
+ if (*p == 4 && p[1] != '\0') {
+ if (p[1] >= FORMAT_STYLE_SPECIAL) {
+ p++;
+ continue;
+ }
+
+ /* irssi color */
+ if (p[2] != '\0') {
+ p += 2;
+ continue;
+ }
}
if (*p == 27 && p[1] != '\0') {
- p++;
+ p++;
p = get_ansi_color(current_theme, p, NULL, NULL, NULL);
p--;
} else if (!IS_COLOR_CODE(*p))
- *out++ = *p;
- }
+ *out++ = *p;
+ }
- *out = '\0';
- return str;
+ *out = '\0';
+ return str;
}
/* send a fully parsed text string for GUI to print */
void format_send_to_gui(TEXT_DEST_REC *dest, const char *text)
{
- THEME_REC *theme;
+ THEME_REC *theme;
char *dup, *str, *ptr, type;
int fgcolor, bgcolor;
int flags;
- theme = dest->window != NULL && dest->window->theme != NULL ?
+ theme = dest->window != NULL && dest->window->theme != NULL ?
dest->window->theme : current_theme;
dup = str = g_strdup(text);
flags = 0; fgcolor = theme->default_color; bgcolor = -1;
while (*str != '\0') {
- type = '\0';
+ type = '\0';
for (ptr = str; *ptr != '\0'; ptr++) {
if (IS_COLOR_CODE(*ptr) || *ptr == '\n') {
type = *ptr;
if (type == 7) {
/* bell */
if (settings_get_bool("bell_beeps"))
- signal_emit("beep", 0);
+ signal_emit("beep", 0);
} else if (type == 4 && *ptr == FORMAT_STYLE_CLRTOEOL) {
- /* clear to end of line */
+ /* clear to end of line */
flags |= GUI_PRINT_FLAG_CLRTOEOL;
}
if (*str != '\0' || (flags & GUI_PRINT_FLAG_CLRTOEOL)) {
- /* send the text to gui handler */
+ /* send the text to gui handler */
signal_emit_id(signal_gui_print_text, 6, dest->window,
GINT_TO_POINTER(fgcolor),
GINT_TO_POINTER(bgcolor),
while (*ptr != ',' && *ptr != '\0')
ptr++;
if (*ptr != '\0') *ptr++ = '\0';
- ptr--;
+ ptr--;
signal_emit_id(signal_gui_print_text, 6,
dest->window, NULL, NULL,
GINT_TO_POINTER(GUI_PRINT_FLAG_INDENT_FUNC),
- start, dest);
+ str, start, dest);
break;
}
case FORMAT_STYLE_DEFAULTS:
- fgcolor = theme->default_color;
+ fgcolor = theme->default_color;
bgcolor = -1;
flags &= GUI_PRINT_FLAG_INDENT|GUI_PRINT_FLAG_MONOSPACE;
break;
case FORMAT_STYLE_CLRTOEOL:
- break;
+ break;
default:
if (*ptr != FORMAT_COLOR_NOCHANGE) {
fgcolor = (unsigned char) *ptr-'0';
flags &= ~GUI_PRINT_FLAG_BLINK;
else {
/* blink */
- bgcolor -= 8;
- flags |= GUI_PRINT_FLAG_BLINK;
+ bgcolor -= 8;
+ flags |= GUI_PRINT_FLAG_BLINK;
}
}
}
static void read_settings(void)
{
timestamp_level = settings_get_bool("timestamps") ? MSGLEVEL_ALL : 0;
- if (timestamp_level > 0)
- timestamp_level = settings_get_level("timestamp_level");
- timestamp_timeout = settings_get_time("timestamp_timeout")/1000;
+ if (timestamp_level > 0) {
+ timestamp_level =
+ level2bits(settings_get_str("timestamp_level"));
+ }
+ timestamp_timeout = settings_get_int("timestamp_timeout");
hide_server_tags = settings_get_bool("hide_server_tags");
hide_text_style = settings_get_bool("hide_text_style");
void hilight_create(HILIGHT_REC *rec)
{
if (g_slist_find(hilights, rec) != NULL) {
- hilight_remove_config(rec);
hilights = g_slist_remove(hilights, rec);
+ hilight_remove_config(rec);
}
hilights = g_slist_append(hilights, rec);
settings_get_str("hilight_act_color"));
}
-char *hilight_get_color(HILIGHT_REC *rec)
+static char *hilight_get_color(HILIGHT_REC *rec)
{
const char *color;
return format_string_expand(color, NULL);
}
-void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec)
+static void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec)
{
dest->level |= MSGLEVEL_HILIGHT;
dest->hilight_color = hilight_get_act_color(rec);
}
-static void hilight_print(int index, HILIGHT_REC *rec);
-
static void sig_print_text(TEXT_DEST_REC *dest, const char *text,
const char *stripped)
{
signal_stop();
}
-HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel,
+char *hilight_match_nick(SERVER_REC *server, const char *channel,
const char *nick, const char *address,
int level, const char *msg)
{
HILIGHT_REC *rec;
+ char *color;
rec = hilight_match(server, channel, nick, address,
level, msg, NULL, NULL);
- return (rec == NULL || !rec->nick) ? NULL : rec;
+ color = rec == NULL || !rec->nick ? NULL :
+ hilight_get_color(rec);
+
+ return color;
}
static void read_hilight_config(void)
#endif
}
+ if (options->len > 1) g_string_truncate(options, options->len-1);
+
if (rec->priority != 0)
g_string_sprintfa(options, "-priority %d ", rec->priority);
if (rec->color != NULL)
g_strjoinv(",", rec->channels);
levelstr = rec->level == 0 ? NULL :
bits2level(rec->level);
- if (levelstr != NULL)
- levelstr = g_strconcat(levelstr, " ", NULL);
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
TXT_HILIGHT_LINE, index, rec->text,
chans != NULL ? chans : "",
static void read_settings(void)
{
- default_hilight_level = settings_get_level("hilight_level");
+ default_hilight_level = level2bits(settings_get_str("hilight_level"));
}
void hilight_text_init(void)
{
settings_add_str("lookandfeel", "hilight_color", "%Y");
settings_add_str("lookandfeel", "hilight_act_color", "%M");
- settings_add_level("lookandfeel", "hilight_level", "PUBLIC DCCMSGS");
+ settings_add_str("lookandfeel", "hilight_level", "PUBLIC DCCMSGS");
read_settings();
# include <regex.h>
#endif
-#include "formats.h"
-
typedef struct _HILIGHT_REC HILIGHT_REC;
struct _HILIGHT_REC {
int level, const char *str,
int *match_beg, int *match_end);
-HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel,
+char *hilight_match_nick(SERVER_REC *server, const char *channel,
const char *nick, const char *address,
int level, const char *msg);
-
-char *hilight_get_color(HILIGHT_REC *rec);
-void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec);
void hilight_create(HILIGHT_REC *rec);
void hilight_remove(HILIGHT_REC *rec);
return 0;
}
+/* Returns TRUE if key press was consumed. Control characters should be sent
+ as "^@" .. "^_" instead of #0..#31 chars, #127 should be sent as ^? */
int key_pressed(KEYBOARD_REC *keyboard, const char *key)
{
KEY_REC *rec;
if (keyboard->key_state == NULL && key[1] == '\0' &&
!used_keys[(int) (unsigned char) key[0]]) {
/* fast check - key not used */
- return -1;
+ return FALSE;
}
first_key = keyboard->key_state == NULL;
/* unknown key combo, eat the invalid key
unless it was the first key pressed */
g_free(combo);
- return first_key ? -1 : 1;
+ return !first_key;
}
if (g_tree_lookup(key_states, combo) != rec) {
/* key combo continues.. */
keyboard->key_state = combo;
- return 0;
+ return TRUE;
}
/* finished key combo, execute */
consumed = key_emit_signal(keyboard, rec);
/* never consume non-control characters */
- return consumed ? 1 : -1;
+ return consumed;
}
void keyboard_entry_redirect(SIGNAL_FUNC func, const char *entry,
KEYBOARD_REC *keyboard_create(void *gui_data);
/* Destroys a keyboard */
void keyboard_destroy(KEYBOARD_REC *keyboard);
-/* Returns 1 if key press was consumed, -1 if not, 0 if it's beginning of a
- key combo. Control characters should be sent as "^@" .. "^_" instead of
- #0..#31 chars, #127 should be sent as ^? */
+/* Returns TRUE if key press was consumed. Control characters should be sent
+ as "^@" .. "^_" instead of #0..#31 chars, #127 should be sent as ^? */
int key_pressed(KEYBOARD_REC *keyboard, const char *key);
void key_bind(const char *id, const char *description,
{ "looking_up", "Looking up {server $0}", 1, { 0 } },
{ "connecting", "Connecting to {server $0} [$1] port {hilight $2}", 3, { 0, 0, 1 } },
- { "reconnecting", "Reconnecting to {server $0} [$1] port {hilight $2} - use /RMRECONNS to abort", 3, { 0, 0, 1 } },
{ "connection_established", "Connection to {server $0} established", 1, { 0 } },
{ "cant_connect", "Unable to connect server {server $0} port {hilight $1} {reason $2}", 3, { 0, 1, 0 } },
{ "connection_lost", "Connection lost to {server $0}", 1, { 0 } },
{ "chan_not_synced", "Channel not fully synchronized yet, try again after a while", 0 },
{ "illegal_proto", "Command isn't designed for the chat protocol of the active server", 0 },
{ "not_good_idea", "Doing this is not a good idea. Add -YES option to command if you really mean it", 0 },
- { "invalid_time", "Invalid timestamp", 0 },
- { "invalid_level", "Invalid message level", 0 },
- { "invalid_size", "Invalid size", 0 },
- { "invalid_charset", "Invalid charset: $0", 1, { 0 } },
- { "eval_max_recurse", "/eval hit maximum recursion limit", 0 },
- { "program_not_found", "Could not find file or file is not executable", 0 },
/* ---- */
{ NULL, "Themes", 0 },
{ "ignore_line", "%#$[-4]0 $1: $2 $3 $4", 4, { 1, 0, 0, 0 } },
{ "ignore_footer", "", 0 },
- /* ---- */
- { NULL, "Recode", 0 },
-
- { "not_channel_or_query", "The current window is not a channel or query window", 0 },
- { "conversion_added", "Added {hilight $0}/{hilight $1} to conversion database", 2, { FORMAT_STRING, FORMAT_STRING } },
- { "conversion_removed", "Removed {hilight $0} from conversion database", 1, { FORMAT_STRING } },
- { "conversion_not_found", "{hilight $0} not found in conversion database", 1, { FORMAT_STRING } },
- { "conversion_no_translits", "Transliterations not supported in this system", 0 },
- { "recode_header", "%#Target Character set", 0 },
- { "recode_line", "%#%|$[!30]0 $1", 2, { FORMAT_STRING, FORMAT_STRING } },
-
/* ---- */
{ NULL, "Misc", 0 },
{ "unknown_chat_protocol", "Unknown chat protocol: $0", 1, { 0 } },
- { "unknown_chatnet", "Unknown chat network: $0 (create it with /NETWORK ADD)", 1, { 0 } },
+ { "unknown_chatnet", "Unknown chat network: $0 (create it with /IRCNET ADD)", 1, { 0 } },
{ "not_toggle", "Value must be either ON, OFF or TOGGLE", 0 },
{ "perl_error", "Perl error: $0", 1, { 0 } },
{ "bind_header", "%#Key Action", 0 },
TXT_LOOKING_UP,
TXT_CONNECTING,
- TXT_RECONNECTING,
- TXT_CONNECTION_ESTABLISHED,
+ TXT_CONNECTION_ESTABLISHED,
TXT_CANT_CONNECT,
TXT_CONNECTION_LOST,
TXT_LAG_DISCONNECTED,
TXT_CHAN_NOT_SYNCED,
TXT_ILLEGAL_PROTO,
TXT_NOT_GOOD_IDEA,
- TXT_INVALID_TIME,
- TXT_INVALID_LEVEL,
- TXT_INVALID_SIZE,
- TXT_INVALID_CHARSET,
- TXT_EVAL_MAX_RECURSE,
- TXT_PROGRAM_NOT_FOUND,
TXT_FILL_11,
TXT_FILL_13,
- TXT_NOT_CHANNEL_OR_QUERY,
- TXT_CONVERSION_ADDED,
- TXT_CONVERSION_REMOVED,
- TXT_CONVERSION_NOT_FOUND,
- TXT_CONVERSION_NO_TRANSLITS,
- TXT_RECODE_HEADER,
- TXT_RECODE_LINE,
-
- TXT_FILL_14,
-
TXT_UNKNOWN_CHAT_PROTOCOL,
TXT_UNKNOWN_CHATNET,
TXT_NOT_TOGGLE,
#define MODULE_NAME "fe-common/core"
-typedef guint32 unichar;
typedef struct {
time_t time;
char *nick;
g_return_if_fail(dest != NULL);
g_return_if_fail(text != NULL);
-
+
theme = window_get_theme(dest->window);
tmp = format_get_level_tag(theme, dest);
str = !theme->info_eol ? format_add_linestart(text, tmp) :
format_add_lineend(text, tmp);
g_free_not_null(tmp);
-
+
/* send both the formatted + stripped (for logging etc.) */
stripped = strip_codes(str);
signal_emit_id(signal_print_text, 3, dest, str, stripped);
static void read_settings(void)
{
- beep_msg_level = settings_get_level("beep_msg_level");
+ beep_msg_level = level2bits(settings_get_str("beep_msg_level"));
beep_when_away = settings_get_bool("beep_when_away");
beep_when_window_active = settings_get_bool("beep_when_window_active");
}
static int init_finished;
static char *init_errors;
-static THEME_REC *internal_theme;
-static int theme_read(THEME_REC *theme, const char *path);
+static int theme_read(THEME_REC *theme, const char *path, const char *data);
THEME_REC *theme_create(const char *path, const char *name)
{
int braces = 1; /* we start with one brace opened */
str = g_string_new(NULL);
- while (**format != '\0' && braces != 0) {
+ while ((**format != '\0') && (braces)) {
if (**format == '{')
braces++;
else if (**format == '}')
continue;
}
- if (braces == 0) {
+ if (!braces) {
(*format)++;
break;
}
themes_remove_module(module);
}
-void theme_set_default_abstract(const char *key, const char *value)
-{
- gpointer oldkey, oldvalue;
-
- if (g_hash_table_lookup_extended(internal_theme->abstracts, key,
- &oldkey, &oldvalue)) {
- /* new values override old ones */
- g_hash_table_remove(internal_theme->abstracts, oldkey);
- g_free(oldkey);
- g_free(oldvalue);
- }
-
- g_hash_table_insert(internal_theme->abstracts,
- g_strdup(key), g_strdup(value));
-}
-
static THEME_REC *theme_find(const char *name)
{
GSList *tmp;
oldtheme = theme;
theme = theme_create(fname, name);
theme->last_modify = statbuf.st_mtime;
- if (!theme_read(theme, theme->path)) {
+ if (!theme_read(theme, theme->path, NULL)) {
/* error reading .theme file */
theme_destroy(theme);
theme = NULL;
if (oldtheme != NULL && theme != NULL) {
theme_destroy(oldtheme);
- if (current_theme == oldtheme)
- current_theme = theme;
window_themes_update();
}
return theme;
}
-static void copy_abstract_hash(char *key, char *value, GHashTable *dest)
-{
- g_hash_table_insert(dest, g_strdup(key), g_strdup(value));
-}
-
-static void theme_copy_abstracts(THEME_REC *dest, THEME_REC *src)
-{
- g_hash_table_foreach(src->abstracts, (GHFunc) copy_abstract_hash,
- dest->abstracts);
-}
-
typedef struct {
THEME_REC *theme;
CONFIG_REC *config;
}
}
-static int theme_read(THEME_REC *theme, const char *path)
+static int theme_read(THEME_REC *theme, const char *path, const char *data)
{
CONFIG_REC *config;
THEME_READ_REC rec;
char *str;
- config = config_open(path, -1) ;
+ config = config_open(data == NULL ? path : NULL, -1) ;
if (config == NULL) {
/* didn't exist or no access? */
str = g_strdup_printf("Error reading theme file %s: %s",
return FALSE;
}
- if (path == NULL)
- config_parse_data(config, default_theme, "internal");
+ if (data != NULL)
+ config_parse_data(config, data, "internal");
else
config_parse(config);
theme->default_color = -1;
theme_read_replaces(config, theme);
- if (path != NULL)
- theme_copy_abstracts(theme, internal_theme);
+ if (data == NULL) {
+ /* get the default abstracts from default theme. */
+ CONFIG_REC *default_config;
+
+ default_config = config_open(NULL, -1);
+ config_parse_data(default_config, default_theme, "internal");
+ theme_read_abstracts(default_config, theme);
+ config_close(default_config);
+ }
theme_read_abstracts(config, theme);
rec.theme = theme;
ptr = line;
words = 0;
- if (*ptr != '\0') {
- do {
- ptr++;
- words++;
- ptr = strchr(ptr, ' ');
- } while (ptr != NULL);
- }
+ do {
+ ptr++;
+
+ words++;
+ ptr = strchr(ptr, ' ');
+ } while (ptr != NULL);
if (words > 2)
return;
change_theme(theme, TRUE);
}
-void themes_reload(void)
+static void themes_read(void)
{
GSList *refs;
char *fname;
fname = g_strdup_printf("%s/default.theme", get_irssi_dir());
current_theme = theme_create(fname, "default");
current_theme->default_color = -1;
- theme_read(current_theme, NULL);
+ theme_read(current_theme, NULL, default_theme);
g_free(fname);
}
}
}
-static THEME_REC *read_internal_theme(void)
-{
- CONFIG_REC *config;
- THEME_REC *theme;
-
- theme = theme_create("internal", "_internal");
-
- config = config_open(NULL, -1);
- config_parse_data(config, default_theme, "internal");
- theme_read_abstracts(config, theme);
- config_close(config);
-
- return theme;
-}
-
void themes_init(void)
{
settings_add_str("lookandfeel", "theme", "default");
default_formats = g_hash_table_new((GHashFunc) g_str_hash,
(GCompareFunc) g_str_equal);
- internal_theme = read_internal_theme();
init_finished = FALSE;
init_errors = NULL;
themes = NULL;
- themes_reload();
+ themes_read();
command_bind("format", NULL, (SIGNAL_FUNC) cmd_format);
command_bind("save", NULL, (SIGNAL_FUNC) cmd_save);
signal_add("complete command format", (SIGNAL_FUNC) sig_complete_format);
signal_add("irssi init finished", (SIGNAL_FUNC) sig_print_errors);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
- signal_add("setup reread", (SIGNAL_FUNC) themes_reload);
+ signal_add("setup reread", (SIGNAL_FUNC) themes_read);
command_set_options("format", "delete reset");
command_set_options("save", "formats");
{
while (themes != NULL)
theme_destroy(themes->data);
- theme_destroy(internal_theme);
g_hash_table_destroy(default_formats);
default_formats = NULL;
signal_remove("complete command format", (SIGNAL_FUNC) sig_complete_format);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_print_errors);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
- signal_remove("setup reread", (SIGNAL_FUNC) themes_reload);
+ signal_remove("setup reread", (SIGNAL_FUNC) themes_read);
}
void theme_register_module(const char *module, FORMAT_REC *formats);
void theme_unregister_module(const char *module);
-void theme_set_default_abstract(const char *key, const char *value);
-
#define EXPAND_FLAG_IGNORE_REPLACES 0x01 /* don't use the character replaces when expanding */
#define EXPAND_FLAG_IGNORE_EMPTY 0x02 /* if abstract's argument is empty, or the argument is a $variable that is empty, don't try to expand it (ie. {xx }, but not {xx}) */
#define EXPAND_FLAG_RECURSIVE_MASK 0x0f
char *save_last_fg, char *save_last_bg,
int flags);
-void themes_reload(void);
-
void themes_init(void);
void themes_deinit(void);
+++ /dev/null
-#ifndef __UTF8_H
-#define __UTF8_H
-
-/* Returns -2 = invalid, -1 = need more data, otherwise unichar. */
-int get_utf8_char(const unsigned char **ptr, int len, unichar *chr_r);
-
-/* Returns length of UTF8 string */
-int strlen_utf8(const char *str);
-
-/* UTF-8 -> unichar string. The NUL is copied as well. */
-void utf8_to_utf16(const char *str, unichar *out);
-
-/* unichar -> UTF-8 string. outbuf must be at least 6 chars long.
- Returns outbuf string length. */
-int utf16_char_to_utf8(unichar c, char *outbuf);
-
-/* unichar -> UTF-8 string. The NUL is copied as well.
- Make sure out is at least 6 x length of str. */
-void utf16_to_utf8(const unichar *str, char *out);
-
-/* unichar -> UTF-8 string with position transformed. The NUL is copied as well.
- Make sure out is at least 6 x length of str. */
-void utf16_to_utf8_with_pos(const unichar *str, int spos, char *out, int *opos);
-
-/* XXX I didn't check the encoding range of big5+. This is standard big5. */
-#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */
-#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */
-#define is_big5_lo(lo) ((is_big5_los(lo) || is_big5_lox(lo)))
-#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
-#define is_big5(hi,lo) (is_big5_hi(hi) && is_big5_lo(lo))
-
-/* Returns width for character (0-2). */
-int utf8_width(unichar c);
-
-#endif
static void sig_hilight_text(TEXT_DEST_REC *dest, const char *msg)
{
WI_ITEM_REC *item;
- char *tagtarget;
int data_level;
if (dest->window == active_win || (dest->level & hide_level))
DATA_LEVEL_MSG : DATA_LEVEL_TEXT;
}
- if ((dest->level & MSGLEVEL_HILIGHT) == 0 && dest->target != NULL) {
- /* check for both target and tag/target */
- if (hide_target_activity(data_level, dest->target))
- return;
-
- tagtarget = dest->server_tag == NULL ? NULL :
- g_strdup_printf("%s/%s", dest->server_tag,
- dest->target);
- if (hide_target_activity(data_level, tagtarget)) {
- g_free(tagtarget);
- return;
- }
- g_free(tagtarget);
- }
+ if ((dest->level & MSGLEVEL_HILIGHT) == 0 &&
+ hide_target_activity(data_level, dest->target))
+ return;
if (dest->target != NULL) {
item = window_item_find(dest->server, dest->target);
g_strsplit(targets, " ", -1);
hide_level = MSGLEVEL_NEVER | MSGLEVEL_NO_ACT |
- settings_get_level("activity_hide_level");
- msg_level = settings_get_level("activity_msg_level");
+ level2bits(settings_get_str("activity_hide_level"));
+ msg_level = level2bits(settings_get_str("activity_msg_level"));
hilight_level = MSGLEVEL_HILIGHT |
- settings_get_level("activity_hilight_level");
+ level2bits(settings_get_str("activity_hilight_level"));
}
void window_activity_init(void)
{
settings_add_str("lookandfeel", "activity_hide_targets", "");
- settings_add_level("lookandfeel", "activity_hide_level", "");
- settings_add_level("lookandfeel", "activity_msg_level", "PUBLIC");
- settings_add_level("lookandfeel", "activity_hilight_level", "MSGS DCCMSGS");
+ settings_add_str("lookandfeel", "activity_hide_level", "");
+ settings_add_str("lookandfeel", "activity_msg_level", "PUBLIC");
+ settings_add_str("lookandfeel", "activity_hilight_level", "MSGS DCCMSGS");
read_settings();
signal_add("print text", (SIGNAL_FUNC) sig_hilight_text);
window_change_server(window, server);
}
-/* SYNTAX: WINDOW CLOSE [<first> [<last>]] */
+/* SYNTAX: WINDOW CLOSE [<first> [<last>] */
static void cmd_window_close(const char *data)
{
GSList *tmp, *destroys;
{
WI_ITEM_REC *item;
GSList *tmp;
- void *free_arg;
- char *target;
-
- if (!cmd_get_params(data, &free_arg, 1, &target))
- return;
- if (is_numeric(target, '\0')) {
+ if (is_numeric(data, '\0')) {
/* change to specified number */
- tmp = g_slist_nth(active_win->items, atoi(target)-1);
+ tmp = g_slist_nth(active_win->items, atoi(data)-1);
item = tmp == NULL ? NULL : tmp->data;
} else {
- item = window_item_find_window(active_win, server, target);
+ item = window_item_find_window(active_win, server, data);
}
if (item != NULL)
window_item_set_active(active_win, item);
-
- cmd_params_free(free_arg);
}
/* SYNTAX: WINDOW ITEM MOVE <number>|<name> */
WINDOW_BIND_REC *rec = window_bind_add(window, tag, name);
rec->sticky = TRUE;
} else if (g_strcasecmp(type, "QUERY") == 0 && chat_type != NULL) {
- CHAT_PROTOCOL_REC *protocol;
/* create query immediately */
signal_add("query created",
(SIGNAL_FUNC) signal_query_created_curwin);
restore_win = window;
-
- protocol = chat_protocol_find(chat_type);
- if (protocol->query_create != NULL)
- protocol->query_create(tag, name, TRUE);
- else {
- QUERY_REC *query;
-
- query = g_new0(QUERY_REC, 1);
- query->chat_type = chat_protocol_lookup(chat_type);
- query->name = g_strdup(name);
- query->server_tag = g_strdup(tag);
- query_init(query, TRUE);
- }
+ chat_protocol_find(chat_type)->query_create(tag, name, TRUE);
signal_remove("query created",
(SIGNAL_FUNC) signal_query_created_curwin);
-I$(SILC_INCLUDE)/lib/silcske \
-I$(SILC_INCLUDE)/lib/silcsim \
-I$(SILC_INCLUDE)/lib/silcutil \
- -I$(SILC_INCLUDE)/lib/silcapputil \
- -I$(SILC_INCLUDE)/lib/silcvcard \
- -I$(SILC_INCLUDE)/lib/silcskr \
- -I$(SILC_INCLUDE)/lib/silcsftp \
- -I$(SILC_INCLUDE)/lib/silcasn1 \
- -I$(SILC_INCLUDE)/lib/silchttp \
-I$(SILC_INCLUDE)/lib/silcclient \
-I$(SILC_INCLUDE)/lib/silcmath/gmp \
-I$(SILC_INCLUDE)/lib/trq
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
int verified)
{
CHANNEL_REC *chanrec;
- NICK_REC *nickrec = NULL; /* we cheat here a little to keep the limit of
+ NICK_REC *nickrec = NULL; /* we cheat here a little to keep the limit of
6 parameters to a signal handler ... */
const char *nickmode, *printnick;
int for_me, print_channel, level;
for_me = !settings_get_bool("hilight_nick_matches") ? FALSE :
nick_match_msg(chanrec, msg, server->nick);
color = for_me ? NULL :
- (char *)hilight_match_nick(server, target, nick, address, MSGLEVEL_PUBLIC,
- msg);
+ hilight_match_nick(server, target, nick, address, MSGLEVEL_PUBLIC,
+ msg);
print_channel = chanrec == NULL ||
!window_item_is_active((WI_ITEM_REC *) chanrec);
g_free_not_null(freemsg);
}
-static void sig_message_own_action_all(SERVER_REC *server,
+static void sig_message_own_action_all(SERVER_REC *server,
const char *msg, const char *target,
bool is_channel, bool is_signed)
{
printformat(server, target,
MSGLEVEL_ACTIONS | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT |
(is_channel ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS),
- item != NULL ?
+ item != NULL ?
(is_signed ? SILCTXT_OWN_ACTION_SIGNED : SILCTXT_OWN_ACTION) :
(is_signed ? SILCTXT_OWN_ACTION_TARGET_SIGNED :
SILCTXT_OWN_ACTION_TARGET),
msg = freemsg = expand_emphasis(item, msg);
if (is_channel) {
- /* channel action */
+ /* channel action */
if (window_item_is_active(item)) {
/* message to active channel in window */
printformat(server, target, level,
- VERIFIED_MSG2(verified, SILCTXT_ACTION_PUBLIC),
+ VERIFIED_MSG2(verified, SILCTXT_ACTION_PUBLIC),
nick, target, msg);
} else {
/* message to not existing/active channel */
sig_message_action_all(server, msg, nick, address, target, FALSE, verified);
}
-static void sig_message_own_notice_all(SERVER_REC *server,
+static void sig_message_own_notice_all(SERVER_REC *server,
const char *msg, const char *target,
bool is_signed)
{
return;
if (is_channel) {
- /* channel notice */
+ /* channel notice */
printformat(server, target, MSGLEVEL_NOTICES,
- VERIFIED_MSG2(verified, SILCTXT_NOTICE_PUBLIC),
+ VERIFIED_MSG2(verified, SILCTXT_NOTICE_PUBLIC),
nick, target, msg);
} else {
/* private notice */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2003 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
{ "notice_private_signed", "{notice {flag_signed}$0{pvtnotice_host $1}}$2", 3, { 0, 0, 0 } },
{ "notice_private_unknown", "{notice {flag_unknown}$0{pvtnotice_host $1}}$2", 3, { 0, 0, 0 } },
{ "notice_private_failed", "{notice {flag_failed}$0{pvtnotice_host $1}}$2", 3, { 0, 0, 0 } },
- { "many", "There are now $0 {channick_hilight $1}'s on this channel", 2, { 0, 0 } },
- { "user_appears", "{channick_hilight $0} will appear as {channick_hilight $1}", 2, { 0, 0 } },
-
/* WHOIS, WHOWAS and USERS (alias WHO) messages */
{ NULL, "Who Queries", 0 },
{ "private_key_list_nick", "Private message keys with {nick $0}%: Client Cipher Key", 1, { 0 } },
{ "key_agreement", "Requesting key agreement with {nick $0}", 1, { 0 } },
{ "key_agreement_request", "{nick $0} wants to perform key agreement", 1, { 0 } },
- { "key_agreement_request_host", "{nick $0} wants to perform key agreement on {nickhost $1} port {hilight $2} ($3)", 4, { 0, 0, 0, 0 } },
+ { "key_agreement_request_host", "{nick $0} wants to perform key agreement on {nickhost $1} port {hilight $2}", 3, { 0, 0, 0 } },
{ "key_agreement_negotiate", "Starting key agreement with {nick $0}", 1, { 0 } },
- { "key_agreement_privmsg", "Private messages with {nick $0} are now protected with private key", 1, { 0 } },
+ { "key_agreement_privmsg", "The private messages with {nick $0} are now protected with private key", 1, { 0 } },
{ "key_agreement_ok", "Key agreement completed successfully with {nick $0}", 1, { 0 } },
{ "key_agreement_error", "Error occurred during key agreement with {nick $0}", 1, { 0 } },
{ "key_agreement_failure", "Key agreement failed with {nick $0}", 1, { 0 } },
{ "attr_geolocation", " Geolocation : $0", 1, { 0 } },
{ "attr_device_info", " Device Info : $0", 1, { 0 } },
{ "attr_public_keys", " Public keys : $0", 1, { 0 } },
- { "attr_timezone", " Timezone (GMT) : $0", 1, { 0 } },
+ { "attr_timezone", " Timezone : $0", 1, { 0 } },
{ "attr_timezone_allow", " Sending timezone : $0", 1, { 0 } },
{ "attr_user_sign_verified", " User's signature : verified successfully", 0 },
{ "attr_user_sign_failed", " User's signature : {hilight signature failed}", 0 },
{ "lstkey_file", "Public key file : $0", 1, { 0 } },
{ "lstkey_alg", "Algorithm : $0", 1, { 0 } },
- { "lstkey_ver", "Version : $0", 1, { 0 } },
{ "lstkey_bits", "Key length (bits) : $0", 1, { 1 } },
{ "lstkey_rn", "Real name : $0", 1, { 0 } },
{ "lstkey_un", "Username : $0", 1, { 0 } },
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2003, 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2003 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
SILCTXT_NOTICE_PRIVATE_SIGNED,
SILCTXT_NOTICE_PRIVATE_UNKNOWN,
SILCTXT_NOTICE_PRIVATE_FAILED,
- SILCTXT_CHANNEL_MANY_NICKS,
- SILCTXT_CHANNEL_USER_APPEARS,
+
SILCTXT_FILL_2,
SILCTXT_ATTR_SAVED,
SILCTXT_FILL_7,
-
+
SILCTXT_LISTKEY_PUB_FILE,
SILCTXT_LISTKEY_PUB_ALG,
- SILCTXT_LISTKEY_PUB_VER,
SILCTXT_LISTKEY_PUB_BITS,
SILCTXT_LISTKEY_PUB_RN,
SILCTXT_LISTKEY_PUB_UN,
#undef PACKAGE
#undef VERSION
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "silc-core.h"
curses_sources = \
term-curses.c
-cuix_sources = \
- cuix-api.c \
- cuix-lib.c \
- cuix.c
-
if NEED_TPARM
use_tparm_sources = $(tparm_sources)
endif
use_term_sources = $(terminfo_sources)
endif
-if USE_CUIX
-use_term_sources += $(cuix_sources)
-silc_LDADD += -lform -lpanel -lmenu
-INCLUDES += -I$(top_srcdir)/src/irc/core
-endif
-
silc_SOURCES = \
gui-entry.c \
gui-expandos.c \
textbuffer-commands.c \
textbuffer-reformat.c \
textbuffer-view.c \
+ utf8.c \
silc.c \
module-formats.c
textbuffer.h \
textbuffer-view.h \
textbuffer-reformat.h \
+ utf8.h \
module.h \
module-formats.h
+++ /dev/null
-#include "module.h"
-#include "settings.h"
-#include "term.h"
-#include "gui-windows.h"
-#include <stdarg.h>
-#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
-# include <ncurses.h>
-#else
-# include <curses.h>
-#endif
-#include <form.h>
-#include <panel.h>
-#include <menu.h>
-
-
-#include "cuix-api.h"
-
-#define INIT_ENTRIES 8
-#define X0_OFFSET 4
-#define Y0_OFFSET 2
-#define Y_OFFSET 1
-#define CUIX_FIELD_WIDTH 16
-
-object *create_object (char *title, int type, void **entries)
-{
- object *obj;
- void **new_entries;
- int i;
-
- obj = g_malloc (sizeof(object));
- if (!obj) {
- return NULL;
- }
- obj->type = type;
- obj->title = title;
- if (!entries) {
- new_entries = g_new0 (void *, INIT_ENTRIES);
- obj->entries = new_entries;
- obj->alloced = INIT_ENTRIES;
- obj->last = 0;
- } else {
- for (i = 0; ((entry **)entries)[i]; i++);
- obj->alloced = i;
- obj->last = i;
- obj->entries = entries;
- }
- return obj;
-}
-
-
-object *create_menu (char *title)
-{
- return create_object (title, CUIX_MENU, NULL);
-}
-
-
-object *create_form (char *title)
-{
- return create_object (title, CUIX_FORM, NULL);
-}
-
-
-/* entries must be NULL terminated */
-object *create_list (char *title, entry **entries)
-{
- return create_object (title, CUIX_LIST, (void **)entries);
-}
-
-entry *create_entry (char *label, int type, action_fn_type action)
-{
- entry *entry;
-
- entry = g_malloc (sizeof(object));
- if (!entry) {
- return NULL;
- }
- entry->type = type;
- entry->data = label;
- entry->action = action;
- return entry;
-}
-
-entry *create_menuentry (char *label, action_fn_type action)
-{
- return create_entry (label, CUIX_MENUENTRY, action);
-}
-
-entry *create_label (char *label)
-{
- return create_entry (label, CUIX_LABEL, NULL);
-}
-
-
-entry *create_field (char *label, action_fn_type action)
-{
- return create_entry (label, CUIX_FIELD, action);
-}
-
-
-
-/* Adds child at the last position of father->entries */
-void attach_entry (object *father, void *child)
-{
- void **entries;
- int i;
-
- /* Check that we have enough space in father->entries, otherwise alloc
- * twice more than previously */
- if (father->last >= father->alloced) {
- entries = g_new0 (void *,2 * father->alloced);
- if (!entries) {
- fprintf (stderr, "Problem with memory allocation, quitting now...\n");
- exit (1);
- }
- for (i = 0; i < father->alloced; i++) {
- entries[i] = father->entries[i];
- }
- g_free (father->entries);
- father->entries = entries;
- father->alloced *= 2;
- }
- father->entries[father->last++] = child;
-}
-
-
-/* Adds a submenu to father */
-void attach_submenu (object *father, object *child)
-{
-
- /* Check that both are really menus */
- if (father->type != CUIX_MENU || child->type != CUIX_MENU) {
- fprintf (stderr, "Typing error, trying to add %p (%d) as child of"
- "%p (%d)\n", father, father->type, child, child->type);
- exit (1);
- }
- attach_entry (father, (void *)child);
-}
-
-
-/* Returns the maximum width occupied by labels */
-int get_labels_width (object *obj)
-{
- int i;
- unsigned int w = 0;
- entry *e;
- object *o;
-
- for (i = 0; i < obj->last; i++) {
- e = (entry *)obj->entries[i];
- if (e->type == CUIX_LABEL || e->type == CUIX_MENUENTRY) {
- w = (w > strlen (e->data)) ? w : strlen (e->data);
- }
- if (e->type == CUIX_MENU) {
- o = (object *)obj->entries[i];
- w = (w > strlen (o->title)) ? w : strlen (o->title);
- }
-
- }
- w += 2 * X0_OFFSET;
- return (int)w;
-}
-
-
-/* Puts in x and y the coordinates to center an object of size objw and objh
- * in the window win */
-void get_center (WINDOW *win, int objh, int objw, int *y, int *x)
-{
- int begx, begy, maxx, maxy, w, h;
- getbegyx (win, begy, begx);
- getmaxyx (win, maxy, maxx);
- w = maxx - begx;
- h = maxy - begy;
- *x = (w - objw) / 2 + begx;
- *y = (h - objh) / 2 + begy;
- if (*x < 0)
- *x = 0;
- if (*y < 0)
- *y = 0;
-}
-
-
-
-void display_object (object *obj)
-{
- WINDOW *subwin;
- FORM *form;
- MENU *menu;
- FIELD **fields;
- ITEM **items, *cur_item;
- object *o;
- entry *e;
- char *result;
- int i, x, y, w, h;
- int ch;
- p_main = new_panel(root_window->win);
-
- if (obj->type >= CUIX_LABEL) {
- fprintf (stderr, "Trying to display an entry %p (%d), terminating...\n",
- obj, obj->type);
- exit (1);
- }
-
- switch (obj->type) {
- case CUIX_LIST:
- w = get_labels_width (obj);
- h = Y_OFFSET * obj->last + 2 * Y0_OFFSET;
- get_center (root_window->win, h, w, &y, &x);
- cuix_win = newwin (h, w, y, x);
- box (cuix_win, 0, 0);
- p_cuix = new_panel(cuix_win);
- x = X0_OFFSET;
- y = Y0_OFFSET;
-
- for (i = 0; i < obj->last; i++) {
- e = (entry *)obj->entries[i];
- if (e->type != CUIX_LABEL) {
- fprintf (stderr, "Non-label entry in a list.\n");
- exit (1);
- }
- wmove (cuix_win,y,x);
- waddstr (cuix_win,e->data);
- y += Y_OFFSET;
- x = X0_OFFSET;
- }
- top_panel (p_cuix);
- update_panels();
- doupdate();
- wgetch(cuix_win);
- /* refresh (); */
- /* wrefresh (cuix_win); */
- break;
-
- case CUIX_FORM:
- w = get_labels_width (obj);
- w = (w > CUIX_FIELD_WIDTH + 2 * X0_OFFSET) ?
- w : CUIX_FIELD_WIDTH + 2 * X0_OFFSET;
- h = Y_OFFSET * obj->last + 2 * Y0_OFFSET;
- fields = g_new0 (FIELD *, obj->last + 1);
- for (i = 0; i < obj->last; i++) {
- e = (entry *)obj->entries[i];
- fields[i] = new_field (1, w,
- Y0_OFFSET + i * Y_OFFSET, X0_OFFSET, 0, 0);
- if (e->type == CUIX_LABEL) {
- field_opts_off (fields[i], O_ACTIVE);
- field_opts_off (fields[i], O_EDIT);
- set_field_back (fields[i], A_BOLD);
- }
- set_field_buffer (fields[i], 0, e->data);
- }
- fields[obj->last] = NULL;
- form = new_form (fields);
- scale_form (form, &h, &w);
- h += Y0_OFFSET;
- w += 2 * X0_OFFSET;
- get_center (root_window->win, h, w, &y, &x);
- cuix_win = newwin (h, w, y, x);
- keypad (cuix_win, TRUE);
- nonl ();
- set_form_win (form, cuix_win);
- set_form_sub (form, derwin(cuix_win, w, h, X0_OFFSET, Y0_OFFSET));
- post_form (form);
- box (cuix_win, 0, 0);
- p_cuix = new_panel (cuix_win);
- top_panel (p_cuix);
- while((ch = wgetch(cuix_win)) != '\n' && ch != '\r' && ch != 27 /* ESC */) {
- switch(ch) {
- case KEY_DOWN:
- /* Go to next field */
- form_driver(form, REQ_NEXT_FIELD);
- /* Go to the end of the present buffer */
- /* Leaves nicely at the last character */
- form_driver(form, REQ_END_LINE);
- break;
- case KEY_UP:
- /* Go to previous field */
- form_driver(form, REQ_PREV_FIELD);
- form_driver(form, REQ_END_LINE);
- break;
- case KEY_BACKSPACE:
- form_driver(form, REQ_PREV_CHAR);
- form_driver(form, REQ_DEL_CHAR);
- break;
- case KEY_LEFT:
- form_driver(form, REQ_PREV_CHAR);
- break;
- case KEY_RIGHT:
- form_driver(form, REQ_NEXT_CHAR);
- break;
- default:
- /* If this is a normal character, it gets */
- /* Printed */
- form_driver(form, ch);
- break;
- }
- }
- form_driver (form, REQ_VALIDATION);
- if (ch != 27) {
- for (i = 0; i < obj->last; i++) {
- e = (entry *)obj->entries[i];
- if (e->type == CUIX_FIELD) {
- result = field_buffer(fields[i],0);
- e->action (result);
- }
- }
- }
- for (i = 0; i < obj->last; i++) {
- free_field (fields[i]);
- }
- g_free (fields);
- unpost_form (form);
-
- break;
-
- case CUIX_MENU:
- w = get_labels_width (obj);
- w = (w > CUIX_FIELD_WIDTH + 2 * X0_OFFSET) ?
- w : CUIX_FIELD_WIDTH + 2 * X0_OFFSET;
- h = Y_OFFSET * obj->last + 2 * Y0_OFFSET;
- items = g_new0 (ITEM *, obj->last + 1);
- for (i = 0; i < obj->last; i++) {
- e = (entry *)obj->entries[i];
- o = (object *)obj->entries[i];
- if (e->type == CUIX_MENUENTRY) {
- items[i] = new_item (e->data, "");
- set_item_userptr (items[i], (void*)e);
- } else {
- if (e->type == CUIX_LABEL) {
- items[i] = new_item (e->data, "");
- item_opts_off (items[i], O_SELECTABLE);
- } else {
- items[i] = new_item (o->title, " (SUB) ");
- set_item_userptr (items[i], (void*)o);
- }
- }
- }
- items[obj->last] = NULL;
- menu = new_menu (items);
- set_menu_mark (menu, " * ");
- scale_menu (menu, &h, &w);
- h += 4 * Y0_OFFSET;
- w += 4 * X0_OFFSET;
- get_center (root_window->win, h, w, &y, &x);
- cuix_win = newwin (h, w, y, x);
- keypad (cuix_win, TRUE);
- nonl ();
- set_menu_win (menu, cuix_win);
- subwin = derwin (cuix_win,
- h - 2 * Y0_OFFSET, w - 2 * X0_OFFSET, Y0_OFFSET, X0_OFFSET);
- set_menu_sub (menu, subwin);
- box (cuix_win, 0, 0);
- post_menu (menu);
- p_cuix = new_panel (cuix_win);
- top_panel (p_cuix);
- while((ch = wgetch(cuix_win)) != 27 /* ESC */) {
- switch(ch) {
- case KEY_DOWN:
- menu_driver(menu, REQ_DOWN_ITEM);
- break;
- case KEY_UP:
- menu_driver(menu, REQ_UP_ITEM);
- break;
- case '\n':
- case '\r':
- cur_item = current_item(menu);
- e = (entry *)item_userptr(cur_item);
- o = (object *)item_userptr(cur_item);
- if (e->type == CUIX_MENUENTRY)
- {
- e->action ("");
- } else {
- display_object (o);
- }
- goto end;
- break;
- default:
- break;
- }
- }
-end:
- for (i = 0; i < obj->last; i++) {
- free_item (items[i]);
- }
- g_free (items);
- unpost_menu (menu);
- }
-}
+++ /dev/null
-#ifndef __CUIX_API_H
-#define __CUIX_API_H
-
-#include "term-curses.h"
-
-#define MAX_FIELD_SIZE 64
-
-WINDOW *cuix_win;
-PANEL *p_main;
-PANEL *p_cuix;
-
-enum objtype {
- /* For objects */
- CUIX_MENU,
- CUIX_FORM,
- CUIX_LIST,
- /* For entries */
- /* NB: LABEL must stay the first entry, as it is used to test if we have
- * an object or an entry */
- CUIX_LABEL,
- CUIX_FIELD,
- CUIX_MENUENTRY
-};
-
-
-
-/* This is the type of the action to be executed when the entry has been
- * successfully selected (in case of a menuentry) or filled (in case of a
- * field). */
-typedef int(*action_fn_type)(char *);
-
-
-typedef struct entry {
- int type;
- char *data; /* contains label or submenu title */
- action_fn_type action;
-} entry;
-
-
-typedef struct object {
- int type;
- char *title;
- void **entries;
- int alloced; /* defines the current size of entries */
- int last; /* index of the first non-alloced entry */
-} object;
-
-
-/* Object definitions */
-
-object *create_menu (char *title);
-object *create_form (char *title);
-/* entries must be NULL terminated */
-object *create_list (char *title, entry **entries);
-
-
-entry *create_menuentry (char *label, action_fn_type action);
-entry *create_label (char *label);
-entry *create_field (char *label, action_fn_type action);
-
-void attach_submenu (object *father, object *child);
-void attach_entry (object *father, void *child);
-
-void display_object (object *obj);
-
-void my_menu(void);
-
-#endif /* __CUIX_API_H */
+++ /dev/null
-#include "module.h"
-#include "settings.h"
-#include "cuix-lib.h"
-#include "signals.h"
-#include "irc.h"
-#include "irc-channels.h"
-#include "mode-lists.h"
-#include "gui-windows.h"
-
-
-int do_nothing (char *foo)
-{
- (void)foo;
- return 0;
-}
-
-
-void display_message (char *message)
-{
- object *list;
- entry *text, *entries[2];
-
- text = create_label (message);
- entries[0] = text;
- entries[1] = NULL;
- list = create_list ("Message", entries);
- display_object (list);
-}
-
-
-int change_nick (char *nick)
-{
- SERVER_REC *server;
- WI_ITEM_REC *wiitem;
- if (active_win == NULL) {
- server = NULL;
- wiitem = NULL;
- } else {
- server = active_win->active_server != NULL ?
- active_win->active_server : active_win->connect_server;
- wiitem = active_win->active;
- }
- signal_emit("command nick", 3, nick, server, wiitem);
- return 0;
-}
-
-
-
-int show_banlist (char *nothing)
-{
- GSList *tmp;
- IRC_CHANNEL_REC *chan = IRC_CHANNEL(active_win->active);
- BAN_REC *ban;
- object *list;
- entry *entry, **entries;
- unsigned int size, i;
- GString **baninfo;
-
- if (!chan) {
- display_message ("This is not a channel");
- return 1;
- }
- if (!chan->banlist) {
- display_message ("No bans set");
- return 0;
- }
-
- size = (unsigned int) g_slist_length (chan->banlist);
- entries = g_new0 (struct entry *, size + 1);
- baninfo = g_new0 (GString *, size);
-
- for (tmp = chan->banlist, i = 0; tmp; tmp = tmp->next, i++) {
- ban = tmp->data;
- baninfo[i] = g_string_new (NULL);
- g_string_sprintf (baninfo[i], "%s set by %s %d seconds ago", ban->ban, ban->setby, (int)(time(NULL)-ban->time));
- entry = create_label (baninfo[i]->str);
- entries[i] = entry;
- }
-
- list = create_list ("Bans", entries);
- display_object (list);
- for (i = 0; i < size; i++) {
- g_string_free (baninfo[i], FALSE);
- }
- g_free (entries);
- g_free (baninfo);
-
- return 0;
-}
-
-
-int change_nick_form (char *nothing) {
- object *form;
- entry *question, *answer;
- (void)nothing;
-
- form = create_form ("True!");
- question = create_label ("Enter your new nick");
- answer = create_field ("", change_nick);
- attach_entry (form, question);
- attach_entry (form, answer);
- display_object (form);
- return 0;
-}
-
-
-int about_list (char *nothing)
-{
- (void)nothing;
-
- display_message ("(c) irssi; See http://www.irssi.org.");
- return 0;
-}
-
-
-
-
-int home_menu (char *nothing)
-{
- /* Objects declaration */
- object *root_menu;
- entry *about, *banlist, *nick;
- (void)nothing;
-
- /* Objects initialisation */
- root_menu = create_menu ("My root menu");
- banlist = create_menuentry ("Banlist", show_banlist);
- nick = create_menuentry ("Change nick", change_nick_form);
- about = create_menuentry ("About", about_list);
-
- /* Layout */
- attach_entry (root_menu, (void *)banlist);
- attach_entry (root_menu, (void *)nick);
- attach_entry (root_menu, (void *)about);
-
- /* Declare that the object is ready to be displayed and do it */
- display_object (root_menu);
- return 0;
-}
+++ /dev/null
-#ifndef __CUIX_LIB_H
-#define __CUIX_LIB_H
-
-#include "cuix-api.h"
-
-int home_menu (char *);
-
-
-#endif /* __CUIX_LIB_H */
+++ /dev/null
-#include "module.h"
-#include "settings.h"
-#include "cuix-api.h"
-#include "cuix-lib.h"
-#include "cuix.h"
-#include "term.h"
-#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
-# include <ncurses.h>
-#else
-# include <curses.h>
-#endif
-
-
-void cuix_destroy (void)
-{
- if (cuix_win) {
- del_panel (p_cuix);
- delwin(cuix_win);
- }
- cuix_win = NULL;
- cuix_active = 0;
- update_panels ();
- doupdate();
- term_refresh (root_window);
- irssi_redraw ();
-}
-
-void cuix_create(void)
-{
- home_menu (NULL);
- cuix_destroy ();
-}
-
-void cuix_refresh (void)
-{
- update_panels ();
-}
-
-
+++ /dev/null
-#ifndef __CUIX_TRY_H
-#define __CUIX_TRY_H
-
-int cuix_active;
-
-void cuix_create (void);
-void cuix_destroy (void);
-void cuix_refresh (void);
-
-
-#endif /* __CUIX_TRY_H */
g_free(entry);
}
-/* big5 functions */
-#define big5_width(ch) ((ch)>0xff ? 2:1)
-
-void unichars_to_big5(const unichar *str, char *out)
-{
- for (; *str != '\0'; str++) {
- if (*str > 0xff)
- *out++ = (*str >> 8) & 0xff;
- *out++ = *str & 0xff;
- }
- *out = '\0';
-}
-
-int strlen_big5(const unsigned char *str)
-{
- int len=0;
-
- if (term_type != TERM_TYPE_BIG5)
- return strlen(str);
-
- while (*str != '\0') {
- if (is_big5(str[0], str[1]))
- str++;
- len++;
- str++;
- }
- return len;
-}
-
-void unichars_to_big5_with_pos(const unichar *str, int spos, char *out, int *opos)
-{
- const unichar *sstart = str;
- char *ostart = out;
-
- *opos = 0;
- while(*str != '\0')
- {
- if(*str > 0xff)
- *out ++ = (*str >> 8) & 0xff;
- *out ++ = *str & 0xff;
- str ++;
- if(str - sstart == spos)
- *opos = out - ostart;
- }
- *out = '\0';
-}
-
-void big5_to_unichars(const char *str, unichar *out)
-{
- const unsigned char *p = (const unsigned char *) str;
-
- while (*p != '\0') {
- if (is_big5(p[0], p[1])) {
- *out++ = p[0] << 8 | p[1];
- p += 2;
- } else {
- *out++ = *p++;
- }
- }
- *out = '\0';
-}
-
-/* ----------------------------- */
-
-static int pos2scrpos(GUI_ENTRY_REC *entry, int pos)
-{
- unichar *p;
- int xpos = 0;
-
- for (p = entry->text; p - entry->text < pos; p++) {
- if (term_type == TERM_TYPE_BIG5)
- xpos += big5_width(*p);
- else if (entry->utf8)
- xpos += utf8_width(*p);
- else
- xpos++;
- }
- return xpos;
-}
-
-static int scrpos2pos(GUI_ENTRY_REC *entry, int pos)
-{
- int i, width, xpos;
-
- for (i = 0, xpos = 0; entry->text[i]; i++) {
- unichar *p = entry->text+i;
-
- if (term_type == TERM_TYPE_BIG5)
- width = big5_width(*p);
- else if (entry->utf8)
- width = utf8_width(*p);
- else
- width = 1;
-
- if (xpos + width > pos)
- break;
- xpos += width;
- }
-
- if (xpos == pos)
- return i;
- else
- return i-1;
-}
-
/* Fixes the cursor position in screen */
static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry)
{
int old_scrstart;
- /* assume prompt len == prompt scrlen */
- int start = pos2scrpos(entry, entry->scrstart);
- int now = pos2scrpos(entry, entry->pos);
-
- old_scrstart = entry->scrstart;
- if (now-start < entry->width - 2 - entry->promptlen && now-start > 0)
- entry->scrpos = now-start;
- else if (now < entry->width - 1 - entry->promptlen) {
+ old_scrstart = entry->scrstart;
+ if (entry->pos - entry->scrstart < entry->width-2 - entry->promptlen &&
+ entry->pos - entry->scrstart > 0) {
+ entry->scrpos = entry->pos - entry->scrstart;
+ } else if (entry->pos < entry->width-1 - entry->promptlen) {
entry->scrstart = 0;
- entry->scrpos = now;
+ entry->scrpos = entry->pos;
} else {
- entry->scrstart = scrpos2pos(entry, now-(entry->width -
- entry->promptlen)*2/3);
- start = pos2scrpos(entry, entry->scrstart);
- entry->scrpos = now - start;
+ entry->scrpos = (entry->width - entry->promptlen)*2/3;
+ entry->scrstart = entry->pos - entry->scrpos;
}
if (old_scrstart != entry->scrstart)
const unichar *p;
int xpos, end_xpos;
- xpos = entry->xpos + entry->promptlen +
- pos2scrpos(entry, pos + entry->scrstart) -
- pos2scrpos(entry, entry->scrstart);
+ xpos = entry->xpos + entry->promptlen + pos;
end_xpos = entry->xpos + entry->width;
-
if (xpos > end_xpos)
return;
p = entry->scrstart + pos < entry->text_len ?
entry->text + entry->scrstart + pos : empty_str;
for (; *p != '\0'; p++) {
- if (entry->hidden)
- xpos++;
- else if (term_type == TERM_TYPE_BIG5)
- xpos += big5_width(*p);
- else if (entry->utf8)
- xpos += utf8_width(*p);
- else
- xpos++;
-
+ xpos += utf8_width(*p);
if (xpos > end_xpos)
break;
}
/* clear the rest of the input line */
- if (end_xpos == term_width-1)
+ if (end_xpos == term_width)
term_clrtoeol(root_window);
else {
while (xpos < end_xpos) {
if (entry->utf8)
utf16_to_utf8(entry->text, buf);
else {
- if (term_type == TERM_TYPE_BIG5)
- unichars_to_big5(entry->text, buf);
- else
- for (i = 0; i <= entry->text_len; i++)
- buf[i] = entry->text[i];
- }
- return buf;
-}
-
-char *gui_entry_get_text_and_pos(GUI_ENTRY_REC *entry, int *pos)
-{
- char *buf;
- int i;
-
- g_return_val_if_fail(entry != NULL, NULL);
-
- buf = g_malloc(entry->text_len*6 + 1);
- if (entry->utf8)
- utf16_to_utf8_with_pos(entry->text, entry->pos, buf, pos);
- else {
- if(term_type==TERM_TYPE_BIG5)
- unichars_to_big5_with_pos(entry->text, entry->pos, buf, pos);
- else
- {
- for (i = 0; i <= entry->text_len; i++)
- buf[i] = entry->text[i];
- *pos = entry->pos;
- }
+ for (i = 0; i <= entry->text_len; i++)
+ buf[i] = entry->text[i];
}
return buf;
}
gui_entry_redraw_from(entry, entry->pos);
- len = !entry->utf8 ? strlen_big5(str) : strlen_utf8(str);
+ len = !entry->utf8 ? strlen(str) : strlen_utf8(str);
entry_text_grow(entry, len);
/* make space for the string */
(entry->text_len-entry->pos + 1) * sizeof(unichar));
if (!entry->utf8) {
- if (term_type == TERM_TYPE_BIG5) {
- chr = entry->text[entry->pos + len];
- big5_to_unichars(str, entry->text + entry->pos);
- entry->text[entry->pos + len] = chr;
- } else {
- for (i = 0; i < len; i++)
- entry->text[entry->pos + i] = str[i];
- }
+ for (i = 0; i < len; i++)
+ entry->text[entry->pos+i] = str[i];
} else {
chr = entry->text[entry->pos+len];
utf8_to_utf16(str, entry->text+entry->pos);
buf = g_malloc(entry->cutbuffer_len*6 + 1);
if (entry->utf8)
utf16_to_utf8(entry->cutbuffer, buf);
- else if (term_type == TERM_TYPE_BIG5) {
- unichars_to_big5(entry->cutbuffer, buf);
- } else {
+ else {
for (i = 0; i <= entry->cutbuffer_len; i++)
buf[i] = entry->cutbuffer[i];
}
return buf;
}
-void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer)
-{
- int newpos, size = 0;
-
- g_return_if_fail(entry != NULL);
-
- for (newpos = gui_entry_get_pos(entry); newpos > pos; size++)
- newpos = newpos - 1;
- gui_entry_erase(entry, size, update_cutbuffer);
-}
-
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer)
{
g_return_if_fail(entry != NULL);
gui_entry_draw(entry);
}
-void gui_entry_transpose_words(GUI_ENTRY_REC *entry)
-{
- int spos1, epos1, spos2, epos2;
-
- /* find last position */
- epos2 = entry->pos;
- while (epos2 < entry->text_len && !i_isalnum(entry->text[epos2]))
- epos2++;
- while (epos2 < entry->text_len && i_isalnum(entry->text[epos2]))
- epos2++;
-
- /* find other position */
- spos2 = epos2;
- while (spos2 > 0 && !i_isalnum(entry->text[spos2-1]))
- spos2--;
- while (spos2 > 0 && i_isalnum(entry->text[spos2-1]))
- spos2--;
-
- epos1 = spos2;
- while (epos1 > 0 && !i_isalnum(entry->text[epos1-1]))
- epos1--;
-
- spos1 = epos1;
- while (spos1 > 0 && i_isalnum(entry->text[spos1-1]))
- spos1--;
-
- /* do wordswap if any found */
- if (spos1 < epos1 && epos1 < spos2 && spos2 < epos2) {
- unichar *first, *sep, *second;
- int i;
-
- first = (unichar *) g_malloc( (epos1 - spos1) * sizeof(unichar) );
- sep = (unichar *) g_malloc( (spos2 - epos1) * sizeof(unichar) );
- second = (unichar *) g_malloc( (epos2 - spos2) * sizeof(unichar) );
-
- for (i = spos1; i < epos1; i++)
- first[i-spos1] = entry->text[i];
- for (i = epos1; i < spos2; i++)
- sep[i-epos1] = entry->text[i];
- for (i = spos2; i < epos2; i++)
- second[i-spos2] = entry->text[i];
-
- entry->pos = spos1;
- for (i = 0; i < epos2-spos2; i++)
- entry->text[entry->pos++] = second[i];
- for (i = 0; i < spos2-epos1; i++)
- entry->text[entry->pos++] = sep[i];
- for (i = 0; i < epos1-spos1; i++)
- entry->text[entry->pos++] = first[i];
-
- g_free(first);
- g_free(sep);
- g_free(second);
-
- }
-
- gui_entry_redraw_from(entry, spos1);
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
-}
-
-void gui_entry_capitalize_word(GUI_ENTRY_REC *entry)
-{
- int pos = entry->pos;
- while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
- pos++;
-
- if (pos < entry->text_len) {
- entry->text[pos] = i_toupper(entry->text[pos]);
- pos++;
- }
-
- while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
- entry->text[pos] = i_tolower(entry->text[pos]);
- pos++;
- }
-
- gui_entry_redraw_from(entry, entry->pos);
- entry->pos = pos;
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
-}
-
-void gui_entry_downcase_word(GUI_ENTRY_REC *entry)
-{
- int pos = entry->pos;
- while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
- pos++;
-
- while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
- entry->text[pos] = i_tolower(entry->text[pos]);
- pos++;
- }
-
- gui_entry_redraw_from(entry, entry->pos);
- entry->pos = pos;
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
-}
-
-void gui_entry_upcase_word(GUI_ENTRY_REC *entry)
-{
- int pos = entry->pos;
- while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
- pos++;
-
- while (pos < entry->text_len && i_isalnum(entry->text[pos])) {
- entry->text[pos] = i_toupper(entry->text[pos]);
- pos++;
- }
-
- gui_entry_redraw_from(entry, entry->pos);
- entry->pos = pos;
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
-}
-
int gui_entry_get_pos(GUI_ENTRY_REC *entry)
{
g_return_val_if_fail(entry != NULL, 0);
{
g_return_if_fail(entry != NULL);
- if (entry->pos + pos >= 0 && entry->pos + pos <= entry->text_len)
+ if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text_len)
entry->pos += pos;
gui_entry_fix_cursor(entry);
void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str);
char *gui_entry_get_text(GUI_ENTRY_REC *entry);
-char *gui_entry_get_text_and_pos(GUI_ENTRY_REC *entry, int *pos);
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str);
void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr);
char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry);
-void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer);
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer);
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space);
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space);
void gui_entry_transpose_chars(GUI_ENTRY_REC *entry);
-void gui_entry_transpose_words(GUI_ENTRY_REC *entry);
-
-void gui_entry_capitalize_word(GUI_ENTRY_REC *entry);
-void gui_entry_downcase_word(GUI_ENTRY_REC *entry);
-void gui_entry_upcase_word(GUI_ENTRY_REC *entry);
int gui_entry_get_pos(GUI_ENTRY_REC *entry);
void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos);
#include "term.h"
#include "gui-printtext.h"
#include "gui-windows.h"
-#ifdef HAVE_CUIX
-#include "cuix.h"
-#endif
int mirc_colors[] = { 15, 0, 1, 2, 12, 4, 5, 6, 14, 10, 3, 11, 9, 13, 8, 7 };
-static int scrollback_lines, scrollback_time, scrollback_burst_remove;
+static int scrollback_lines, scrollback_hours, scrollback_burst_remove;
static int last_fg, last_bg, last_flags;
static int next_xpos, next_ypos;
LINE_REC *line;
time_t old_time;
- old_time = time(NULL)-scrollback_time+1;
+ old_time = time(NULL)-(scrollback_hours*3600)+1;
if (view->buffer->lines_count >=
scrollback_lines+scrollback_burst_remove) {
/* remove lines by line count */
scrollback_lines == 0) {
/* too new line, don't remove yet - also
if scrollback_lines is 0, we want to check
- only scrollback_time setting. */
+ only scrollback_hours setting. */
break;
}
textbuffer_view_remove_line(view, line);
if (flags & GUI_PRINT_FLAG_CLRTOEOL)
term_clrtoeol(root_window);
term_addstr(root_window, str);
- next_xpos += strlen(str); /* FIXME utf8 or big5 */
+ next_xpos += strlen(str);
return;
}
}
if (gui->use_insert_after)
gui->insert_after = insert_after;
-#ifdef HAVE_CUIX
- cuix_refresh ();
-#endif
}
static void sig_gui_printtext_finished(WINDOW_REC *window)
static void read_settings(void)
{
scrollback_lines = settings_get_int("scrollback_lines");
- scrollback_time = settings_get_time("scrollback_time")/1000;
+ scrollback_hours = settings_get_int("scrollback_hours");
scrollback_burst_remove = settings_get_int("scrollback_burst_remove");
}
(GCompareFunc) g_str_equal);
settings_add_int("history", "scrollback_lines", 500);
- settings_add_time("history", "scrollback_time", "1day");
+ settings_add_int("history", "scrollback_hours", 24);
settings_add_int("history", "scrollback_burst_remove", 10);
signal_add("gui print text", (SIGNAL_FUNC) sig_gui_print_text);
*/
#include "module.h"
-#include "module-formats.h"
#include "signals.h"
#include "misc.h"
#include "settings.h"
#include "special-vars.h"
-#include "levels.h"
#include "servers.h"
#include "completion.h"
#include "command-history.h"
#include "keyboard.h"
#include "translation.h"
-#include "printtext.h"
#include "term.h"
#include "gui-entry.h"
static int escape_next_key;
static int readtag;
-static unichar prev_key;
-static GTimeVal last_keypress;
-
-static int paste_detect_time, paste_detect_keycount, paste_verify_line_count;
-static int paste_state, paste_keycount;
-static char *paste_entry, *prev_entry;
-static int paste_entry_pos, prev_entry_pos;
-static GArray *paste_buffer;
-
-static char *paste_old_prompt;
-static int paste_prompt, paste_line_count;
-static int paste_join_multiline;
+static time_t idle_time;
static void sig_input(void);
str = settings_get_str("scroll_page_count");
count = atof(str + (*str == '/'));
- if (count == 0)
+ if (count <= 0)
count = 1;
- else if (count < 0)
- count = active_mainwin->height-active_mainwin->statusbar_lines+count;
else if (count < 1)
count = 1.0/count;
gui_window_scroll(active_win, get_scroll_count());
}
-static void paste_buffer_join_lines(GArray *buf)
-{
-#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
- unsigned int i, count, indent, line_len;
- unichar *arr, *dest, *last_lf_pos;
- int last_lf;
-
- /* first check if we actually want to join anything. This is assuming
- that we only want to join lines if
-
- a) first line doesn't begin with whitespace
- b) subsequent lines begin with same amount of whitespace
- c) whenever there's no whitespace, goto a)
-
- For example:
-
- line 1
- line 2
- line 3
- line 4
- line 5
- line 6
-
- ->
-
- line1 line2 line 3
- line4
- line5 line 6
- */
- if (buf->len == 0)
- return;
-
- arr = (unichar *) paste_buffer->data;
-
- /* first line */
- if (IS_WHITE(arr[0]))
- return;
-
- /* find the first beginning of indented line */
- for (i = 1; i < buf->len; i++) {
- if (arr[i-1] == '\n' && IS_WHITE(arr[i]))
- break;
- }
- if (i == buf->len)
- return;
-
- /* get how much indentation we have.. */
- for (indent = 0; i < buf->len; i++, indent++) {
- if (!IS_WHITE(arr[i]))
- break;
- }
- if (i == buf->len)
- return;
-
- /* now, enforce these to all subsequent lines */
- count = indent; last_lf = TRUE;
- for (; i < buf->len; i++) {
- if (last_lf) {
- if (IS_WHITE(arr[i]))
- count++;
- else {
- last_lf = FALSE;
- if (count != 0 && count != indent)
- return;
- count = 0;
- }
- }
- if (arr[i] == '\n')
- last_lf = TRUE;
- }
-
- /* all looks fine - now remove the whitespace, but don't let lines
- get longer than 400 chars */
- dest = arr; last_lf = TRUE; last_lf_pos = NULL; line_len = 0;
- for (i = 0; i < buf->len; i++) {
- if (last_lf && IS_WHITE(arr[i])) {
- /* whitespace, ignore */
- } else if (arr[i] == '\n') {
- if (!last_lf && i+1 != buf->len &&
- IS_WHITE(arr[i+1])) {
- last_lf_pos = dest;
- *dest++ = ' ';
- } else {
- *dest++ = '\n'; /* double-LF */
- line_len = 0;
- last_lf_pos = NULL;
- }
- last_lf = TRUE;
- } else {
- last_lf = FALSE;
- if (++line_len >= 400 && last_lf_pos != NULL) {
- memmove(last_lf_pos+1, last_lf_pos,
- dest - last_lf_pos);
- *last_lf_pos = '\n'; last_lf_pos = NULL;
- line_len = 0;
- dest++;
- }
- *dest++ = arr[i];
- }
- }
- g_array_set_size(buf, dest - arr);
-}
-
-static void paste_send(void)
-{
- HISTORY_REC *history;
- unichar *arr;
- GString *str;
- char out[10], *text;
- unsigned int i;
-
- if (paste_join_multiline)
- paste_buffer_join_lines(paste_buffer);
-
- arr = (unichar *) paste_buffer->data;
- if (active_entry->text_len == 0)
- i = 0;
- else {
- /* first line has to be kludged kind of to get pasting in the
- middle of line right.. */
- for (i = 0; i < paste_buffer->len; i++) {
- if (arr[i] == '\r' || arr[i] == '\n') {
- i++;
- break;
- }
-
- gui_entry_insert_char(active_entry, arr[i]);
- }
-
- text = gui_entry_get_text(active_entry);
- history = command_history_current(active_win);
- command_history_add(history, text);
-
- translate_output(text);
- signal_emit("send command", 3, text,
- active_win->active_server, active_win->active);
- g_free(text);
- }
-
- /* rest of the lines */
- str = g_string_new(NULL);
- for (; i < paste_buffer->len; i++) {
- if (arr[i] == '\r' || arr[i] == '\n') {
- history = command_history_current(active_win);
- command_history_add(history, str->str);
-
- translate_output(str->str);
- signal_emit("send command", 3, str->str,
- active_win->active_server,
- active_win->active);
- g_string_truncate(str, 0);
- } else if (active_entry->utf8) {
- out[utf16_char_to_utf8(arr[i], out)] = '\0';
- g_string_append(str, out);
- } else if (term_type == TERM_TYPE_BIG5) {
- if (arr[i] > 0xff)
- g_string_append_c(str, (arr[i] >> 8) & 0xff);
- g_string_append_c(str, arr[i] & 0xff);
- } else {
- g_string_append_c(str, arr[i]);
- }
- }
-
- gui_entry_set_text(active_entry, str->str);
- g_string_free(str, TRUE);
-}
-
-static void paste_flush(int send)
-{
- gui_entry_set_text(active_entry, paste_entry);
- gui_entry_set_pos(active_entry, paste_entry_pos);
-
- if (send)
- paste_send();
- g_array_set_size(paste_buffer, 0);
-
- gui_entry_set_prompt(active_entry,
- paste_old_prompt == NULL ? "" : paste_old_prompt);
- g_free(paste_old_prompt); paste_old_prompt = NULL;
- paste_prompt = FALSE;
-
- paste_line_count = 0;
- paste_state = 0;
- paste_keycount = 0;
-
- gui_entry_redraw(active_entry);
-}
-
-static gboolean paste_timeout(gpointer data)
-{
- GTimeVal now;
- char *str;
- int diff;
-
- if (paste_state == 0) {
- /* gone already */
- return FALSE;
- }
-
- g_get_current_time(&now);
- diff = (now.tv_sec - last_keypress.tv_sec) * 1000 +
- (now.tv_usec - last_keypress.tv_usec)/1000;
-
- if (diff < paste_detect_time) {
- /* still pasting */
- return TRUE;
- }
-
- if (paste_line_count < paste_verify_line_count ||
- active_win->active == NULL) {
- /* paste without asking */
- paste_flush(TRUE);
- } else if (!paste_prompt) {
- paste_prompt = TRUE;
- paste_old_prompt = g_strdup(active_entry->prompt);
- printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
- TXT_PASTE_WARNING,
- paste_line_count,
- active_win->active == NULL ? "window" :
- active_win->active->visible_name);
-
- str = format_get_text(MODULE_NAME, active_win, NULL, NULL,
- TXT_PASTE_PROMPT, 0, 0);
- gui_entry_set_prompt(active_entry, str);
- gui_entry_set_text(active_entry, "");
- g_free(str);
- }
- return TRUE;
-}
-
-static int check_pasting(unichar key, int diff)
-{
- if (paste_state < 0)
- return FALSE;
-
- if (paste_state == 0) {
- /* two keys hit together quick. possibly pasting */
- if (diff > paste_detect_time)
- return FALSE;
-
- g_free(paste_entry);
- paste_entry = g_strdup(prev_entry);
- paste_entry_pos = prev_entry_pos;
-
- paste_state++;
- paste_line_count = 0;
- paste_keycount = 0;
- g_array_set_size(paste_buffer, 0);
- if (prev_key != '\r' && prev_key != '\n')
- g_array_append_val(paste_buffer, prev_key);
- } else if (paste_state > 0 && diff > paste_detect_time &&
- paste_line_count == 0) {
- /* reset paste state */
- paste_state = 0;
- paste_keycount = 0;
- return FALSE;
- }
-
- /* continuing quick hits */
- if ((key == 11 || key == 3) && paste_prompt) {
- paste_flush(key == 11);
- return TRUE;
- }
-
- g_array_append_val(paste_buffer, key);
- if (key == '\r' || key == '\n') {
- if (paste_state == 1 &&
- paste_keycount < paste_detect_keycount) {
- /* not enough keypresses to determine if this is
- pasting or not. don't reset paste keycount, but
- send this line as non-pasted */
- g_array_set_size(paste_buffer, 0);
- return FALSE;
- }
-
- /* newline - assume this line was pasted */
- if (paste_state == 1) {
- paste_state = 2;
- gui_entry_set_text(active_entry, paste_entry);
- gui_entry_set_pos(active_entry, paste_entry_pos);
- if (paste_verify_line_count > 0)
- g_timeout_add(100, paste_timeout, NULL);
- }
-
- if (paste_verify_line_count <= 0) {
- /* paste previous line */
- paste_send();
- g_array_set_size(paste_buffer, 0);
- } else {
- paste_line_count++;
- }
- }
-
- return paste_state == 2;
-}
-
static void sig_gui_key_pressed(gpointer keyp)
{
- GTimeVal now;
unichar key;
char str[20];
- int ret, diff;
key = GPOINTER_TO_INT(keyp);
return;
}
- g_get_current_time(&now);
- diff = (now.tv_sec - last_keypress.tv_sec) * 1000 +
- (now.tv_usec - last_keypress.tv_usec)/1000;
-
- if (check_pasting(key, diff)) {
- last_keypress = now;
- return;
- }
+ idle_time = time(NULL);
if (key < 32) {
/* control key */
str[1] = '?';
str[2] = '\0';
} else if (!active_entry->utf8) {
- if (key <= 0xff) {
- str[0] = (char)key;
- str[1] = '\0';
- } else {
- str[0] = (char) (key >> 8);
- str[1] = (char) (key & 0xff);
- str[2] = '\0';
- }
+ str[0] = (char)key;
+ str[1] = '\0';
} else {
/* need to convert to utf8 */
str[utf16_char_to_utf8(key, str)] = '\0';
str[2] = '\0';
}
- g_free(prev_entry);
- prev_entry = gui_entry_get_text(active_entry);
- prev_entry_pos = gui_entry_get_pos(active_entry);
-
- if (escape_next_key) {
- escape_next_key = FALSE;
+ if (escape_next_key || !key_pressed(keyboard, str)) {
+ /* key wasn't used for anything, print it */
+ escape_next_key = FALSE;
gui_entry_insert_char(active_entry, key);
- ret = 1;
- } else {
- ret = key_pressed(keyboard, str);
- if (ret < 0) {
- /* key wasn't used for anything, print it */
- gui_entry_insert_char(active_entry, key);
- }
}
-
- /* ret = 0 : some key create multiple characters - we're in the middle
- of one. try to detect the keycombo as a single keypress rather than
- multiple small onces to avoid incorrect paste detection.
-
- don't count repeated keys so paste detection won't go on when
- you're holding some key down */
- if (ret != 0 && key != prev_key) {
- last_keypress = now;
- paste_keycount++;
- }
- prev_key = key;
}
static void key_send_line(void)
{
HISTORY_REC *history;
char *str, *add_history;
+ gint flags = (redir ? redir->flags : 0);
str = gui_entry_get_text(active_entry);
active_win->active_server,
active_win->active);
} else {
- if (redir->flags & ENTRY_REDIRECT_FLAG_HIDDEN)
+ if (flags & ENTRY_REDIRECT_FLAG_HIDDEN && add_history) {
+ memset(add_history, 0, strlen(add_history));
g_free_and_null(add_history);
+ }
handle_entry_redirect(str);
+ if (flags & ENTRY_REDIRECT_FLAG_HIDDEN && str)
+ memset(str, 0, strlen(str));
}
if (add_history != NULL) {
gui_entry_transpose_chars(active_entry);
}
-static void key_transpose_words(void)
-{
- gui_entry_transpose_words(active_entry);
-}
-
-static void key_capitalize_word(void)
-{
- gui_entry_capitalize_word(active_entry);
-}
-
-static void key_downcase_word(void)
-{
- gui_entry_downcase_word(active_entry);
-}
-static void key_upcase_word(void)
-{
- gui_entry_upcase_word(active_entry);
-}
-
static void key_delete_character(void)
{
if (gui_entry_get_pos(active_entry) < active_entry->text_len) {
time_t get_idle_time(void)
{
- return last_keypress.tv_sec;
+ return idle_time;
}
static void key_scroll_backward(void)
char *text, *line;
int pos;
- text = gui_entry_get_text_and_pos(active_entry, &pos);
+ pos = gui_entry_get_pos(active_entry);
+
+ text = gui_entry_get_text(active_entry);
line = word_complete(active_win, text, &pos, erase);
g_free(text);
char *text, *line;
int pos;
- text = gui_entry_get_text_and_pos(active_entry, &pos);
+ pos = gui_entry_get_pos(active_entry);
+
+ text = gui_entry_get_text(active_entry);
line = auto_word_complete(text, &pos);
g_free(text);
gui_entry_set_prompt(active_entry, entry);
}
-static void setup_changed(void)
-{
- paste_detect_time = settings_get_time("paste_detect_time");
- if (paste_detect_time == 0)
- paste_state = -1;
- else if (paste_state == -1)
- paste_state = 0;
-
- paste_detect_keycount = settings_get_int("paste_detect_keycount");
- if (paste_detect_keycount < 2)
- paste_state = -1;
-
- paste_verify_line_count = settings_get_int("paste_verify_line_count");
- paste_join_multiline = settings_get_bool("paste_join_multiline");
-}
-
void gui_readline_init(void)
{
static char changekeys[] = "1234567890qwertyuio";
escape_next_key = FALSE;
redir = NULL;
- prev_entry = NULL;
- paste_state = 0;
- paste_keycount = 0;
- paste_entry = NULL;
- paste_entry_pos = 0;
- paste_buffer = g_array_new(FALSE, FALSE, sizeof(unichar));
- paste_old_prompt = NULL;
- g_get_current_time(&last_keypress);
+ idle_time = time(NULL);
input_listen_init(STDIN_FILENO);
settings_add_str("history", "scroll_page_count", "/2");
- settings_add_time("misc", "paste_detect_time", "5msecs");
- settings_add_int("misc", "paste_detect_keycount", 5);
- /* NOTE: function keys can generate at least 5 characters long
- keycodes. this must be larger to allow them to work. */
- settings_add_int("misc", "paste_verify_line_count", 5);
- settings_add_bool("misc", "paste_join_multiline", TRUE);
- setup_changed();
keyboard = keyboard_create(NULL);
key_configure_freeze();
key_bind("backspace", "", "backspace", NULL, (SIGNAL_FUNC) key_backspace);
key_bind("delete_character", "", "delete", NULL, (SIGNAL_FUNC) key_delete_character);
key_bind("delete_character", NULL, "^D", NULL, (SIGNAL_FUNC) key_delete_character);
- key_bind("delete_next_word", "", "meta-d", NULL, (SIGNAL_FUNC) key_delete_next_word);
- key_bind("delete_previous_word", "", "meta-backspace", NULL, (SIGNAL_FUNC) key_delete_previous_word);
+ key_bind("delete_next_word", "meta-d", NULL, NULL, (SIGNAL_FUNC) key_delete_next_word);
+ key_bind("delete_previous_word", "meta-backspace", NULL, NULL, (SIGNAL_FUNC) key_delete_previous_word);
key_bind("delete_to_previous_space", "", "^W", NULL, (SIGNAL_FUNC) key_delete_to_previous_space);
key_bind("delete_to_next_space", "", "", NULL, (SIGNAL_FUNC) key_delete_to_next_space);
key_bind("erase_line", "", "^U", NULL, (SIGNAL_FUNC) key_erase_line);
key_bind("erase_to_end_of_line", "", "^K", NULL, (SIGNAL_FUNC) key_erase_to_end_of_line);
key_bind("yank_from_cutbuffer", "", "^Y", NULL, (SIGNAL_FUNC) key_yank_from_cutbuffer);
key_bind("transpose_characters", "Swap current and previous character", "^T", NULL, (SIGNAL_FUNC) key_transpose_characters);
- key_bind("transpose_words", "Swap current and previous word", NULL, NULL, (SIGNAL_FUNC) key_transpose_words);
- key_bind("capitalize_word", "Capitalize word", NULL, NULL, (SIGNAL_FUNC) key_capitalize_word);
- key_bind("downcase_word", "Downcase word", NULL, NULL, (SIGNAL_FUNC) key_downcase_word);
- key_bind("upcase_word", "Upcase word", NULL, NULL, (SIGNAL_FUNC) key_upcase_word);
/* line transmitting */
key_bind("send_line", "Execute the input line", "return", NULL, (SIGNAL_FUNC) key_send_line);
signal_add("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
signal_add("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect);
signal_add("gui key pressed", (SIGNAL_FUNC) sig_gui_key_pressed);
- signal_add("setup changed", (SIGNAL_FUNC) setup_changed);
}
void gui_readline_deinit(void)
key_unbind("erase_to_end_of_line", (SIGNAL_FUNC) key_erase_to_end_of_line);
key_unbind("yank_from_cutbuffer", (SIGNAL_FUNC) key_yank_from_cutbuffer);
key_unbind("transpose_characters", (SIGNAL_FUNC) key_transpose_characters);
- key_unbind("transpose_words", (SIGNAL_FUNC) key_transpose_words);
-
- key_unbind("capitalize_word", (SIGNAL_FUNC) key_capitalize_word);
- key_unbind("downcase_word", (SIGNAL_FUNC) key_downcase_word);
- key_unbind("upcase_word", (SIGNAL_FUNC) key_upcase_word);
key_unbind("send_line", (SIGNAL_FUNC) key_send_line);
key_unbind("word_completion", (SIGNAL_FUNC) key_word_completion);
key_unbind("insert_text", (SIGNAL_FUNC) key_insert_text);
key_unbind("change_window", (SIGNAL_FUNC) key_change_window);
key_unbind("stop_irc", (SIGNAL_FUNC) key_sig_stop);
- keyboard_destroy(keyboard);
- g_array_free(paste_buffer, TRUE);
+ keyboard_destroy(keyboard);
key_configure_thaw();
signal_remove("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
signal_remove("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect);
signal_remove("gui key pressed", (SIGNAL_FUNC) sig_gui_key_pressed);
- signal_remove("setup changed", (SIGNAL_FUNC) setup_changed);
}
if (len > MAX_LINES_WITHOUT_FORCE && fhandle == -1 &&
g_hash_table_lookup(optlist, "force") == NULL) {
- printformat_window(active_win,
- MSGLEVEL_CLIENTNOTICE|MSGLEVEL_LASTLOG,
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
TXT_LASTLOG_TOO_LONG, len);
g_list_free(list);
return;
WINDOW_REC *rec = tmp->data;
if (rec != skip_window) {
- other = rec;
- break;
+ if (WINDOW_MAIN(rec) == mainwin) {
+ window_set_active(rec);
+ return;
+ }
+ other = rec;
}
}
+ /* no more non-sticky windows, remove main window */
window_set_active(other);
- if (mainwindows->next != NULL)
- mainwindow_destroy(mainwin);
+ mainwindow_destroy(mainwin);
}
void mainwindows_recreate(void)
term_window_destroy(window->screen_win);
- if (mainwindows != NULL) {
+ if (!quitting && mainwindows != NULL) {
gui_windows_remove_parent(window);
- if (!quitting) {
- mainwindows_add_space(window->first_line,
- window->last_line);
- mainwindows_redraw();
- }
+ mainwindows_add_space(window->first_line, window->last_line);
+
+ mainwindows_redraw();
}
g_free(window);
{ "statusbar_info_item_footer", "", 0 },
{ "statusbar_info_item_name", "%# : $[35]0 $[9]1 $2", 3, { 0, 1, 0 } },
{ "statusbar_not_found", "Statusbar doesn't exist: $0", 1, { 0 } },
+ { "statusbar_not_found", "Statusbar doesn't exist: $0", 1, { 0 } },
{ "statusbar_item_not_found", "Statusbar item doesn't exist: $0", 1, { 0 } },
{ "statusbar_unknown_command", "Unknown statusbar command: $0", 1, { 0 } },
{ "statusbar_unknown_type", "Statusbar type must be 'window' or 'root'", 1, { 0 } },
{ "statusbar_unknown_placement", "Statusbar placement must be 'top' or 'bottom'", 1, { 0 } },
{ "statusbar_unknown_visibility", "Statusbar visibility must be 'always', 'active' or 'inactive'", 1, { 0 } },
- /* ---- */
- { NULL, "Pasting", 0 },
-
- { "paste_warning", "Pasting $0 lines to $1. Press Ctrl-K if you wish to do this or Ctrl-C to cancel.", 2, { 1, 0 } },
- { "paste_prompt", "Hit Ctrl-K to paste, Ctrl-C to abort?", 0 },
-
{ NULL, NULL, 0 }
};
TXT_STATUSBAR_UNKNOWN_COMMAND,
TXT_STATUSBAR_UNKNOWN_TYPE,
TXT_STATUSBAR_UNKNOWN_PLACEMENT,
- TXT_STATUSBAR_UNKNOWN_VISIBILITY,
-
- TXT_FILL_4,
-
- TXT_PASTE_WARNING,
- TXT_PASTE_PROMPT,
-
- TXT_COUNT
+ TXT_STATUSBAR_UNKNOWN_VISIBILITY
};
-extern FORMAT_REC gui_text_formats[TXT_COUNT+1];
+extern FORMAT_REC gui_text_formats[];
/*
irssi.c : irssi
- Copyright (C) 1999-2000, 2007 Timo Sirainen
+ Copyright (C) 1999-2000 Timo Sirainen
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
static GMainLoop *main_loop;
int quitting;
-int quit_signalled;
-int protocols_deinit;
+static const char *firsttimer_text =
+ "Looks like this is the first time you run irssi.\n"
+ "This is just a reminder that you really should go read\n"
+ "startup-HOWTO if you haven't already. Irssi's default\n"
+ "settings aren't probably what you've used to, and you\n"
+ "shouldn't judge the whole client as crap based on them.\n\n"
+ "You can find startup-HOWTO and more irssi beginner info at\n"
+ "http://irssi.org/beginner/";
static int display_firsttimer = FALSE;
-/* Protocol exit signal to tell protocol has gone away. Safe to quit. */
-
-static void sig_protocol_exit(void)
-{
- protocols_deinit = TRUE;
- if (!quitting && quit_signalled)
- quitting = TRUE;
-}
static void sig_exit(void)
{
- quit_signalled = TRUE;
-
- /* If protocol hasn't finished yet, wait untill it sends "chat protocol
- deinit" signal. */
- if (!protocols_deinit)
- return;
- quitting = TRUE;
+ quitting = TRUE;
}
/* redraw irssi's screen.. */
theme_register(gui_text_formats);
signal_add_last("gui exit", (SIGNAL_FUNC) sig_exit);
- signal_add_last("chat protocol deinit",
- (SIGNAL_FUNC) sig_protocol_exit);
}
static void textui_finish_init(void)
{
quitting = FALSE;
- quit_signalled = FALSE;
- protocols_deinit = FALSE;
if (dummy)
term_dummy_init();
gui_windows_init();
statusbar_init();
term_refresh_thaw();
-
- /* don't check settings with dummy mode */
- settings_check();
}
+ settings_check();
module_register("core", "fe-text");
#ifdef HAVE_STATIC_PERL
fe_common_core_finish_init();
signal_emit("irssi init finished", 0);
+
+#if 0
+ if (display_firsttimer) {
+ printtext_window(active_win, MSGLEVEL_CLIENTNOTICE,
+ "%s", firsttimer_text);
+ }
+#endif
}
static void textui_deinit(void)
dirty_check(); /* one last time to print any quit messages */
signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
- signal_remove("chat protocol deinit", (SIGNAL_FUNC) sig_protocol_exit);
if (dummy)
term_dummy_deinit();
}
#endif
-#ifdef USE_GC
-#ifdef HAVE_GC_H
-# include <gc.h>
-#else
-# include <gc/gc.h>
-#endif
-
-GMemVTable gc_mem_table = {
- GC_malloc,
- GC_realloc,
- GC_free,
-
- NULL, NULL, NULL
-};
-#endif
-
int main(int argc, char **argv)
{
static struct poptOption options[] = {
{ NULL, '\0', 0, NULL }
};
-#ifdef USE_GC
- g_mem_set_vtable(&gc_mem_table);
-#endif
-
- srand(time(NULL));
-
dummy = FALSE;
quitting = FALSE;
- quit_signalled = FALSE;
- protocols_deinit = FALSE;
core_init_paths(argc, argv);
check_files();
textdomain(PACKAGE);
#endif
- /* setlocale() must be called at the beginning before any calls that
- affect it, especially regexps seem to break if they're generated
- before t his call.
-
- locales aren't actually used for anything else than autodetection
- of UTF-8 currently..
+ /* setlocale() must be called at the beginning before any callsthat
+ affect it, especially regexps seem to break if they'regenerated
+ before t his call.
- furthermore to get the users's charset with g_get_charset() properly
- you have to call setlocale(LC_ALL, "") */
- setlocale(LC_ALL, "");
+ locales aren't actually used for anything else thanautodetection
+ of UTF-8 currently.. */
+ setlocale(LC_CTYPE, "");
textui_init();
args_register(options);
/* Does the same as g_main_run(main_loop), except we
can call our dirty-checker after each iteration */
while (!quitting) {
-#ifdef USE_GC
- GC_collect_a_little();
-#endif
- if (!dummy) term_refresh_freeze();
g_main_iteration(TRUE);
- if (!dummy) term_refresh_thaw();
-
- if (reload_config) {
- /* SIGHUP received, do /RELOAD */
- reload_config = FALSE;
- signal_emit("command reload", 1, "");
- }
-
dirty_check();
}
int lag, lag_unknown;
server = active_win == NULL ? NULL : active_win->active_server;
- lag = get_lag(server, &lag_unknown);
+ lag = get_lag(server, &lag_unknown)/10;
- if (lag <= 0 || lag < settings_get_time("lag_min_show")) {
+ if (lag <= 0 || lag < settings_get_int("lag_min_show")) {
/* don't print the lag item */
if (get_size_only)
item->min_size = item->max_size = 0;
return;
}
- lag /= 10;
last_lag = lag;
last_lag_unknown = lag_unknown;
server = active_win == NULL ? NULL : active_win->active_server;
lag = get_lag(server, &lag_unknown)/10;
- if (lag < settings_get_time("lag_min_show"))
- lag = 0;
- else
- lag /= 10;
+ if (lag < settings_get_int("lag_min_show"))
+ lag = 0;
if (lag != last_lag || (lag > 0 && lag_unknown != last_lag_unknown))
statusbar_items_redraw("lag");
void statusbar_items_init(void)
{
- settings_add_time("misc", "lag_min_show", "1sec");
+ settings_add_int("misc", "lag_min_show", 100);
settings_add_bool("lookandfeel", "actlist_moves", FALSE);
statusbar_item_register("window", NULL, item_window_active);
int escape_vars)
{
SERVER_REC *server;
- WI_ITEM_REC *wiitem;
- char *tmpstr, *tmpstr2;
+ WI_ITEM_REC *wiitem;
+ char *tmpstr, *tmpstr2;
int len;
if (str == NULL)
#include "term.h"
#include "mainwindows.h"
-#ifdef HAVE_CUIX
-#include "cuix.h"
-#endif
-
-#include "term-curses.h"
+#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
+# include <ncurses.h>
+#else
+# include <curses.h>
+#endif
#include <termios.h>
#include <signal.h>
# define _POSIX_VDISABLE 0
#endif
+struct _TERM_WINDOW {
+ int x, y;
+ int width, height;
+ WINDOW *win;
+};
+
TERM_WINDOW *root_window;
static int curs_x, curs_y;
if (!term_use_colors)
attr = (color & 0x70) ? A_REVERSE : 0;
- else if ((color & 0xff) == 8 || (color & (0xff | ATTR_RESETFG)) == 0)
- attr = COLOR_PAIR(63);
+ else if (((color & 0x0f) == 8) && (color & ATTR_BOLD) == 0)
+ attr = (A_DIM | COLOR_PAIR(63));
else if ((color & 0x77) == 0)
attr = A_NORMAL;
else {
color &= ~0x0f;
color |= settings_get_int("default_color");
}
- attr = COLOR_PAIR((color&7) | ((color&0x70)>>1));
+ attr = (COLOR_PAIR((color&7) + (color&0x70)/2));
}
if ((color & 0x08) || (color & ATTR_BOLD)) attr |= A_BOLD;
void term_add_unichar(TERM_WINDOW *window, unichar chr)
{
-#ifdef WIDEC_CURSES
- cchar_t wch;
- wchar_t temp[2];
- temp[0] = chr;
- temp[1] = 0;
- if (setcchar(&wch, temp, A_NORMAL, 0, NULL) == OK)
- wadd_wch(window->win, &wch);
- else
-#endif
waddch(window->win, chr);
}
void term_refresh(TERM_WINDOW *window)
{
-#ifdef HAVE_CUIX
- if (!cuix_active) {
-#endif
if (window != NULL)
wnoutrefresh(window->win);
if (freeze_refresh == 0) {
move(curs_y, curs_x);
wnoutrefresh(stdscr);
-#ifdef HAVE_CUIX
- cuix_refresh ();
-#endif
doupdate();
}
-#ifdef HAVE_CUIX
- } else {
- update_panels ();
- doupdate ();
- }
-#endif
}
void term_stop(void)
{
term_deinit_int();
- kill(getpid(), SIGTSTP);
+ kill(getpid(), SIGSTOP);
term_init_int();
irssi_redraw();
}
int term_gets(unichar *buffer, int size)
{
- int count;
-#ifdef WIDEC_CURSES
- wint_t key;
-#else
- int key;
-#endif
+ int key, count;
for (count = 0; count < size; ) {
-#ifdef WIDEC_CURSES
- if (get_wch(&key) == ERR)
-#else
- if ((key = getch()) == ERR)
-#endif
- break;
+ key = getch();
#ifdef KEY_RESIZE
if (key == KEY_RESIZE)
continue;
#endif
- buffer[count++] = key;
+ if (key == ERR)
+ break;
+
+ buffer[count] = key;
+ count++;
}
return count;
+++ /dev/null
-#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
-# include <ncurses.h>
-#else
-# include <curses.h>
-#endif
-
-#ifdef HAVE_CUIX
-#include <form.h>
-#include <panel.h>
-#endif
-
-struct _TERM_WINDOW {
- int x, y;
- int width, height;
- WINDOW *win;
-};
/* bold */
if (col & 0x08)
col |= ATTR_BOLD;
- if (col & ATTR_BOLD)
+ else if (col & ATTR_BOLD)
terminfo_set_bold();
/* underline */
void term_move(TERM_WINDOW *window, int x, int y)
{
- if (x >= 0 && y >= 0) {
vcmove = TRUE;
vcx = x+window->x;
vcy = y+window->y;
vcx = term_width-1;
if (vcy >= term_height)
vcy = term_height-1;
- }
}
static void term_printed_text(int count)
if (vcy == term_height-1 && vcx == term_width-1)
return; /* last char in screen */
+ term_printed_text(1);
switch (term_type) {
case TERM_TYPE_UTF8:
- term_printed_text(utf8_width(chr));
term_addch_utf8(window, chr);
break;
case TERM_TYPE_BIG5:
- if (chr > 0xff) {
- term_printed_text(2);
- putc((chr >> 8) & 0xff, window->term->out);
- } else {
- term_printed_text(1);
- }
+ putc((chr >> 8) & 0xff, window->term->out);
putc((chr & 0xff), window->term->out);
break;
default:
- term_printed_text(1);
putc(chr, window->term->out);
break;
}
if (term_detached) return;
if (vcmove) term_move_real();
- len = strlen(str); /* FIXME utf8 or big5 */
+ len = strlen(str);
term_printed_text(len);
if (vcy != term_height || vcx != 0)
void term_stop(void)
{
if (term_detached) {
- kill(getpid(), SIGTSTP);
+ kill(getpid(), SIGSTOP);
} else {
terminfo_stop(current_term);
- kill(getpid(), SIGTSTP);
+ kill(getpid(), SIGSTOP);
terminfo_cont(current_term);
irssi_redraw();
}
{
const unsigned char *end = buffer;
- switch (get_utf8_char(&end, size, result)) {
- case -2:
+ *result = get_utf8_char(&end, size);
+ switch (*result) {
+ case (unichar) -2:
/* not UTF8 - fallback to 8bit ascii */
*result = *buffer;
return 1;
- case -1:
+ case (unichar) -1:
/* need more data */
return -1;
default:
}
}
+/* XXX I didn't check the encoding range of big5+. This is standard big5. */
+#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */
+#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */
+#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
+#define is_big5(hi,lo) (is_big5_hi(hi) && (is_big5_los(lo) || is_big5_lox(lo)))
+
static int input_big5(const unsigned char *buffer, int size, unichar *result)
{
if (is_big5_hi(*buffer)) {
if (i >= term_inbuf_pos)
term_inbuf_pos = 0;
else if (i > 0) {
- memmove(term_inbuf, term_inbuf+i, term_inbuf_pos-i);
+ memmove(term_inbuf+i, term_inbuf, term_inbuf_pos-i);
term_inbuf_pos -= i;
}
}
term_resize_dirty();
}
-static void cmd_redraw(void)
-{
- irssi_redraw();
-}
-
static void read_settings(void)
{
const char *str;
term_auto_detach(settings_get_bool("term_auto_detach"));
/* set terminal type */
- str = settings_get_str("term_charset");
+ str = settings_get_str("term_type");
if (g_strcasecmp(str, "utf-8") == 0)
term_type = TERM_TYPE_UTF8;
else if (g_strcasecmp(str, "big5") == 0)
settings_add_bool("lookandfeel", "term_force_colors", FALSE);
settings_add_bool("lookandfeel", "term_auto_detach", FALSE);
settings_add_bool("lookandfeel", "mirc_blink_fix", FALSE);
+ settings_add_str("lookandfeel", "term_type", "8bit");
force_colors = FALSE;
term_use_colors = term_has_colors() && settings_get_bool("colors");
signal_add("beep", (SIGNAL_FUNC) term_beep);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
command_bind("resize", NULL, (SIGNAL_FUNC) cmd_resize);
- command_bind("redraw", NULL, (SIGNAL_FUNC) cmd_redraw);
#ifdef SIGWINCH
sigemptyset (&act.sa_mask);
void term_common_deinit(void)
{
command_unbind("resize", (SIGNAL_FUNC) cmd_resize);
- command_unbind("redraw", (SIGNAL_FUNC) cmd_redraw);
signal_remove("beep", (SIGNAL_FUNC) term_beep);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}
terminfo_colors_deinit(term);
term->has_colors = term->TI_setf || term->TI_setaf;
- if (term->TI_setaf) {
- for (i = 0; i < 8; i++)
- term->TI_fg[i] = g_strdup(tparm(term->TI_setaf, ansitab[i], 0));
- } else if (term->TI_setf) {
+ if (term->TI_setf) {
for (i = 0; i < 8; i++)
term->TI_fg[i] = g_strdup(tparm(term->TI_setf, i, 0));
+ } else if (term->TI_setaf) {
+ for (i = 0; i < 8; i++)
+ term->TI_fg[i] = g_strdup(tparm(term->TI_setaf, ansitab[i], 0));
} else if (force) {
for (i = 0; i < 8; i++)
term->TI_fg[i] = g_strdup_printf("\033[%dm", 30+ansitab[i]);
}
- if (term->TI_setab) {
- for (i = 0; i < 8; i++)
- term->TI_bg[i] = g_strdup(tparm(term->TI_setab, ansitab[i], 0));
- } else if (term->TI_setb) {
+ if (term->TI_setb) {
for (i = 0; i < 8; i++)
term->TI_bg[i] = g_strdup(tparm(term->TI_setb, i, 0));
+ } else if (term->TI_setab) {
+ for (i = 0; i < 8; i++)
+ term->TI_bg[i] = g_strdup(tparm(term->TI_setab, ansitab[i], 0));
} else if (force) {
for (i = 0; i < 8; i++)
term->TI_bg[i] = g_strdup_printf("\033[%dm", 40+ansitab[i]);
#include "printtext.h"
#include "gui-windows.h"
#include "textbuffer-reformat.h"
-#ifdef HAVE_CUIX
-#include "cuix.h"
-#endif
/* SYNTAX: CLEAR [-all] [<refnum>] */
static void cmd_clear(const char *data)
{
- WINDOW_REC *window;
+ WINDOW_REC *window;
GHashTable *optlist;
- char *refnum;
+ char *refnum;
void *free_arg;
- GSList *tmp;
+ GSList *tmp;
g_return_if_fail(data != NULL);
"clear", &optlist, &refnum)) return;
if (g_hash_table_lookup(optlist, "all") != NULL) {
- /* clear all windows */
+ /* clear all windows */
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
- window = tmp->data;
+ WINDOW_REC *window = tmp->data;
+
textbuffer_view_clear(WINDOW_GUI(window)->view);
}
} else if (*refnum != '\0') {
- /* clear specified window */
+ /* clear specified window */
window = window_find_refnum(atoi(refnum));
- if (window != NULL)
+ if (window != NULL)
textbuffer_view_clear(WINDOW_GUI(window)->view);
} else {
- /* clear active window */
+ /* clear active window */
textbuffer_view_clear(WINDOW_GUI(active_win)->view);
}
command_runsub("scrollback", data, server, item);
}
-/* SYNTAX: SCROLLBACK CLEAR [-all] [<refnum>] */
-static void cmd_scrollback_clear(const char *data)
+/* SYNTAX: SCROLLBACK CLEAR */
+static void cmd_scrollback_clear(void)
{
- WINDOW_REC *window;
- GHashTable *optlist;
- char *refnum;
- void *free_arg;
- GSList *tmp;
-
- g_return_if_fail(data != NULL);
-
- if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
- "scrollback clear", &optlist, &refnum)) return;
-
- if (g_hash_table_lookup(optlist, "all") != NULL) {
- /* clear all windows */
- for (tmp = windows; tmp != NULL; tmp = tmp->next) {
- window = tmp->data;
- textbuffer_view_remove_all_lines(WINDOW_GUI(window)->view);
- }
- } else if (*refnum != '\0') {
- /* clear specified window */
- window = window_find_refnum(atoi(refnum));
- if (window != NULL)
- textbuffer_view_remove_all_lines(WINDOW_GUI(window)->view);
- } else {
- /* clear active window */
- textbuffer_view_remove_all_lines(WINDOW_GUI(active_win)->view);
- }
-
- cmd_params_free(free_arg);
+ textbuffer_view_remove_all_lines(WINDOW_GUI(active_win)->view);
}
static void scrollback_goto_line(int linenum)
}
}
-#ifdef HAVE_CUIX
-static void cmd_cuix(void)
-{
- if (!cuix_active)
- {
- /* textbuffer_view_clear(WINDOW_GUI(active_win)->view); */
- cuix_active = 1;
- cuix_create();
- } else {
- /* should never been called */
- /* cuix_destroy (); */
- cuix_active = 0;
- /* textbuffer_view_clear(WINDOW_GUI(active_win)->view); */
- }
-}
-#endif
-
void textbuffer_commands_init(void)
{
command_bind("clear", NULL, (SIGNAL_FUNC) cmd_clear);
command_bind("scrollback end", NULL, (SIGNAL_FUNC) cmd_scrollback_end);
command_bind("scrollback redraw", NULL, (SIGNAL_FUNC) cmd_scrollback_redraw);
command_bind("scrollback status", NULL, (SIGNAL_FUNC) cmd_scrollback_status);
-#ifdef HAVE_CUIX
- command_bind("cuix", NULL, (SIGNAL_FUNC) cmd_cuix);
-#endif
command_set_options("clear", "all");
- command_set_options("scrollback clear", "all");
signal_add("away mode changed", (SIGNAL_FUNC) sig_away_changed);
}
command_unbind("scrollback end", (SIGNAL_FUNC) cmd_scrollback_end);
command_unbind("scrollback redraw", (SIGNAL_FUNC) cmd_scrollback_redraw);
command_unbind("scrollback status", (SIGNAL_FUNC) cmd_scrollback_status);
-#ifdef HAVE_CUIX
- command_unbind("cuix", (SIGNAL_FUNC) cmd_cuix);
-#endif
signal_remove("away mode changed", (SIGNAL_FUNC) sig_away_changed);
}
text = (const unsigned char *) line->text;
/* skip the beginning of the line until we find the format */
- format_name = line_read_format(&text);
- g_free(format_name);
+ g_free(line_read_format(&text));
if (text[1] == LINE_CMD_FORMAT_CONT) {
if (raw != NULL) {
g_string_append_c(raw, '\0');
#include "module.h"
#include "textbuffer-view.h"
#include "utf8.h"
-#ifdef HAVE_CUIX
-#include "cuix.h"
-#endif
typedef struct {
char *name;
}
if (!view->utf8) {
- /* MH */
- if (term_type != TERM_TYPE_BIG5 ||
- ptr[1] == '\0' || !is_big5(ptr[0], ptr[1]))
- char_len = 1;
- else
- char_len = 2;
- next_ptr = ptr+char_len;
+ next_ptr = ptr+1;
+ char_len = 1;
} else {
char_len = 1;
while (ptr[char_len] != '\0' && char_len < 6)
char_len++;
next_ptr = ptr;
- if (get_utf8_char(&next_ptr, char_len, &chr) < 0)
+ chr = get_utf8_char(&next_ptr, char_len);
+ if (chr < 0)
char_len = 1;
else
char_len = utf8_width(chr);
continue;
}
- if (!view->utf8 && char_len > 1) {
- last_space = xpos;
- last_space_ptr = next_ptr;
- last_color = color;
- } else if (*ptr == ' ') {
+ if (*ptr == ' ') {
last_space = xpos;
last_space_ptr = ptr;
last_color = color;
if (rec->count > 1) {
for (pos = 0; lines != NULL; pos++) {
- void *data = lines->data;
-
- memcpy(&rec->lines[pos], data,
+ memcpy(&rec->lines[pos], lines->data,
sizeof(LINE_CACHE_SUB_REC));
- lines = g_slist_remove(lines, data);
- g_free(data);
+ g_free(lines->data);
+ lines = g_slist_remove(lines, lines->data);
}
}
end = text;
if (view->utf8) {
- unichar chr;
- if (get_utf8_char(&end, 6, &chr)<0)
- char_width = 1;
- else
- char_width = utf8_width(chr);
+ unichar chr = get_utf8_char(&end, 6);
+ char_width = utf8_width(chr);
} else {
- if (term_type == TERM_TYPE_BIG5 &&
- is_big5(end[0], end[1]))
- char_width = 2;
- else
- char_width = 1;
- end += char_width-1;
+ char_width = 1;
}
xpos += char_width;
if (new_line != NULL) {
g_hash_table_insert(view->bookmarks,
tmp->data, new_line);
- } else {
- g_free(tmp->data);
}
}
g_slist_free(rec.remove_list);
if (view->startline == line) {
/* removing the first line in screen */
- int is_last = view->startline->next == NULL;
-
realcount = view_scroll(view, &view->startline,
&view->subline,
linecount, FALSE);
view->ypos -= realcount;
view->empty_linecount += linecount-realcount;
- if (is_last == 1)
- view->startline = NULL;
}
} else {
if (textbuffer_line_exists_after(view->bottom_startline,
void textbuffer_view_init(void)
{
linecache_tag = g_timeout_add(LINE_CACHE_CHECK_TIME, (GSourceFunc) sig_check_linecache, NULL);
-#ifdef HAVE_CUIX
- cuix_active = 0;
-#endif
}
void textbuffer_view_deinit(void)
{
TEXT_CHUNK_REC *chunk;
const unsigned char *text;
- unsigned char cmd, *tmp = NULL;
+ unsigned char *tmp = NULL;
for (text = line->text;; text++) {
if (*text != '\0')
continue;
text++;
- cmd = *text;
- if (cmd == LINE_CMD_CONTINUE || cmd == LINE_CMD_EOL) {
- if (cmd == LINE_CMD_CONTINUE)
+ if (*text == LINE_CMD_CONTINUE || *text == LINE_CMD_EOL) {
+ if (*text == LINE_CMD_CONTINUE)
memcpy(&tmp, text+1, sizeof(char *));
/* free the previous block */
text_chunk_destroy(buffer, chunk);
}
- if (cmd == LINE_CMD_EOL)
+ if (*text == LINE_CMD_EOL)
break;
text = tmp-1;
- } else if (cmd == LINE_CMD_INDENT_FUNC) {
- text += sizeof(int (*) ());
}
}
}
(Result) |= ((Chars)[(Count)] & 0x3f); \
}
-int get_utf8_char(const unsigned char **ptr, int len, unichar *chr_r)
+unichar get_utf8_char(const unsigned char **ptr, int len)
{
int i, result, mask, chrlen;
mask = 0;
UTF8_COMPUTE(**ptr, mask, chrlen);
if (chrlen == -1)
- return -2;
+ return (unichar) -2;
if (chrlen > len)
- return -1;
+ return (unichar) -1;
UTF8_GET(result, *ptr, i, mask, chrlen);
if (result == -1)
- return -2;
-
- *chr_r = (unichar) result;
+ return (unichar) -2;
+
*ptr += chrlen-1;
return result;
}
{
const unsigned char *p = (const unsigned char *) str;
int len;
- unichar chr_r;
len = 0;
- while (*p != '\0' && get_utf8_char(&p, 6, &chr_r) > 0) {
+ while (*p != '\0' && get_utf8_char(&p, 6) > 0) {
len++;
p++;
}
*out = '\0';
}
-void utf16_to_utf8_with_pos(const unichar *str, int spos, char *out, int *opos)
-{
- int len;
- const unichar *sstart = str;
- char *ostart = out;
-
- *opos = 0;
- while (*str != '\0') {
- len = utf16_char_to_utf8(*str, out);
- out += len;
-
- str++;
- if(str - sstart == spos)
- *opos = out - ostart;
- }
- *out = '\0';
-}
-
static const unichar wcc[] = {
0x0, 0x300, 0x34F, 0x360, 0x363, 0x483, 0x487, 0x488, 0x48A, 0x591,
0x5A2, 0x5A3, 0x5BA, 0x5BB, 0x5BE, 0x5BF, 0x5C0, 0x5C1, 0x5C3, 0x5C4,
--- /dev/null
+#ifndef __UTF8_H
+#define __UTF8_H
+
+/* Returns -2 = invalid, -1 = need more data, otherwise unichar. */
+unichar get_utf8_char(const unsigned char **ptr, int len);
+
+/* Returns length of UTF8 string */
+int strlen_utf8(const char *str);
+
+/* UTF-8 -> unichar string. The NUL is copied as well. */
+void utf8_to_utf16(const char *str, unichar *out);
+
+/* unichar -> UTF-8 string. outbuf must be at least 6 chars long.
+ Returns outbuf string length. */
+int utf16_char_to_utf8(unichar c, char *outbuf);
+
+/* unichar -> UTF-8 string. The NUL is copied as well.
+ Make sure out is at least 6 x length of str. */
+void utf16_to_utf8(const unichar *str, char *out);
+
+/* Returns width for character (0-2). */
+int utf8_width(unichar c);
+
+#endif
rec->scanner = scanner = g_scanner_new(NULL);
scanner->config->skip_comment_single = FALSE;
- scanner->config->cset_identifier_first = G_CSET_a_2_z"_0123456789"G_CSET_A_2_Z;
scanner->config->cset_skip_characters = " \t";
scanner->config->scan_binary = FALSE;
scanner->config->scan_octal = FALSE;
libperl_core.la libfe_perl.la \
libperl_core_static.la libfe_perl_static.la
-libperl_core_la_LDFLAGS = -module -avoid-version -rpath $(moduledir)
-libfe_perl_la_LDFLAGS = -module -avoid-version -rpath $(moduledir)
+libperl_core_la_LDFLAGS = -avoid-version -rpath $(moduledir)
+libfe_perl_la_LDFLAGS = -avoid-version -rpath $(moduledir)
perl-core.c: perl-signals-list.h irssi-core.pl.h
for dir in $(perl_dirs); do \
cd $$dir && \
if [ ! -f Makefile ]; then \
- $(perlpath) Makefile.PL $(PERL_MM_PARAMS); \
+ $(perlpath) Makefile.PL $(PERL_MM_PARAMS); \
fi && \
- ($(MAKE) CC="$(CC)" CCFLAGS="$(PERL_CFLAGS) $(CFLAGS)" $(PERL_EXTRA_OPTS) || \
- $(MAKE) CC="$(CC)" CCFLAGS="$(PERL_CFLAGS) $(CFLAGS)" $(PERL_EXTRA_OPTS)) && \
+ ($(MAKE) || $(MAKE)) && \
cd ..; \
done
distclean-generic:
for dir in $(perl_dirs); do \
- cd $$dir; \
- $(MAKE) realclean; rm -f Makefile.PL Makefile; \
+ cd $$dir && \
+ test ! -f Makefile || $(MAKE) realclean && rm -f Makefile.PL && \
cd ..; \
done
#include "core.h"
#include "pidwait.h"
-#include "session.h"
#define DEFAULT_COMMAND_CATEGORY "Perl scripts' commands"
p[n-1] = irssi_ref_object(ST(n));
else if (SvROK(ST(n)))
p[n-1] = (void *) SvIV((SV*)SvRV(ST(n)));
- else if (SvIOK(ST(n)))
- p[n-1] = (void *)SvIV(ST(n));
else
p[n-1] = NULL;
}
p[n] = irssi_ref_object(ST(n));
else if (SvROK(ST(n)))
p[n] = (void *) SvIV((SV*)SvRV(ST(n)));
- else if (SvIOK(ST(n)))
- p[n] = (void *) SvIV(ST(n));
else
p[n] = NULL;
}
else
perl_signal_add_hash(SvIV(ST(0)), ST(1));
-void
-signal_register(...)
-PREINIT:
- HV *hv;
- HE *he;
- I32 len, pos;
- const char *arr[7];
-CODE:
- if (items != 1 || !is_hvref(ST(0)))
- croak("Usage: Irssi::signal_register(hash)");
-
- hv = hvref(ST(0));
- hv_iterinit(hv);
- while ((he = hv_iternext(hv)) != NULL) {
- const char *key = hv_iterkey(he, &len);
- SV *val = HeVAL(he);
- AV *av;
-
- if (!SvROK(val) || SvTYPE(SvRV(val)) != SVt_PVAV)
- croak("not array reference");
-
- av = (AV *) SvRV(val);
- len = av_len(av)+1;
- if (len > 6) len = 6;
- for (pos = 0; pos < len; pos++) {
- SV **val = av_fetch(av, pos, 0);
- arr[pos] = SvPV(*val, PL_na);
- }
- arr[pos] = NULL;
- perl_signal_register(key, arr);
- }
-
-
int
SIGNAL_PRIORITY_LOW()
CODE:
OUTPUT:
RETVAL
-char *
-get_irssi_binary()
-CODE:
- RETVAL = irssi_binary;
-OUTPUT:
- RETVAL
-
char *
version()
PREINIT:
if (!initialized) return;
perl_expando_deinit();
perl_settings_deinit();
- initialized = FALSE;
BOOT:
irssi_boot(Channel);
Irssi::Server server
char flag
CODE:
- RETVAL = server->isnickflag(server, flag);
+ RETVAL = server->isnickflag(flag);
OUTPUT:
RETVAL
get_nick_flags(server)
Irssi::Server server
CODE:
- RETVAL = (char *) server->get_nick_flags(server);
+ RETVAL = (char *) server->get_nick_flags();
OUTPUT:
RETVAL
#include "module.h"
#include "misc.h"
-#include "recode.h"
static GHashTable *perl_settings;
MODULE = Irssi::Settings PACKAGE = Irssi
PROTOTYPES: ENABLE
-SV *
+char *
settings_get_str(key)
char *key
-PREINIT:
- const char *str;
CODE:
- str = settings_get_str(key);
- RETVAL = new_pv(str);
- if (is_utf8())
- SvUTF8_on(RETVAL);
+ RETVAL = (char *) settings_get_str(key);
OUTPUT:
RETVAL
settings_get_bool(key)
char *key
-int
-settings_get_time(key)
- char *key
-
-int
-settings_get_level(key)
- char *key
-
-int
-settings_get_size(key)
- char *key
-
void
settings_set_str(key, value)
char *key
char *key
int value
-int
-settings_set_time(key, value)
- char *key
- char *value
-
-int
-settings_set_level(key, value)
- char *key
- char *value
-
-int
-settings_set_size(key, value)
- char *key
- char *value
-
void
settings_add_str(section, key, def)
char *section
perl_settings_add(key);
settings_add_bool_module(MODULE_NAME"/scripts", section, key, def);
-void
-settings_add_time(section, key, def)
- char *section
- char *key
- char *def
-CODE:
- perl_settings_add(key);
- settings_add_time_module(MODULE_NAME"/scripts", section, key, def);
-
-void
-settings_add_level(section, key, def)
- char *section
- char *key
- char *def
-CODE:
- perl_settings_add(key);
- settings_add_level_module(MODULE_NAME"/scripts", section, key, def);
-
-void
-settings_add_size(section, key, def)
- char *section
- char *key
- char *def
-CODE:
- perl_settings_add(key);
- settings_add_size_module(MODULE_NAME"/scripts", section, key, def);
-
void
settings_remove(key)
char *key
s/WINDOW_REC[^,]*/Irssi::UI::Window/g;
s/WI_ITEM_REC[^,]*/iobject/g;
- # perl
- s/PERL_SCRIPT_REC[^,]*/Irssi::Script/g;
-
s/([\w\*:]+)(,|$)/"\1"\2/g;
print " { \"$signal\", { $_, NULL } },\n";
}
#include "queries.h"
#include "nicklist.h"
-#include "perl-core.h"
#include "perl-common.h"
typedef struct {
return func;
}
-static int magic_free_object(pTHX_ SV *sv, MAGIC *mg)
-{
- sv_setiv(sv, 0);
- return 0;
-}
-
-static MGVTBL vtbl_free_object =
-{
- NULL, NULL, NULL, NULL, magic_free_object
-};
-
-static SV *create_sv_ptr(void *object)
-{
- SV *sv;
-
- sv = newSViv((IV)object);
-
- sv_magic(sv, NULL, '~', NULL, 0);
-
- SvMAGIC(sv)->mg_private = 0x1551; /* HF */
- SvMAGIC(sv)->mg_virtual = &vtbl_free_object;
-
- return sv;
-}
-
SV *irssi_bless_iobject(int type, int chat_type, void *object)
{
PERL_OBJECT_REC *rec;
GINT_TO_POINTER(type | (chat_type << 16)));
if (rec == NULL) {
/* unknown iobject */
- return create_sv_ptr(object);
+ return newSViv((IV)object);
}
stash = gv_stashpv(rec->stash, 1);
hv = newHV();
- hv_store(hv, "_irssi", 6, create_sv_ptr(object), 0);
+ hv_store(hv, "_irssi", 6, newSViv((IV)object), 0);
rec->fill_func(hv, object);
return sv_bless(newRV_noinc((SV*)hv), stash);
}
fill_func = g_hash_table_lookup(plain_stashes, stash);
hv = newHV();
- hv_store(hv, "_irssi", 6, create_sv_ptr(object), 0);
+ hv_store(hv, "_irssi", 6, newSViv((IV)object), 0);
if (fill_func != NULL)
fill_func(hv, object);
return sv_bless(newRV_noinc((SV*)hv), gv_stashpv((char *)stash, 1));
{
SV **sv;
HV *hv;
- void *p;
hv = hvref(o);
if (hv == NULL)
sv = hv_fetch(hv, "_irssi", 6, 0);
if (sv == NULL)
- croak("variable is damaged");
- p = GINT_TO_POINTER(SvIV(*sv));
- return p;
+ croak("variable is damaged");
+ return GINT_TO_POINTER(SvIV(*sv));
}
void irssi_add_object(int type, int chat_type, const char *stash,
hv_store(hv, "type", 4, new_pv(type), 0);
hv_store(hv, "chat_type", 9, new_pv(chat_type), 0);
- hv_store(hv, "tag", 3, new_pv(conn->tag), 0);
hv_store(hv, "address", 7, new_pv(conn->address), 0);
hv_store(hv, "port", 4, newSViv(conn->port), 0);
hv_store(hv, "chatnet", 7, new_pv(conn->chatnet), 0);
hv_store(hv, "wanted_nick", 11, new_pv(conn->nick), 0);
hv_store(hv, "username", 8, new_pv(conn->username), 0);
hv_store(hv, "realname", 8, new_pv(conn->realname), 0);
-
- hv_store(hv, "reconnection", 12, newSViv(conn->reconnection), 0);
- hv_store(hv, "no_autojoin_channels", 20, newSViv(conn->no_autojoin_channels), 0);
- hv_store(hv, "unix_socket", 11, newSViv(conn->unix_socket), 0);
- hv_store(hv, "use_ssl", 7, newSViv(conn->use_ssl), 0);
- hv_store(hv, "no_connect", 10, newSViv(conn->no_connect), 0);
}
void perl_server_fill_hash(HV *hv, SERVER_REC *server)
hv_store(hv, "op", 2, newSViv(nick->op), 0);
hv_store(hv, "halfop", 6, newSViv(nick->halfop), 0);
hv_store(hv, "voice", 5, newSViv(nick->voice), 0);
- hv_store(hv, "other", 5, newSViv(nick->other), 0);
hv_store(hv, "last_check", 10, newSViv(nick->last_check), 0);
hv_store(hv, "send_massjoin", 13, newSViv(nick->send_massjoin), 0);
hv_store(hv, "next_connect", 12, newSViv(reconnect->next_connect), 0);
}
-static void perl_script_fill_hash(HV *hv, PERL_SCRIPT_REC *script)
-{
- hv_store(hv, "name", 4, new_pv(script->name), 0);
- hv_store(hv, "package", 7, new_pv(script->package), 0);
- hv_store(hv, "path", 4, new_pv(script->path), 0);
- hv_store(hv, "data", 4, new_pv(script->data), 0);
-}
-
-static void remove_newlines(char *str)
-{
- char *writing = str;
-
- for (;*str;str++)
- if (*str != '\n' && *str != '\r')
- *(writing++) = *str;
- *writing = '\0';
-}
-
void perl_command(const char *cmd, SERVER_REC *server, WI_ITEM_REC *item)
{
const char *cmdchars;
sendcmd = g_strdup_printf("%c%s", *cmdchars, cmd);
}
- /* remove \r and \n from commands,
- to make it harder to introduce a security bug in a script */
- if(strpbrk(sendcmd, "\r\n")) {
- if (sendcmd == cmd)
- sendcmd = strdup(cmd);
- remove_newlines(sendcmd);
- }
-
signal_emit("send command", 3, sendcmd, server, item);
if (sendcmd != cmd) g_free(sendcmd);
}
chat_type = chat_protocol_lookup(rec->name);
g_return_if_fail(chat_type >= 0);
-#if GLIB_MAJOR_VERSION < 2
name = g_strdup(rec->name);
g_strdown(name+1);
-#else
- name = g_ascii_strdown(rec->name,-1);
- *name = *(rec->name);
-#endif
/* window items: channel, query */
type = module_get_uniq_id_str("WINDOW ITEM TYPE", "CHANNEL");
static void perl_unregister_protocol(CHAT_PROTOCOL_REC *rec)
{
- GSList *item;
- void *data;
+ GSList *item;
item = gslist_find_icase_string(use_protocols, rec->name);
if (item != NULL) {
- data = item->data;
- use_protocols = g_slist_remove(use_protocols, data);
- g_free(data);
+ g_free(item->data);
+ use_protocols =
+ g_slist_remove(use_protocols, item->data);
}
g_hash_table_foreach_remove(iobject_stashes,
(GHRFunc) free_iobject_proto,
{ "Irssi::Logitem", (PERL_OBJECT_FUNC) perl_log_item_fill_hash },
{ "Irssi::Rawlog", (PERL_OBJECT_FUNC) perl_rawlog_fill_hash },
{ "Irssi::Reconnect", (PERL_OBJECT_FUNC) perl_reconnect_fill_hash },
- { "Irssi::Script", (PERL_OBJECT_FUNC) perl_script_fill_hash },
{ NULL, NULL }
};
/* Unload all perl libraries loaded with dynaloader */
perl_eval_pv("foreach my $lib (@DynaLoader::dl_modules) { if ($lib =~ /^Irssi\\b/) { $lib .= '::deinit();'; eval $lib; } }", TRUE);
-
- /* We could unload all libraries .. but this crashes with some
- libraries, probably because we don't call some deinit function..
- Anyway, this would free some memory with /SCRIPT RESET, but it
- leaks memory anyway. */
- /*perl_eval_pv("eval { foreach my $lib (@DynaLoader::dl_librefs) { DynaLoader::dl_unload_file($lib); } }", TRUE);*/
+ perl_eval_pv("eval { foreach my $lib (@DynaLoader::dl_librefs) { DynaLoader::dl_unload_file($lib); } }", TRUE);
/* perl interpreter */
perl_destruct(my_perl);
/* check from SCRIPTDIR */
g_free(path);
path = g_strdup_printf(SCRIPTDIR"/%s", file);
- if (stat(path, &statbuf) != 0) {
- g_free(path);
- path = NULL;
- }
+ if (stat(path, &statbuf) != 0)
+ path = NULL;
}
g_free(file);
- return path;
+ return path;
}
/* If core should handle printing script errors */
void perl_core_deinit(void)
{
- perl_scripts_deinit();
perl_signals_deinit();
+ perl_scripts_deinit();
signal_remove("script error", (SIGNAL_FUNC) sig_script_error);
}
TXT_SCRIPT_LIST_FOOTER);
}
-static void cmd_load(const char *data, SERVER_REC *server, void *item)
-{
- char *rootmodule, *submodule;
- void *free_arg;
- size_t len;
-
- if (!cmd_get_params(data, &free_arg, 2 , &rootmodule, &submodule))
- return;
-
- len = strlen(rootmodule);
- if (len > 3 && strcmp(rootmodule + len - 3, ".pl") == 0) {
- /* make /LOAD script.pl work as expected */
- signal_stop();
- cmd_script_load(data);
- }
-
- cmd_params_free(free_arg);
-}
-
static void sig_script_error(PERL_SCRIPT_REC *script, const char *error)
{
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
command_bind("script unload", NULL, (SIGNAL_FUNC) cmd_script_unload);
command_bind("script reset", NULL, (SIGNAL_FUNC) cmd_script_reset);
command_bind("script list", NULL, (SIGNAL_FUNC) cmd_script_list);
- command_bind("load", NULL, (SIGNAL_FUNC) cmd_load);
command_set_options("script exec", "permanent");
signal_add("script error", (SIGNAL_FUNC) sig_script_error);
command_unbind("script unload", (SIGNAL_FUNC) cmd_script_unload);
command_unbind("script reset", (SIGNAL_FUNC) cmd_script_reset);
command_unbind("script list", (SIGNAL_FUNC) cmd_script_list);
- command_unbind("load", (SIGNAL_FUNC) cmd_load);
signal_remove("script error", (SIGNAL_FUNC) sig_script_error);
signal_remove("complete command script load", (SIGNAL_FUNC) sig_complete_load);
typedef struct {
char *signal;
char *args[7];
- int dynamic;
} PERL_SIGNAL_ARGS_REC;
#include "perl-signals-list.h"
signals = NULL;
}
-static void register_signal_rec(PERL_SIGNAL_ARGS_REC *rec)
-{
- if (rec->signal[strlen(rec->signal)-1] == ' ') {
- perl_signal_args_partial =
- g_slist_append(perl_signal_args_partial, rec);
- } else {
- int signal_id = signal_get_uniq_id(rec->signal);
- g_hash_table_insert(perl_signal_args_hash,
- GINT_TO_POINTER(signal_id), rec);
- }
-}
-
-void perl_signal_register(const char *signal, const char **args)
-{
- PERL_SIGNAL_ARGS_REC *rec;
- int i;
-
- if (perl_signal_args_find(signal_get_uniq_id(signal)) != NULL)
- return;
-
- rec = g_new0(PERL_SIGNAL_ARGS_REC, 1);
- for (i = 0; i < 6 && args[i] != NULL; i++)
- rec->args[i] = g_strdup(args[i]);
- rec->dynamic = TRUE;
- rec->signal = g_strdup(signal);
- register_signal_rec(rec);
-}
-
void perl_signals_init(void)
{
int n;
(GCompareFunc) g_direct_equal);
perl_signal_args_partial = NULL;
- for (n = 0; perl_signal_args[n].signal != NULL; n++)
- register_signal_rec(&perl_signal_args[n]);
-}
+ for (n = 0; perl_signal_args[n].signal != NULL; n++) {
+ PERL_SIGNAL_ARGS_REC *rec = &perl_signal_args[n];
-static void signal_args_free(PERL_SIGNAL_ARGS_REC *rec)
-{
- int i;
-
- if (!rec->dynamic)
- return;
-
- for (i = 0; i < 6 && rec->args[i] != NULL; i++)
- g_free(rec->args[i]);
- g_free(rec->signal);
- g_free(rec);
-}
-
-static void signal_args_hash_free(void *key, PERL_SIGNAL_ARGS_REC *rec)
-{
- signal_args_free(rec);
+ if (rec->signal[strlen(rec->signal)-1] == ' ') {
+ perl_signal_args_partial =
+ g_slist_append(perl_signal_args_partial, rec);
+ } else {
+ int signal_id = signal_get_uniq_id(rec->signal);
+ g_hash_table_insert(perl_signal_args_hash,
+ GINT_TO_POINTER(signal_id),
+ rec);
+ }
+ }
}
void perl_signals_deinit(void)
{
- g_slist_foreach(perl_signal_args_partial,
- (GFunc) signal_args_free, NULL);
- g_slist_free(perl_signal_args_partial);
-
- g_hash_table_foreach(perl_signal_args_hash,
- (GHFunc) signal_args_hash_free, NULL);
+ g_slist_free(perl_signal_args_partial);
g_hash_table_destroy(perl_signal_args_hash);
}
void perl_command_runsub(const char *cmd, const char *data,
SERVER_REC *server, WI_ITEM_REC *item);
-void perl_signal_register(const char *signal, const char **args);
-
void perl_signals_start(void);
void perl_signals_stop(void);
'LIBS' => '',
'OBJECT' => '$(O_FILES)',
'TYPEMAPS' => ['../common/typemap'],
- 'INC' => '-I../../.. -I@top_srcdir@/src -I@top_srcdir@/src/core -I@top_srcdir@/src/silc/core -I@top_srcdir@/src/silc -I$(silc_top_srcdir) -I$(silc_top_srcdir)/lib/silccore -I$(silc_top_srcdir)/lib/silccrypt -I$(silc_top_srcdir)/lib/silcmath -DHAVE_SILCDEFS_H -I$(silc_top_srcdir)/lib/silcske -I$(silc_top_srcdir)/lib/silcsim -I$(silc_top_srcdir)/lib/silcskr -I$(silc_top_srcdir)/lib/silchttp -I$(silc_top_srcdir)/lib/silcasn1 -I$(silc_top_srcdir)/lib/silcapputil -I$(silc_top_srcdir)/lib/silcvcard -I$(silc_top_srcdir)/lib/silcutil -I$(silc_top_srcdir)/lib/silcsftp -I$(silc_top_srcdir)/lib/silcclient -I$(silc_top_srcdir)/lib/contrib -I$(silc_top_srcdir)/includes -I$(silc_top_srcdir)/doc @GLIB_CFLAGS@',
+ 'INC' => '-I../../.. -I@top_srcdir@/src -I@top_srcdir@/src/core -I@top_srcdir@/src/silc/core -I@top_srcdir@/src/silc -I$(silc_top_srcdir) -I$(silc_top_srcdir)/lib/silccore -I$(silc_top_srcdir)/lib/silccrypt -I$(silc_top_srcdir)/lib/silcmath -DHAVE_SILCDEFS_H -I$(silc_top_srcdir)/lib/silcske -I$(silc_top_srcdir)/lib/silcsim -I$(silc_top_srcdir)/lib/silcutil -I$(silc_top_srcdir)/lib/silcsftp -I$(silc_top_srcdir)/lib/silcclient -I$(silc_top_srcdir)/lib/contrib -I$(silc_top_srcdir)/includes -I$(silc_top_srcdir)/doc @GLIB_CFLAGS@',
'VERSION_FROM' => '@srcdir@/Silc.pm');
#include "../common/module.h"
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_ops.h"
#include "silc-core.h"
#include "module.h"
-#include "recode.h"
MODULE = Irssi::TextUI::TextBuffer PACKAGE = Irssi
PROTOTYPES: ENABLE
int coloring
PREINIT:
GString *str;
- SV *result;
PPCODE:
str = g_string_new(NULL);
textbuffer_line2text(line, coloring, str);
- result = new_pv(str->str);
- if (is_utf8())
- SvUTF8_on(result);
- XPUSHs(sv_2mortal(result));
+ XPUSHs(sv_2mortal(new_pv(str->str)));
g_string_free(str, TRUE);
CODE:
if (!initialized) return;
perl_statusbar_deinit();
- initialized = FALSE;
MODULE = Irssi::TextUI PACKAGE = Irssi
static int magic_free_text_dest(pTHX_ SV *sv, MAGIC *mg)
{
TEXT_DEST_REC *dest = (TEXT_DEST_REC *) mg->mg_ptr;
- char *target = (char *) dest->target;
- g_free(target);
+ g_free((char *) dest->target);
g_free(dest);
mg->mg_ptr = NULL;
- sv_setiv(sv, 0);
return 0;
}
Irssi::UI::TextDest dest
char *str
CODE:
- printtext_dest(dest, "%s", str);
+ printtext_dest(dest, str);
printformat_perl(&dest, format, arglist);
-void
-abstracts_register(abstracts)
- SV *abstracts
-PREINIT:
- AV *av;
- char *key, *value;
- int i, len;
-CODE:
- if (!SvROK(abstracts))
- croak("abstracts is not a reference to list");
- av = (AV *) SvRV(abstracts);
- len = av_len(av)+1;
- if (len == 0 || (len & 1) != 0)
- croak("abstracts list is invalid - not divisible by 2 (%d)", len);
-
- for (i = 0; i < len; i++) {
- key = SvPV(*av_fetch(av, i, 0), PL_na); i++;
- value = SvPV(*av_fetch(av, i, 0), PL_na);
-
- theme_set_default_abstract(key, value);
- }
- themes_reload();
-
-void
-themes_reload()
-
#*******************************
MODULE = Irssi::UI::Themes PACKAGE = Irssi::Server
#*******************************
CODE:
if (!initialized) return;
perl_themes_deinit();
- initialized = FALSE;
BOOT:
irssi_boot(UI__Formats);
old = active_win;
active_win = window;
perl_command(cmd, window->active_server, window->active);
- if (active_win == window &&
- g_slist_find(windows, old) != NULL)
+ if (g_slist_find(windows, old) != NULL)
active_win = old;
void
noinst_LIBRARIES=libsilc_core.a
libsilc_core_a_SOURCES = \
+ client_ops.c \
clientutil.c \
silc-channels.c \
silc-core.c \
silc-servers-reconnect.c \
silc-lag.c \
silc-chatnets.c \
- silc-cmdqueue.c \
- client_ops.c
+ silc-cmdqueue.c
noinst_HEADERS = \
module.h \
client_ops.c
- Author: Pekka Riikonen <priikone@silcnet.org>
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 2001 - 2007 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
static void
silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
- const char *name, SilcConnectionType conn_type,
- SilcPublicKey public_key,
+ const char *name, SilcSocketType conn_type,
+ unsigned char *pk, SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context);
char *silc_get_session_filename(SILC_SERVER_REC *server)
static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
SilcChannelEntry channel_entry,
- SilcDList channel_pubkeys)
+ SilcBuffer channel_pubkeys)
{
- SilcArgumentDecodedList e;
- SilcPublicKey pubkey;
- SilcSILCPublicKey silc_pubkey;
- SilcUInt32 pk_len, type;
+ SilcUInt16 argc;
+ SilcArgumentPayload chpks;
unsigned char *pk;
- char *fingerprint, *babbleprint;
+ SilcUInt32 pk_len, type;
int c = 1;
+ char *fingerprint, *babbleprint;
+ SilcPublicKey pubkey;
+ SilcPublicKeyIdentifier ident;
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
channel_entry->channel_name);
- silc_dlist_start(channel_pubkeys);
- while ((e = silc_dlist_get(channel_pubkeys))) {
- pubkey = e->argument;
- type = e->arg_type;
-
- if (silc_pkcs_get_type(pubkey) != SILC_PKCS_SILC)
- continue;
-
- pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
- if (!pk)
- continue;
+ SILC_GET16_MSB(argc, channel_pubkeys->data);
+ chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
+ channel_pubkeys->len - 2, argc);
+ if (!chpks)
+ return;
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
- silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, pubkey);
+ pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
+ while (pk) {
+ fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
+ babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
+ silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
+ ident = silc_pkcs_decode_identifier(pubkey->identifier);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
c++, channel_entry->channel_name,
type == 0x00 ? "Added" : "Removed",
- silc_pubkey->identifier.realname ?
- silc_pubkey->identifier.realname : "",
+ ident->realname ? ident->realname : "",
fingerprint, babbleprint);
silc_free(fingerprint);
silc_free(babbleprint);
- silc_free(pk);
+ silc_pkcs_public_key_free(pubkey);
+ silc_pkcs_free_identifier(ident);
+ pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
}
+
+ silc_argument_payload_free(chpks);
}
void silc_say(SilcClient client, SilcClientConnection conn,
va_end(va);
}
-/* Try to verify a message using locally stored public key data */
-
+/* try to verify a message using locally stored public key data */
int verify_message_signature(SilcClientEntry sender,
+ SilcMessageSignedPayload sig,
SilcMessagePayload message)
{
SilcPublicKey pk;
char file[256], filename[256];
char *fingerprint, *fingerprint2;
- const unsigned char *pk_data;
+ unsigned char *pk_data;
SilcUInt32 pk_datalen;
struct stat st;
int ret = SILC_MSG_SIGNED_VERIFIED, i;
+ if (sig == NULL)
+ return SILC_MSG_SIGNED_UNKNOWN;
+
/* get public key from the signature payload and compare it with the
one stored in the client entry */
- pk = silc_message_signed_get_public_key(message, &pk_data, &pk_datalen);
+ pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
if (pk != NULL) {
fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
- if (sender->fingerprint[0]) {
+ if (sender->fingerprint) {
fingerprint2 = silc_fingerprint(sender->fingerprint,
- sizeof(sender->fingerprint));
+ sender->fingerprint_len);
if (strcmp(fingerprint, fingerprint2)) {
/* since the public key differs from the senders public key, the
verification _failed_ */
}
silc_free(fingerprint2);
}
- } else if (sender->fingerprint[0])
+ } else if (sender->fingerprint)
fingerprint = silc_fingerprint(sender->fingerprint,
- sizeof(sender->fingerprint));
+ sender->fingerprint_len);
else
/* no idea, who or what signed that message ... */
return SILC_MSG_SIGNED_UNKNOWN;
SilcPublicKey cached_pk=NULL;
/* try to load the file */
- if (!silc_pkcs_load_public_key(filename, &cached_pk)) {
+ if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(filename, &cached_pk,
+ SILC_PKCS_FILE_BIN)) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
if (pk == NULL)
}
/* the public key is now in pk, our "level of trust" in ret */
- if ((pk) && silc_message_signed_verify(message, pk,
- sha1hash) != SILC_AUTH_OK)
+ if ((pk) && silc_message_signed_verify(sig, message, pk,
+ silc_client->sha1hash)!= SILC_AUTH_OK)
ret = SILC_MSG_SIGNED_FAILED;
if (pk)
return ret;
}
-char *silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
+char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
{
- char *data, *ptr;
- int i = 0, j = 0, len = strlen(escaped_data);
-
- data = silc_calloc(len, sizeof(char));
-
- while (i < len) {
- ptr = memchr(escaped_data + i, 1, len - i);
- if (ptr) {
- int inc = (ptr - escaped_data) - i;
- memcpy(data + j, escaped_data + i, inc);
- j += inc;
- i += inc + 2;
- data[j++] = *(ptr + 1) - 1;
- } else {
- memcpy(data + j, escaped_data + i, len - i);
- j += (len - i);
- break;
+ char *data, *ptr;
+ int i = 0, j = 0, len = strlen(escaped_data);
+
+ data = silc_calloc(len, sizeof(char));
+
+ while (i < len) {
+ ptr = memchr(escaped_data + i, 1, len - i);
+ if (ptr) {
+ int inc = (ptr - escaped_data) - i;
+ memcpy(data + j, escaped_data + i, inc);
+ j += inc;
+ i += inc + 2;
+ data[j++] = *(ptr + 1) - 1;
+ } else {
+ memcpy(data + j, escaped_data + i, len - i);
+ j += (len - i);
+ break;
+ }
}
- }
- *length = j;
- return data;
+ *length = j;
+ return data;
}
-char *silc_escape_data(const char *data, SilcUInt32 len)
+char * silc_escape_data(const char *data, SilcUInt32 len)
{
- char *escaped_data, *ptr, *ptr0, *ptr1;
- int i = 0, j = 0;
-
- escaped_data = silc_calloc(2 * len, sizeof(char));
-
- while (i < len) {
- ptr0 = memchr(data + i, 0, len - i);
- ptr1 = memchr(data + i, 1, len - i);
-
- ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
-
- if (ptr) {
- int inc = (ptr - data) - i;
- if (inc)
- memcpy(escaped_data + j, data + i, inc);
- j += inc;
- i += inc;
- escaped_data[j++] = 1;
- escaped_data[j++] = *(data + i++) + 1;
- } else {
- memcpy(escaped_data + j, data + i, len - i);
- j += (len - i);
- break;
+ char *escaped_data, *ptr, *ptr0, *ptr1;
+ int i = 0, j = 0;
+
+ escaped_data = silc_calloc(2 * len, sizeof(char));
+
+ while (i < len) {
+ ptr0 = memchr(data + i, 0, len - i);
+ ptr1 = memchr(data + i, 1, len - i);
+
+ ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
+
+ if (ptr) {
+ int inc = (ptr - data) - i;
+ if (inc)
+ memcpy(escaped_data + j, data + i, inc);
+ j += inc;
+ i += inc;
+ escaped_data[j++] = 1;
+ escaped_data[j++] = *(data + i++) + 1;
+ } else {
+ memcpy(escaped_data + j, data + i, len - i);
+ j += (len - i);
+ break;
+ }
}
- }
- return escaped_data;
+ return escaped_data;
}
void silc_emit_mime_sig(SILC_SERVER_REC *server, WI_ITEM_REC *item,
- const char *data, SilcUInt32 data_len,
- const char *nick, int verified)
+ const char *data, SilcUInt32 data_len, const char *nick,
+ int verified)
{
- char *escaped_data;
+ char *escaped_data;
- escaped_data = silc_escape_data(data, data_len);
+ escaped_data = silc_escape_data(data, data_len);
- signal_emit("mime", 5, server, item, escaped_data, nick, verified);
+ signal_emit("mime", 5, server, item, escaped_data, nick, verified);
- silc_free(escaped_data);
+ silc_free(escaped_data);
}
SilcChannelUser chu = silc_client_on_channel(channel, sender);
if (chu)
nick = silc_nicklist_insert(chanrec, chu, FALSE);
- if (!nick)
- return;
}
/* If the messages is digitally signed, verify it, if possible. */
if (flags & SILC_MESSAGE_FLAG_SIGNED) {
if (!settings_get_bool("ignore_message_signatures")) {
- verified = verify_message_signature(sender, payload);
+ SilcMessageSignedPayload sig = silc_message_get_signature(payload);
+ verified = verify_message_signature(sender, sig, payload);
} else {
flags &= ~SILC_MESSAGE_FLAG_SIGNED;
}
if (flags & SILC_MESSAGE_FLAG_DATA) {
silc_emit_mime_sig(server, (WI_ITEM_REC *)chanrec, message, message_len,
- nick == NULL ? NULL : nick->nick,
- flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
+ nick == NULL ? NULL : nick->nick,
+ flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
message = NULL;
}
server = conn == NULL ? NULL : conn->context;
memset(userhost, 0, sizeof(userhost));
- if (sender->username[0])
+ if (sender->username)
snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
sender->username, sender->hostname);
/* If the messages is digitally signed, verify it, if possible. */
if (flags & SILC_MESSAGE_FLAG_SIGNED) {
if (!settings_get_bool("ignore_message_signatures")) {
- verified = verify_message_signature(sender, payload);
+ SilcMessageSignedPayload sig = silc_message_get_signature(payload);
+ verified = verify_message_signature(sender, sig, payload);
} else {
flags &= ~SILC_MESSAGE_FLAG_SIGNED;
}
if (flags & SILC_MESSAGE_FLAG_DATA) {
silc_emit_mime_sig(server,
- sender->nickname[0] ?
+ sender->nickname ?
(WI_ITEM_REC *)query_find(SERVER(server), sender->nickname) :
NULL,
message, message_len,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
+ sender->nickname ? sender->nickname : "[<unknown>]",
flags & SILC_MESSAGE_FLAG_SIGNED ? verified : -1);
message = NULL;
}
cp, message_len);
if (flags & SILC_MESSAGE_FLAG_SIGNED)
signal_emit("message silc signed_private_action", 6, server, cp,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL,
NULL, verified);
else
signal_emit("message silc private_action", 5, server, cp,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL, NULL);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, NULL);
silc_free(dm);
} else {
if (flags & SILC_MESSAGE_FLAG_SIGNED)
signal_emit("message silc signed_private_action", 6, server, message,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL,
NULL, verified);
else
signal_emit("message silc private_action", 5, server, message,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL, NULL);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, NULL);
}
else if (flags & SILC_MESSAGE_FLAG_NOTICE)
if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
cp, message_len);
if (flags & SILC_MESSAGE_FLAG_SIGNED)
signal_emit("message silc signed_private_notice", 6, server, cp,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL,
NULL, verified);
else
signal_emit("message silc private_notice", 5, server, cp,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL, NULL);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, NULL);
silc_free(dm);
} else {
if (flags & SILC_MESSAGE_FLAG_SIGNED)
signal_emit("message silc signed_private_notice", 6, server, message,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL,
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL,
NULL, verified);
else
signal_emit("message silc private_notice", 5, server, message,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL, NULL);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, NULL);
}
else {
if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
cp, message_len);
if (flags & SILC_MESSAGE_FLAG_SIGNED)
signal_emit("message signed_private", 5, server, cp,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL, verified);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, verified);
else
signal_emit("message private", 4, server, cp,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL);
silc_free(dm);
return;
}
if (flags & SILC_MESSAGE_FLAG_SIGNED)
signal_emit("message signed_private", 5, server, message,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL, verified);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL, verified);
else
signal_emit("message private", 4, server, message,
- sender->nickname[0] ? sender->nickname : "[<unknown>]",
- sender->username[0] ? userhost : NULL);
+ sender->nickname ? sender->nickname : "[<unknown>]",
+ sender->username ? userhost : NULL);
}
}
void *entry;
SilcUInt32 mode;
char buf[512];
- char *name, *tmp, *cipher, *hmac;
+ char *name, *tmp;
GSList *list1, *list_tmp;
- SilcDList chpks, clients;
+ SilcBuffer buffer;
SILC_LOG_DEBUG(("Start"));
}
memset(buf, 0, sizeof(buf));
- if (client_entry->username[0])
- snprintf(buf, sizeof(buf) - 1, "%s@%s",
- client_entry->username, client_entry->hostname);
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
signal_emit("message join", 4, server, channel->channel_name,
client_entry->nickname,
client_entry->username == NULL ? "" : buf);
-
- /* If there are multiple same nicknames on channel now, tell it to user. */
- if (client_entry != server->conn->local_entry) {
- char nick[128 + 1], tmp[32];
-
- silc_parse_userfqdn(client_entry->nickname, nick, sizeof(nick), NULL, 0);
- clients = silc_client_get_clients_local(client, conn, nick, NULL);
- if (!clients || silc_dlist_count(clients) < 2) {
- silc_client_list_free(client, conn, clients);
- break;
- }
- silc_snprintf(tmp, sizeof(tmp), "%d", silc_dlist_count(clients));
- printformat_module("fe-common/silc", server, channel->channel_name,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_MANY_NICKS,
- tmp, nick);
- printformat_module("fe-common/silc", server, channel->channel_name,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_USER_APPEARS,
- buf, client_entry->nickname);
- silc_client_list_free(client, conn, clients);
- }
break;
case SILC_NOTIFY_TYPE_LEAVE:
snprintf(buf, sizeof(buf) - 1, "%s@%s",
client_entry->username, client_entry->hostname);
signal_emit("message part", 5, server, channel->channel_name,
- client_entry->nickname, client_entry->username[0] ?
+ client_entry->nickname, client_entry->username ?
buf : "", client_entry->nickname);
chanrec = silc_channel_find_entry(server, channel);
/* Print only if we have the nickname. If this cliente has just quit
when we were only resolving it, it is possible we don't have the
nickname. */
- if (client_entry->nickname[0]) {
+ if (client_entry->nickname) {
memset(buf, 0, sizeof(buf));
if (client_entry->username)
snprintf(buf, sizeof(buf) - 1, "%s@%s",
client_entry->username, client_entry->hostname);
signal_emit("message quit", 4, server, client_entry->nickname,
- client_entry->username[0] ? buf : "",
+ client_entry->username ? buf : "",
tmp ? tmp : "");
}
SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
client_entry = va_arg(va, SilcClientEntry);
- name = va_arg(va, char *); /* old nickname */
+ client_entry2 = va_arg(va, SilcClientEntry);
- if (!strcmp(client_entry->nickname, name))
+ if (!strcmp(client_entry->nickname, client_entry2->nickname))
break;
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf) - 1, "%s@%s",
- client_entry->username, client_entry->hostname);
+ client_entry2->username, client_entry2->hostname);
nicklist_rename_unique(SERVER(server),
- client_entry, name,
- client_entry, client_entry->nickname);
- signal_emit("message nick", 4, server, client_entry->nickname, name, buf);
+ client_entry, client_entry->nickname,
+ client_entry2, client_entry2->nickname);
+ signal_emit("message nick", 4, server, client_entry2->nickname,
+ client_entry->nickname, buf);
break;
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
idtype = va_arg(va, int);
entry = va_arg(va, void *);
mode = va_arg(va, SilcUInt32);
- cipher = va_arg(va, char *); /* cipher */
- hmac = va_arg(va, char *); /* hmac */
+ (void)va_arg(va, char *); /* cipher */
+ (void)va_arg(va, char *); /* hmac */
(void)va_arg(va, char *); /* passphrase */
(void)va_arg(va, SilcPublicKey); /* founder key */
- chpks = va_arg(va, SilcDList); /* channel public keys */
+ buffer = va_arg(va, SilcBuffer); /* channel public keys */
channel = va_arg(va, SilcChannelEntry);
- tmp = silc_client_chmode(mode, cipher ? cipher : "",
- hmac ? hmac : "");
+ tmp = silc_client_chmode(mode,
+ channel->channel_key ?
+ silc_cipher_get_name(channel->channel_key) : "",
+ channel->hmac ?
+ silc_hmac_get_name(channel->hmac) : "");
chanrec = silc_channel_find_entry(server, channel);
if (chanrec != NULL) {
}
/* Print the channel public key list */
- if (chpks)
- silc_parse_channel_public_keys(server, channel, chpks);
+ if (buffer)
+ silc_parse_channel_public_keys(server, channel, buffer);
silc_free(tmp);
break;
/*
* Server has quit the network.
*/
- SilcDList clients;
+ int i;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
- SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
(void)va_arg(va, void *);
- clients = va_arg(va, SilcDList);
+ clients = va_arg(va, SilcClientEntry *);
+ clients_count = va_arg(va, SilcUInt32);
- silc_dlist_start(clients);
- while ((client_entry = silc_dlist_get(clients))) {
+ for (i = 0; i < clients_count; i++) {
memset(buf, 0, sizeof(buf));
/* Print only if we have the nickname. If this client has just quit
when we were only resolving it, it is possible we don't have the
nickname. */
- if (client_entry->nickname[0]) {
- if (client_entry->username[0])
+ if (clients[i]->nickname) {
+ if (clients[i]->username)
snprintf(buf, sizeof(buf) - 1, "%s@%s",
- client_entry->username, client_entry->hostname);
- signal_emit("message quit", 4, server, client_entry->nickname,
- client_entry->username[0] ? buf : "",
+ clients[i]->username, clients[i]->hostname);
+ signal_emit("message quit", 4, server, clients[i]->nickname,
+ clients[i]->username ? buf : "",
"server signoff");
}
- silc_server_free_ftp(server, client_entry);
+ silc_server_free_ftp(server, clients[i]);
- list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+ list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
for (list_tmp = list1; list_tmp != NULL; list_tmp =
list_tmp->next->next) {
CHANNEL_REC *channel = list_tmp->data;
va_end(va);
}
+/* Called to indicate that connection was either successfully established
+ or connecting failed. This is also the first time application receives
+ the SilcClientConnection object which it should save somewhere. */
+
+void silc_connect(SilcClient client, SilcClientConnection conn,
+ SilcClientConnectionStatus status)
+{
+ SILC_SERVER_REC *server = conn->context;
+
+ if (!server || server->disconnected) {
+ silc_client_close_connection(client, conn);
+ return;
+ }
+
+ switch (status) {
+ case SILC_CLIENT_CONN_SUCCESS:
+ /* We have successfully connected to server */
+ if ((client->nickname != NULL) &&
+ (!silc_utf8_strcasecmp(client->nickname, client->username)))
+ silc_queue_enable(conn); /* enable queueing until we have our nick */
+ server->connected = TRUE;
+ signal_emit("event connected", 1, server);
+ break;
+
+ case SILC_CLIENT_CONN_SUCCESS_RESUME:
+ /* We have successfully resumed old detached session */
+ server->connected = TRUE;
+ signal_emit("event connected", 1, server);
+
+ /* If we resumed old session check whether we need to update
+ our nickname */
+ if (strcmp(server->nick, conn->local_entry->nickname)) {
+ char *old;
+ old = g_strdup(server->nick);
+ server_change_nick(SERVER(server), conn->local_entry->nickname);
+ nicklist_rename_unique(SERVER(server),
+ conn->local_entry, server->nick,
+ conn->local_entry, conn->local_entry->nickname);
+ signal_emit("message own_nick", 4, server, server->nick, old, "");
+ g_free(old);
+ }
+
+ /* remove the detach data now */
+ {
+ char *file;
+
+ file = silc_get_session_filename(server);
+
+ unlink(file);
+ silc_free(file);
+ }
+ break;
+
+ default:
+ {
+ char * file;
+
+ file = silc_get_session_filename(server);
+
+ if (silc_file_size(file) > 0)
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
+
+ silc_free(file);
+
+ server->connection_lost = TRUE;
+ if (server->conn)
+ server->conn->context = NULL;
+ server_disconnect(SERVER(server));
+
+ break;
+ }
+ }
+}
+
+/* Called to indicate that connection was disconnected to the server. */
+
+void silc_disconnect(SilcClient client, SilcClientConnection conn,
+ SilcStatus status, const char *message)
+{
+ SILC_SERVER_REC *server = conn->context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!server || server->connection_lost)
+ return;
+
+ if (server->conn && server->conn->local_entry) {
+ nicklist_rename_unique(SERVER(server),
+ server->conn->local_entry, server->nick,
+ server->conn->local_entry,
+ silc_client->username);
+ silc_change_nick(server, silc_client->username);
+ }
+
+ if (message)
+ silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Server closed connection: %s (%d) %s",
+ silc_get_status_message(status), status,
+ message ? message : "");
+
+ if (server->conn)
+ server->conn->context = NULL;
+ server->conn = NULL;
+ server->connection_lost = TRUE;
+ server_disconnect(SERVER(server));
+}
+
/* Command handler. This function is called always in the command function.
If error occurs it will be called as well. `conn' is the associated
client connection. `cmd_context' is the command context that was
after application has called the command. Just to tell application
that the command really was processed. */
-static SilcBool cmode_list_chpks = FALSE;
+static bool cmode_list_chpks = FALSE;
void silc_command(SilcClient client, SilcClientConnection conn,
- SilcBool success, SilcCommand command, SilcStatus status,
- SilcUInt32 argc, unsigned char **argv)
+ SilcClientCommandContext cmd_context, bool success,
+ SilcCommand command, SilcStatus status)
{
SILC_SERVER_REC *server = conn->context;
switch (command) {
case SILC_COMMAND_INVITE:
- if (argc > 2)
+ if (cmd_context->argc > 2)
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
- argv[2],
- (argv[1][0] == '*' ?
+ cmd_context->argv[2],
+ (cmd_context->argv[1][0] == '*' ?
(char *)conn->current_channel->channel_name :
- (char *)argv[1]));
+ (char *)cmd_context->argv[1]));
break;
case SILC_COMMAND_DETACH:
break;
case SILC_COMMAND_CMODE:
- if (argc == 3 && !strcmp(argv[2], "+C"))
+ if (cmd_context->argc == 3 &&
+ !strcmp(cmd_context->argv[2], "+C"))
cmode_list_chpks = TRUE;
else
cmode_list_chpks = FALSE;
}
}
+typedef struct {
+ SilcChannelEntry channel;
+ bool retry;
+} *SilcJoinResolve;
+
+/* Client info resolving callback when JOIN command reply is received.
+ This will cache all users on the channel. */
+
+static void silc_client_join_get_users(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
+ void *context)
+{
+ SilcJoinResolve r = context;
+ SilcChannelEntry channel = r->channel;
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+ SILC_SERVER_REC *server = conn->context;
+ SILC_CHANNEL_REC *chanrec;
+ SilcClientEntry founder = NULL;
+ NICK_REC *ownnick;
+
+ SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
+ silc_hash_table_count(channel->user_list)));
+
+ if (!clients && r->retry < 1) {
+ /* Retry to resolve */
+ r->retry++;
+ silc_client_get_clients_by_channel(client, conn, channel,
+ silc_client_join_get_users, context);
+ return;
+ }
+
+ chanrec = silc_channel_find(server, channel->channel_name);
+ if (chanrec == NULL)
+ return;
+
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ if (!chu->client->nickname)
+ continue;
+ if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
+ founder = chu->client;
+ silc_nicklist_insert(chanrec, chu, FALSE);
+ }
+ silc_hash_table_list_reset(&htl);
+
+ ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
+ nicklist_set_own(CHANNEL(chanrec), ownnick);
+ signal_emit("channel joined", 1, chanrec);
+ chanrec->entry = channel;
+
+ if (chanrec->topic)
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
+ channel->channel_name, chanrec->topic);
+
+ if (founder) {
+ if (founder == conn->local_entry) {
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_FOUNDER_YOU,
+ channel->channel_name);
+ signal_emit("nick mode changed", 2, chanrec, ownnick);
+ } else
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_FOUNDER,
+ channel->channel_name, founder->nickname);
+ }
+}
+
typedef struct {
SilcClient client;
SilcClientConnection conn;
void *entry;
SilcIdType id_type;
+ char *fingerprint;
} *GetkeyContext;
void silc_getkey_cb(bool success, void *context)
entity, name);
}
+ silc_free(getkey->fingerprint);
silc_free(getkey);
}
MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
channel->channel_name, list_type);
- /* Parse the list */
+ /* parse the list */
tmp = silc_argument_get_first_arg(list, &type, &len);
while (tmp) {
switch (type) {
case 1:
{
- /* An invite string */
+ /* an invite string */
char **list;
int i=0;
case 2:
{
- /* A public key */
+ /* a public key */
char *fingerprint, *babbleprint;
/* tmp is Public Key Payload, take public key from it. */
case 3:
{
- /* A Client ID */
+ /* a client ID */
+ SilcClientID *client_id;
SilcClientEntry client_entry;
- SilcID id;
- if (!silc_id_payload_parse_id(tmp, len, &id)) {
+ client_id = silc_id_payload_parse_id(tmp, len, NULL);
+
+ if (client_id == NULL) {
silc_say_error("Invalid data in %s list encountered", list_type);
break;
}
- client_entry = silc_client_get_client_by_id(client, conn,
- &id.u.client_id);
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+
if (client_entry) {
printformat_module("fe-common/silc", server,
(chanrec ? chanrec->visible_name : NULL),
MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_STRING,
++counter, channel->channel_name, list_type,
client_entry->nickname);
- silc_client_unref_client(client, conn, client_entry);
} else {
resolving = TRUE;
- silc_client_get_client_by_id_resolve(client, conn, &id.u.client_id,
+ silc_client_get_client_by_id_resolve(client, conn, client_id,
NULL, NULL, NULL);
}
+
+ silc_free(client_id);
}
break;
/* "trash" */
silc_say_error("Unkown type in %s list: %u (len %u)",
list_type, type, len);
- break;
}
tmp = silc_argument_get_next_arg(list, &type, &len);
}
and each command defines the number and type of arguments it passes to the
application (on error they are not sent). */
-void silc_command_reply(SilcClient client, SilcClientConnection conn,
- SilcCommand command, SilcStatus status,
- SilcStatus error, va_list vp)
+void
+silc_command_reply(SilcClient client, SilcClientConnection conn,
+ SilcCommandPayload cmd_payload, bool success,
+ SilcCommand command, SilcStatus status, ...)
+
{
SILC_SERVER_REC *server = conn->context;
SILC_CHANNEL_REC *chanrec;
+ va_list vp;
+
+ va_start(vp, status);
SILC_LOG_DEBUG(("Start"));
switch(command) {
case SILC_COMMAND_WHOIS:
{
- char buf[1024], *nickname, *username, *realname, nick[128 + 1];
+ char buf[1024], *nickname, *username, *realname, *nick;
unsigned char *fingerprint;
- SilcUInt32 idle, mode, *user_modes;
- SilcDList channels;
+ SilcUInt32 idle, mode;
+ SilcBuffer channels, user_modes;
SilcClientEntry client_entry;
SilcDList attrs;
if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
/* Print the unknown nick for user */
- char *tmp = va_arg(vp, char *);
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, NULL);
if (tmp)
- silc_say_error("%s: %s", tmp, silc_get_status_message(status));
+ silc_say_error("%s: %s", tmp,
+ silc_get_status_message(status));
break;
} else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
/* Try to find the entry for the unknown client ID, since we
might have, and print the nickname of it for user. */
- SilcClientID *id = va_arg(vp, SilcClientID *);
- if (id) {
- client_entry = silc_client_get_client_by_id(client, conn, id);
- if (client_entry && client_entry->nickname[0])
- silc_say_error("%s: %s", client_entry->nickname,
- silc_get_status_message(status));
- silc_client_unref_client(client, conn, client_entry);
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
+ NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(client, conn,
+ client_id);
+ if (client_entry && client_entry->nickname)
+ silc_say_error("%s: %s", client_entry->nickname,
+ silc_get_status_message(status));
+ silc_free(client_id);
+ }
}
break;
- } else if (SILC_STATUS_IS_ERROR(status)) {
+ } else if (!success) {
silc_say_error("WHOIS: %s", silc_get_status_message(status));
return;
}
nickname = va_arg(vp, char *);
username = va_arg(vp, char *);
realname = va_arg(vp, char *);
- channels = va_arg(vp, SilcDList);
+ channels = va_arg(vp, SilcBuffer);
mode = va_arg(vp, SilcUInt32);
idle = va_arg(vp, SilcUInt32);
fingerprint = va_arg(vp, unsigned char *);
- user_modes = va_arg(vp, SilcUInt32 *);
+ user_modes = va_arg(vp, SilcBuffer);
attrs = va_arg(vp, SilcDList);
- silc_parse_userfqdn(nickname, nick, sizeof(nick), NULL, 0);
+ silc_parse_userfqdn(nickname, &nick, NULL);
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_USERINFO, nickname,
client_entry->username, client_entry->hostname,
nick, client_entry->nickname);
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_REALNAME, realname);
+ silc_free(nick);
if (channels && user_modes) {
- SilcChannelPayload entry;
- int i = 0;
+ SilcUInt32 *umodes;
+ SilcDList list = silc_channel_payload_parse_list(channels->data,
+ channels->len);
+ if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
+ &umodes)) {
+ SilcChannelPayload entry;
+ int i = 0;
- memset(buf, 0, sizeof(buf));
- silc_dlist_start(channels);
- while ((entry = silc_dlist_get(channels))) {
- SilcUInt32 name_len;
- char *m = silc_client_chumode_char(user_modes[i++]);
- char *name = silc_channel_get_name(entry, &name_len);
-
- if (m)
- silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
- silc_strncat(buf, sizeof(buf) - 1, name, name_len);
- silc_strncat(buf, sizeof(buf) - 1, " ", 1);
- silc_free(m);
- }
+ memset(buf, 0, sizeof(buf));
+ silc_dlist_start(list);
+ while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
+ SilcUInt32 name_len;
+ char *m = silc_client_chumode_char(umodes[i++]);
+ char *name = silc_channel_get_name(entry, &name_len);
+
+ if (m)
+ silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
+ silc_strncat(buf, sizeof(buf) - 1, name, name_len);
+ silc_strncat(buf, sizeof(buf) - 1, " ", 1);
+ silc_free(m);
+ }
- printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_WHOIS_CHANNELS, buf);
+ printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
+ SILCTXT_WHOIS_CHANNELS, buf);
+ silc_channel_payload_list_free(list);
+ silc_free(umodes);
+ }
}
if (mode) {
}
break;
+ case SILC_COMMAND_IDENTIFY:
+ {
+ SilcClientEntry client_entry;
+
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ /* Print the unknown nick for user */
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, NULL);
+ if (tmp)
+ silc_say_error("%s: %s", tmp,
+ silc_get_status_message(status));
+ break;
+ } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ /* Try to find the entry for the unknown client ID, since we
+ might have, and print the nickname of it for user. */
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
+ NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(client, conn,
+ client_id);
+ if (client_entry && client_entry->nickname)
+ silc_say_error("%s: %s", client_entry->nickname,
+ silc_get_status_message(status));
+ silc_free(client_id);
+ }
+ }
+ break;
+ }
+
+ break;
+ }
+
case SILC_COMMAND_WHOWAS:
{
char *nickname, *username, *realname;
if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
- char *tmp = va_arg(vp, char *);
+ char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+ 2, NULL);
if (tmp)
silc_say_error("%s: %s", tmp,
silc_get_status_message(status));
break;
- } else if (SILC_STATUS_IS_ERROR(status)) {
+ } else if (!success) {
silc_say_error("WHOWAS: %s", silc_get_status_message(status));
return;
}
case SILC_COMMAND_INVITE:
{
SilcChannelEntry channel;
+ SilcBuffer payload;
SilcArgumentPayload invite_list;
+ SilcUInt16 argc;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
channel = va_arg(vp, SilcChannelEntry);
- invite_list = va_arg(vp, SilcArgumentPayload);
-
- if (invite_list)
- silc_parse_inviteban_list(client, conn, server, channel,
- "invite", invite_list);
+ payload = va_arg(vp, SilcBuffer);
+
+ if (payload) {
+ SILC_GET16_MSB(argc, payload->data);
+ invite_list = silc_argument_payload_parse(payload->data + 2,
+ payload->len - 2, argc);
+ if (invite_list) {
+ silc_parse_inviteban_list(client, conn, server, channel,
+ "invite", invite_list);
+ silc_argument_payload_free(invite_list);
+ }
+ }
}
break;
case SILC_COMMAND_JOIN:
{
- char *channel, *mode, *topic, *cipher, *hmac;
+ char *channel, *mode, *topic;
SilcUInt32 modei;
- SilcHashTableList *user_list;
SilcChannelEntry channel_entry;
- SilcChannelUser chu;
- SilcClientEntry founder = NULL;
- NICK_REC *ownnick;
+ SilcBuffer client_id_list;
+ SilcUInt32 list_count;
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("JOIN: %s", silc_get_status_message(status));
+ if (!success)
return;
- }
channel = va_arg(vp, char *);
channel_entry = va_arg(vp, SilcChannelEntry);
modei = va_arg(vp, SilcUInt32);
- user_list = va_arg(vp, SilcHashTableList *);
+ (void)va_arg(vp, SilcUInt32);
+ (void)va_arg(vp, unsigned char *);
+ (void)va_arg(vp, unsigned char *);
+ (void)va_arg(vp, unsigned char *);
topic = va_arg(vp, char *);
- cipher = va_arg(vp, char *);
- hmac = va_arg(vp, char *);
+ (void)va_arg(vp, unsigned char *);
+ list_count = va_arg(vp, SilcUInt32);
+ client_id_list = va_arg(vp, SilcBuffer);
chanrec = silc_channel_find(server, channel);
if (!chanrec)
silc_free(dm);
}
- mode = silc_client_chmode(modei, cipher ? cipher : "", hmac ? hmac : "");
+ mode = silc_client_chmode(modei,
+ channel_entry->channel_key ?
+ silc_cipher_get_name(channel_entry->
+ channel_key) : "",
+ channel_entry->hmac ?
+ silc_hmac_get_name(channel_entry->hmac) : "");
g_free_not_null(chanrec->mode);
chanrec->mode = g_strdup(mode == NULL ? "" : mode);
signal_emit("channel mode changed", 1, chanrec);
- /* Get user list */
- while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
- if (!chu->client->nickname[0])
- continue;
- if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
- founder = chu->client;
- silc_nicklist_insert(chanrec, chu, FALSE);
- }
-
- ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
- if (!ownnick)
- break;
- nicklist_set_own(CHANNEL(chanrec), ownnick);
- signal_emit("channel joined", 1, chanrec);
- chanrec->entry = channel_entry;
-
- if (chanrec->topic)
- printformat_module("fe-common/silc", server,
- channel_entry->channel_name,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
- channel_entry->channel_name, chanrec->topic);
-
- if (founder) {
- if (founder == conn->local_entry) {
- printformat_module("fe-common/silc",
- server, channel_entry->channel_name,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER_YOU,
- channel_entry->channel_name);
- signal_emit("nick mode changed", 2, chanrec, ownnick);
- } else
- printformat_module("fe-common/silc",
- server, channel_entry->channel_name,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_FOUNDER,
- channel_entry->channel_name, founder->nickname);
+ /* Resolve the client information */
+ {
+ SilcJoinResolve r = silc_calloc(1, sizeof(*r));
+ r->channel = channel_entry;
+ silc_client_get_clients_by_list(client, conn, list_count,
+ client_id_list,
+ silc_client_join_get_users, r);
}
break;
SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
GSList *nicks;
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("NICK: %s", silc_get_status_message(status));
+ if (!success)
return;
- }
nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
if ((nicks != NULL) &&
- (strcmp(SERVER(server)->nick, client_entry->nickname))) {
+ (strcmp(SERVER(server)->nick, client_entry->nickname))) {
char buf[512];
SilcClientEntry collider, old;
old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
- collider = silc_client_get_client_by_id(client, conn, &old->id);
+ collider = silc_client_get_client_by_id(client, conn,
+ old->id);
+
if (collider != client_entry) {
- memset(buf, 0, sizeof(buf));
- snprintf(buf, sizeof(buf) - 1, "%s@%s",
- collider->username, collider->hostname);
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ collider->username, collider->hostname);
nicklist_rename_unique(SERVER(server),
- old, old->nickname,
- collider, collider->nickname);
+ old, old->nickname,
+ collider, collider->nickname);
silc_print_nick_change(server, collider->nickname,
- client_entry->nickname, buf);
+ client_entry->nickname, buf);
}
- silc_client_unref_client(client, conn, collider);
}
if (nicks != NULL)
g_free(old);
/* when connecting to a server, the last thing we receive
- is a SILC_COMMAND_LIST reply. Since we enable queueing
+ is a SILC_COMMAND_NICK reply. Since we enable queueing
during the connection, we can now safely disable it again */
silc_queue_disable(conn);
break;
char users[20];
char tmp[256], *cp, *dm = NULL;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
(void)va_arg(vp, SilcChannelEntry);
name = va_arg(vp, char *);
+ if (!name)
+ return;
topic = va_arg(vp, char *);
usercount = va_arg(vp, int);
SilcUInt32 mode;
char *reason;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
mode = va_arg(vp, SilcUInt32);
break;
case SILC_COMMAND_OPER:
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("OPER: %s", silc_get_status_message(status));
+ if (!success)
return;
- }
server->umode |= SILC_UMODE_SERVER_OPERATOR;
signal_emit("user mode changed", 2, server, NULL);
break;
case SILC_COMMAND_SILCOPER:
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("SILCOPER: %s", silc_get_status_message(status));
+ if (!success)
return;
- }
server->umode |= SILC_UMODE_ROUTER_OPERATOR;
signal_emit("user mode changed", 2, server, NULL);
SilcChannelEntry channel;
SilcChannelUser chu;
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("USERS: %s", silc_get_status_message(status));
+ if (!success)
return;
- }
channel = va_arg(vp, SilcChannelEntry);
SilcClientEntry e = chu->client;
char stat[5], *mode;
- if (!e->nickname[0])
+ if (!e->nickname)
continue;
memset(stat, 0, sizeof(stat));
printformat_module("fe-common/silc", server, channel->channel_name,
MSGLEVEL_CRAP, SILCTXT_USERS,
e->nickname, stat,
- e->username[0] ? e->username : "",
- e->hostname[0] ? e->hostname : "",
+ e->username ? e->username : "",
+ e->hostname ? e->hostname : "",
e->realname ? e->realname : "");
if (mode)
silc_free(mode);
case SILC_COMMAND_BAN:
{
SilcChannelEntry channel;
- SilcArgumentPayload invite_list;
+ SilcBuffer payload;
+ SilcArgumentPayload ban_list;
+ SilcUInt16 argc;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
channel = va_arg(vp, SilcChannelEntry);
- invite_list = va_arg(vp, SilcArgumentPayload);
-
- if (invite_list)
- silc_parse_inviteban_list(client, conn, server, channel,
- "ban", invite_list);
+ payload = va_arg(vp, SilcBuffer);
+
+ if (payload) {
+ SILC_GET16_MSB(argc, payload->data);
+ ban_list = silc_argument_payload_parse(payload->data + 2,
+ payload->len - 2, argc);
+ if (ban_list) {
+ silc_parse_inviteban_list(client, conn, server, channel,
+ "ban", ban_list);
+ silc_argument_payload_free(ban_list);
+ }
+ }
}
break;
SilcIdType id_type;
void *entry;
SilcPublicKey public_key;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
GetkeyContext getkey;
char *name;
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("GETKEY: %s", silc_get_status_message(status));
+ if (!success)
return;
- }
id_type = va_arg(vp, SilcUInt32);
entry = va_arg(vp, void *);
public_key = va_arg(vp, SilcPublicKey);
if (public_key) {
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+
getkey = silc_calloc(1, sizeof(*getkey));
getkey->entry = entry;
getkey->id_type = id_type;
getkey->client = client;
getkey->conn = conn;
+ getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
name = (id_type == SILC_ID_CLIENT ?
((SilcClientEntry)entry)->nickname :
silc_verify_public_key_internal(client, conn, name,
(id_type == SILC_ID_CLIENT ?
- SILC_CONN_CLIENT :
- SILC_CONN_SERVER),
- public_key, silc_getkey_cb, getkey);
+ SILC_SOCKET_TYPE_CLIENT :
+ SILC_SOCKET_TYPE_SERVER),
+ pk, pk_len, SILC_SKE_PK_TYPE_SILC,
+ silc_getkey_cb, getkey);
+ silc_free(pk);
} else {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
char *server_name;
char *server_info;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
server_entry = va_arg(vp, SilcServerEntry);
char *topic;
char tmp[256], *cp, *dm = NULL;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
channel = va_arg(vp, SilcChannelEntry);
case SILC_COMMAND_STATS:
{
- SilcClientStats *cstats;
+ SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
+ my_router_ops, cell_clients, cell_channels, cell_servers,
+ clients, channels, servers, routers, server_ops, router_ops;
+ SilcUInt32 buf_len;
+ SilcBufferStruct buf;
+ unsigned char *tmp_buf;
char tmp[40];
const char *tmptime;
int days, hours, mins, secs;
- if (SILC_STATUS_IS_ERROR(status))
+ if (!success)
return;
- cstats = va_arg(vp, SilcClientStats *);
- if (!cstats) {
+ tmp_buf = va_arg(vp, unsigned char *);
+ buf_len = va_arg(vp, SilcUInt32);
+
+ if (!tmp_buf || !buf_len) {
printtext(server, NULL, MSGLEVEL_CRAP, "No statistics available");
return;
}
- tmptime = silc_time_string(cstats->starttime);
+ /* Get statistics structure */
+ silc_buffer_set(&buf, tmp_buf, buf_len);
+ silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&starttime),
+ SILC_STR_UI_INT(&uptime),
+ SILC_STR_UI_INT(&my_clients),
+ SILC_STR_UI_INT(&my_channels),
+ SILC_STR_UI_INT(&my_server_ops),
+ SILC_STR_UI_INT(&my_router_ops),
+ SILC_STR_UI_INT(&cell_clients),
+ SILC_STR_UI_INT(&cell_channels),
+ SILC_STR_UI_INT(&cell_servers),
+ SILC_STR_UI_INT(&clients),
+ SILC_STR_UI_INT(&channels),
+ SILC_STR_UI_INT(&servers),
+ SILC_STR_UI_INT(&routers),
+ SILC_STR_UI_INT(&server_ops),
+ SILC_STR_UI_INT(&router_ops),
+ SILC_STR_END);
+
+ tmptime = silc_get_time(starttime);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local server start time", tmptime);
- days = cstats->uptime / (24 * 60 * 60);
- cstats->uptime -= days * (24 * 60 * 60);
- hours = cstats->uptime / (60 * 60);
- cstats->uptime -= hours * (60 * 60);
- mins = cstats->uptime / 60;
- cstats->uptime -= mins * 60;
- secs = cstats->uptime;
+ days = uptime / (24 * 60 * 60);
+ uptime -= days * (24 * 60 * 60);
+ hours = uptime / (60 * 60);
+ uptime -= hours * (60 * 60);
+ mins = uptime / 60;
+ uptime -= mins * 60;
+ secs = uptime;
snprintf(tmp, sizeof(tmp) - 1, "%d days %d hours %d mins %d secs",
days, hours, mins, secs);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local server uptime", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_clients);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_clients);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local server clients", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_channels);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_channels);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local server channels", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_server_ops);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_server_ops);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local server operators", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->my_router_ops);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)my_router_ops);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local router operators", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_clients);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_clients);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local cell clients", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_channels);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_channels);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local cell channels", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->cell_servers);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cell_servers);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Local cell servers", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->clients);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)clients);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Total clients", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->channels);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)channels);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Total channels", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->servers);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)servers);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Total servers", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->routers);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)routers);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Total routers", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->server_ops);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)server_ops);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Total server operators", tmp);
- snprintf(tmp, sizeof(tmp) - 1, "%d", (int)cstats->router_ops);
+ snprintf(tmp, sizeof(tmp) - 1, "%d", (int)router_ops);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_STATS,
"Total router operators", tmp);
case SILC_COMMAND_CMODE:
{
SilcChannelEntry channel_entry;
- SilcDList chpks;
+ SilcBuffer channel_pubkeys;
channel_entry = va_arg(vp, SilcChannelEntry);
(void)va_arg(vp, SilcUInt32);
(void)va_arg(vp, SilcPublicKey);
- chpks = va_arg(vp, SilcDList);
+ channel_pubkeys = va_arg(vp, SilcBuffer);
- if (SILC_STATUS_IS_ERROR(status) || !cmode_list_chpks ||
+ if (!success || !cmode_list_chpks ||
!channel_entry || !channel_entry->channel_name)
return;
/* Print the channel public key list */
- if (chpks)
- silc_parse_channel_public_keys(server, channel_entry, chpks);
+ if (channel_pubkeys)
+ silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
else
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
case SILC_COMMAND_LEAVE:
{
- if (SILC_STATUS_IS_ERROR(status))
- return;
-
- /* We might be cycling, so disable queueing again */
+ /* we might be cycling, so disable queueing again */
silc_queue_disable(conn);
}
break;
- case SILC_COMMAND_DETACH:
- {
- /* Save the detachment data to file. */
- char *file;
- SilcBuffer detach;
-
- if (SILC_STATUS_IS_ERROR(status))
- return;
-
- detach = va_arg(vp, SilcBuffer);
- file = silc_get_session_filename(server);
- silc_file_writefile(file, silc_buffer_data(detach),
- silc_buffer_len(detach));
- silc_free(file);
- }
- break;
-
- case SILC_COMMAND_KILL:
- {
- SilcClientEntry client_entry;
-
- if (SILC_STATUS_IS_ERROR(status)) {
- silc_say_error("KILL: %s", silc_get_status_message(status));
- return;
- }
-
- client_entry = va_arg(vp, SilcClientEntry);
- if (!client_entry || !client_entry->nickname[0])
- break;
-
- /* Print this only if the killed client isn't joined on channels.
- If it is, we receive KILLED notify and we'll print this there. */
- if (!silc_hash_table_count(client_entry->channels))
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
- client_entry->nickname,
- conn->local_entry->nickname, "");
- }
}
+
+ va_end(vp);
}
typedef struct {
char *filename;
char *entity;
char *entity_name;
- SilcPublicKey public_key;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+ SilcSKEPKType pk_type;
SilcVerifyPublicKey completion;
void *context;
} *PublicKeyVerify;
verify->completion(TRUE, verify->context);
/* Save the key for future checking */
- silc_pkcs_save_public_key(verify->filename, verify->public_key,
- SILC_PKCS_FILE_BASE64);
+ silc_pkcs_save_public_key_data(verify->filename, verify->pk,
+ verify->pk_len, SILC_PKCS_FILE_PEM);
} else {
/* Call the completion */
if (verify->completion)
silc_free(verify->filename);
silc_free(verify->entity);
silc_free(verify->entity_name);
+ silc_free(verify->pk);
silc_free(verify);
}
static void
silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
- const char *name,
- SilcConnectionType conn_type,
- SilcPublicKey public_key,
+ const char *name, SilcSocketType conn_type,
+ unsigned char *pk, SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context)
{
- PublicKeyVerify verify;
+ int i;
char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
char *fingerprint, *babbleprint, *format;
- SilcPublicKey local_pubkey;
- SilcUInt16 port;
- const char *hostname, *ip;
- unsigned char *pk;
- SilcUInt32 pk_len;
struct passwd *pw;
struct stat st;
- char *entity = ((conn_type == SILC_CONN_SERVER ||
- conn_type == SILC_CONN_ROUTER) ?
+ char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
+ conn_type == SILC_SOCKET_TYPE_ROUTER) ?
"server" : "client");
- int i;
+ PublicKeyVerify verify;
- if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
+ if (pk_type != SILC_SKE_PK_TYPE_SILC) {
printformat_module("fe-common/silc", NULL, NULL,
MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
- entity, silc_pkcs_get_type(public_key));
- if (completion)
- completion(FALSE, context);
- return;
- }
-
- /* Encode public key */
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
- if (!pk) {
+ entity, pk_type);
if (completion)
completion(FALSE, context);
return;
if (!pw) {
if (completion)
completion(FALSE, context);
- silc_free(pk);
return;
}
memset(filename2, 0, sizeof(filename2));
memset(file, 0, sizeof(file));
- /* Get remote host information */
- silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
- NULL, &hostname, &ip, &port);
-
- if (conn_type == SILC_CONN_SERVER ||
- conn_type == SILC_CONN_ROUTER) {
+ if (conn_type == SILC_SOCKET_TYPE_SERVER ||
+ conn_type == SILC_SOCKET_TYPE_ROUTER) {
if (!name) {
- snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port);
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->ip, conn->sock->port);
snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
get_irssi_dir(), entity, file);
snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
- hostname, port);
+ conn->sock->hostname, conn->sock->port);
snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
get_irssi_dir(), entity, file);
hostf = filename2;
} else {
snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
- name, port);
+ name, conn->sock->port);
snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
get_irssi_dir(), entity, file);
verify->conn = conn;
verify->filename = strdup(ipf);
verify->entity = strdup(entity);
- verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
- (name ? strdup(name) : strdup(hostname))
+ verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
+ (name ? strdup(name) : strdup(conn->sock->hostname))
: NULL);
- verify->public_key = public_key;
+ verify->pk = silc_memdup(pk, pk_len);
+ verify->pk_len = pk_len;
+ verify->pk_type = pk_type;
verify->completion = completion;
verify->context = context;
format, 0, verify);
g_free(format);
silc_free(fingerprint);
- silc_free(babbleprint);
- silc_free(pk);
return;
} else {
/* The key already exists, verify it. */
+ SilcPublicKey public_key;
unsigned char *encpk;
SilcUInt32 encpk_len;
/* Load the key file, try for both IP filename and hostname filename */
- if (!silc_pkcs_load_public_key(ipf, &local_pubkey) &&
- (!hostf || (!silc_pkcs_load_public_key(hostf, &local_pubkey)))) {
+ if (!silc_pkcs_load_public_key(ipf, &public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(ipf, &public_key,
+ SILC_PKCS_FILE_BIN) &&
+ (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(hostf, &public_key,
+ SILC_PKCS_FILE_BIN)))) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
verify->entity_name : entity);
format, 0, verify);
g_free(format);
silc_free(fingerprint);
- silc_free(babbleprint);
- silc_free(pk);
return;
}
/* Encode the key data */
- encpk = silc_pkcs_public_key_encode(local_pubkey, &encpk_len);
+ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
if (!encpk) {
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
format, 0, verify);
g_free(format);
silc_free(fingerprint);
- silc_free(babbleprint);
- silc_free(pk);
return;
}
- silc_pkcs_public_key_free(local_pubkey);
/* Compare the keys */
if (memcmp(encpk, pk, encpk_len)) {
format, 0, verify);
g_free(format);
silc_free(fingerprint);
- silc_free(babbleprint);
- silc_free(encpk);
- silc_free(pk);
return;
}
/* Local copy matched */
if (completion)
completion(TRUE, context);
- silc_free(encpk);
silc_free(fingerprint);
- silc_free(babbleprint);
silc_free(verify->filename);
silc_free(verify->entity);
silc_free(verify->entity_name);
+ silc_free(verify->pk);
silc_free(verify);
- silc_free(pk);
}
}
void
silc_verify_public_key(SilcClient client, SilcClientConnection conn,
- SilcConnectionType conn_type,
- SilcPublicKey public_key,
+ SilcSocketType conn_type, unsigned char *pk,
+ SilcUInt32 pk_len, SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context)
{
- silc_verify_public_key_internal(client, conn, NULL, conn_type, public_key,
+ silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
+ pk_len, pk_type,
completion, context);
}
typedef struct {
SilcGetAuthMeth completion;
void *context;
-} *GetAuthMethod;
+} *InternalGetAuthMethod;
+
+/* Callback called when we've received the authentication method information
+ from the server after we've requested it. This will get the authentication
+ data from the user if needed. */
-static void silc_get_auth_ask_passphrase(unsigned char *passphrase,
- SilcUInt32 passphrase_len,
- void *context)
+static void silc_get_auth_method_callback(SilcClient client,
+ SilcClientConnection conn,
+ SilcAuthMethod auth_meth,
+ void *context)
{
- GetAuthMethod a = context;
- a->completion(passphrase ? SILC_AUTH_PASSWORD : SILC_AUTH_NONE,
- passphrase, passphrase_len, a->context);
- silc_free(a);
+ InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ switch (auth_meth) {
+ case SILC_AUTH_NONE:
+ /* No authentication required. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ case SILC_AUTH_PASSWORD:
+ {
+ /* Check whether we find the password for this server in our
+ configuration. If not, then don't provide so library will ask
+ it from the user. */
+ SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
+ conn->remote_port);
+ if (!setup || !setup->password) {
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ }
+
+ (*internal->completion)(TRUE, auth_meth, setup->password,
+ strlen(setup->password), internal->context);
+ }
+ break;
+ case SILC_AUTH_PUBLIC_KEY:
+ /* Do not get the authentication data now, the library will generate
+ it using our default key, if we do not provide it here. */
+ /* XXX In the future when we support multiple local keys and multiple
+ local certificates we will need to ask from user which one to use. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ }
+
+ silc_free(internal);
}
-/* Find authentication data by hostname and port. The hostname may be IP
- address as well.*/
+/* Find authentication method and authentication data by hostname and
+ port. The hostname may be IP address as well. The found authentication
+ method and authentication data is returned to `auth_meth', `auth_data'
+ and `auth_data_len'. The function returns TRUE if authentication method
+ is found and FALSE if not. `conn' may be NULL. */
void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
char *hostname, SilcUInt16 port,
- SilcAuthMethod auth_meth,
SilcGetAuthMeth completion, void *context)
{
- SERVER_SETUP_REC *setup;
+ InternalGetAuthMethod internal;
SILC_LOG_DEBUG(("Start"));
- if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
- /* Returning NULL will cause library to use our private key configured
- for this connection */
- completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
- return;
- }
+ /* If we do not have this connection configured by the user in a
+ configuration file then resolve the authentication method from the
+ server for this session. */
+ internal = silc_calloc(1, sizeof(*internal));
+ internal->completion = completion;
+ internal->context = context;
- /* Check whether we find the password for this server in our
- configuration. If it's set, always send it server. */
- setup = server_setup_find_port(hostname, port);
- if (setup && setup->password) {
- completion(SILC_AUTH_PASSWORD, setup->password, strlen(setup->password),
- context);
- return;
- }
+ silc_client_request_authentication_method(client, conn,
+ silc_get_auth_method_callback,
+ internal);
+}
- /* Didn't find password. If server wants it, ask it from user. */
- if (auth_meth == SILC_AUTH_PASSWORD) {
- GetAuthMethod a;
- a = silc_calloc(1, sizeof(*a));
- if (a) {
- a->completion = completion;
- a->context = context;
- silc_ask_passphrase(client, conn, silc_get_auth_ask_passphrase, a);
- return;
- }
+/* Notifies application that failure packet was received. This is called
+ if there is some protocol active in the client. The `protocol' is the
+ protocol context. The `failure' is opaque pointer to the failure
+ indication. Note, that the `failure' is protocol dependant and application
+ must explicitly cast it to correct type. Usually `failure' is 32 bit
+ failure type (see protocol specs for all protocol failure types). */
+
+void silc_failure(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure)
+{
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+ SilcSKEStatus status = (SilcSKEStatus)failure;
+
+ if (status == SILC_SKE_STATUS_BAD_VERSION)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_BAD_VERSION);
+ if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
+ if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_UNKNOWN_GROUP);
+ if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_UNKNOWN_CIPHER);
+ if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_UNKNOWN_PKCS);
+ if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
+ if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_UNKNOWN_HMAC);
+ if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_INCORRECT_SIGNATURE);
+ if (status == SILC_SKE_STATUS_INVALID_COOKIE)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_KE_INVALID_COOKIE);
}
- /* No authentication */
- completion(SILC_AUTH_NONE, NULL, 0, context);
+ if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
+ SilcUInt32 err = (SilcUInt32)failure;
+
+ if (err == SILC_AUTH_FAILED)
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_AUTH_FAILED);
+ }
}
/* Asks whether the user would like to perform the key agreement protocol.
desired (application may start it later by calling the function
silc_client_perform_key_agreement). */
-void silc_key_agreement(SilcClient client, SilcClientConnection conn,
+bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry, const char *hostname,
- SilcUInt16 protocol, SilcUInt16 port)
+ SilcUInt16 port, SilcKeyAgreementCallback *completion,
+ void **context)
{
- char portstr[12], protostr[5];
+ char portstr[12];
SILC_LOG_DEBUG(("Start"));
/* We will just display the info on the screen and return FALSE and user
will have to start the key agreement with a command. */
- if (hostname) {
+ if (hostname)
snprintf(portstr, sizeof(portstr) - 1, "%d", port);
- snprintf(protostr, sizeof(protostr) - 1, "%s", protocol == 1 ? "UDP" :
- "TCP");
- }
if (!hostname)
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
else
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
- client_entry->nickname, hostname, portstr, protostr);
+ client_entry->nickname, hostname, portstr);
+
+ *completion = NULL;
+ *context = NULL;
+
+ return FALSE;
}
/* Notifies application that file transfer protocol session is being
client_entry->nickname, hostname, portstr);
}
+/* Delivers SILC session detachment data indicated by `detach_data' to the
+ application. If application has issued SILC_COMMAND_DETACH command
+ the client session in the SILC network is not quit. The client remains
+ in the network but is detached. The detachment data may be used later
+ to resume the session in the SILC Network. The appliation is
+ responsible of saving the `detach_data', to for example in a file.
+
+ The detachment data can be given as argument to the functions
+ silc_client_connect_to_server, or silc_client_add_connection when
+ creating connection to remote server, inside SilcClientConnectionParams
+ structure. If it is provided the client library will attempt to resume
+ the session in the network. After the connection is created
+ successfully, the application is responsible of setting the user
+ interface for user into the same state it was before detaching (showing
+ same channels, channel modes, etc). It can do this by fetching the
+ information (like joined channels) from the client library. */
+
+void
+silc_detach(SilcClient client, SilcClientConnection conn,
+ const unsigned char *detach_data, SilcUInt32 detach_data_len)
+{
+ SILC_SERVER_REC *server = conn->context;
+ char *file;
+
+ /* Save the detachment data to file. */
+
+ file = silc_get_session_filename(server);
+ silc_file_writefile(file, detach_data, detach_data_len);
+ silc_free(file);
+}
+
+
/* SILC client operations */
SilcClientOperations ops = {
silc_say,
silc_notify,
silc_command,
silc_command_reply,
+ silc_connect,
+ silc_disconnect,
silc_get_auth_method,
silc_verify_public_key,
silc_ask_passphrase,
+ silc_failure,
silc_key_agreement,
silc_ftp,
+ silc_detach,
};
client_ops.h
- Author: Pekka Riikonen <priikone@silcnet.org>
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 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
void silc_notify(SilcClient client, SilcClientConnection conn,
SilcNotifyType type, ...);
void silc_command(SilcClient client, SilcClientConnection conn,
- SilcBool success, SilcCommand command, SilcStatus status,
- SilcUInt32 argc, unsigned char **argv);
+ SilcClientCommandContext cmd_context, bool success,
+ SilcCommand command, SilcStatus status);
void silc_command_reply(SilcClient client, SilcClientConnection conn,
- SilcCommand command, SilcStatus status,
- SilcStatus error, va_list ap);
+ SilcCommandPayload cmd_payload, bool success,
+ SilcCommand command, SilcStatus status, ...);
+void silc_connect(SilcClient client, SilcClientConnection conn,
+ SilcClientConnectionStatus status);
+void silc_disconnect(SilcClient client, SilcClientConnection conn,
+ SilcStatus status, const char *message);
void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
SilcAskPassphrase completion, void *context);
void silc_verify_public_key(SilcClient client, SilcClientConnection conn,
- SilcConnectionType conn_type,
- SilcPublicKey publi_key,
+ SilcSocketType conn_type, unsigned char *pk,
+ SilcUInt32 pk_len, SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context);
void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
char *hostname, SilcUInt16 port,
- SilcAuthMethod auth_meth,
SilcGetAuthMeth completion, void *context);
-void silc_key_agreement(SilcClient client, SilcClientConnection conn,
+void silc_failure(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure);
+bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry, const char *hostname,
- SilcUInt16 protocol, SilcUInt16 port);
+ SilcUInt16 port, SilcKeyAgreementCallback *completion,
+ void **context);
void silc_ftp(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry, SilcUInt32 session_id,
const char *hostname, SilcUInt16 port);
+void
+silc_detach(SilcClient client, SilcClientConnection conn,
+ const unsigned char *detach_data, SilcUInt32 detach_data_len);
char *
silc_unescape_data(const char *escaped_data, SilcUInt32 *length);
char *
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 Pekka Riikonen
+ Copyright (C) 1997 - 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
silc_free(pkcs);
}
-/* This checks stats for various SILC files and directories. First it
- checks if ~/.silc directory exist and is owned by the correct user. If
+/* This checks stats for various SILC files and directories. First it
+ checks if ~/.silc directory exist and is owned by the correct user. If
it doesn't exist, it will create the directory. After that it checks if
- user's Public and Private key files exists. If they doesn't exist they
+ user's Public and Private key files exists. If they doesn't exist they
will be created after return. */
int silc_client_check_silc_dir()
/* We'll take home path from /etc/passwd file to be sure. */
snprintf(filename, sizeof(filename) - 1, "%s/", get_irssi_dir());
- snprintf(servfilename, sizeof(servfilename) - 1, "%s/serverkeys",
+ snprintf(servfilename, sizeof(servfilename) - 1, "%s/serverkeys",
get_irssi_dir());
- snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/clientkeys",
+ snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/clientkeys",
get_irssi_dir());
- snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s/friends",
+ snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s/friends",
get_irssi_dir());
/*
return FALSE;
}
} else {
-
+
/* Check the owner of the dir */
- if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
+ if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
fprintf(stderr, "You don't seem to own `%s' directory\n",
filename);
return FALSE;
}
-
+
#if 0
/* Check the permissions of the dir */
if ((st.st_mode & 0777) != 0755) {
if ((chmod(filename, 0755)) == -1) {
- fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
+ fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
filename);
return FALSE;
}
return FALSE;
}
}
-
+
/*
* Check ~./silc/clientkeys directory
*/
return FALSE;
}
}
-
+
/*
* Check ~./silc/friends directory
*/
return FALSE;
}
}
-
+
/*
* Check Public and Private keys
*/
- snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
+ snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
filename, SILC_CLIENT_PUBLIC_KEY_NAME);
- snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
+ snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
filename, SILC_CLIENT_PRIVATE_KEY_NAME);
-
+
if ((stat(file_public_key, &st)) == -1) {
/* If file doesn't exist */
if (errno == ENOENT) {
fprintf(stdout, "Running SILC for the first time\n");
silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
SILC_CLIENT_DEF_PKCS_LEN,
- file_public_key, file_private_key,
+ file_public_key, file_private_key, NULL,
NULL, NULL, NULL, NULL, FALSE);
printf("Press <Enter> to continue...\n");
getchar();
return FALSE;
}
}
-
+
/* Check the owner of the public key */
- if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
+ if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
fprintf(stderr, "You don't seem to own your public key!?\n");
return FALSE;
}
-
+
if ((stat(file_private_key, &st)) == -1) {
/* If file doesn't exist */
if (errno == ENOENT) {
fprintf(stdout, "Your private key doesn't exist\n");
silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
SILC_CLIENT_DEF_PKCS_LEN,
- file_public_key, file_private_key,
+ file_public_key, file_private_key, NULL,
NULL, NULL, NULL, NULL, FALSE);
printf("Press <Enter> to continue...\n");
getchar();
return FALSE;
}
}
-
+
/* Check the owner of the private key */
- if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
+ if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
fprintf(stderr, "You don't seem to own your private key!?\n");
return FALSE;
}
-
+
/* Check the permissions for the private key */
if ((st.st_mode & 0777) != 0600) {
fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
"Trying to change them ... ", file_private_key);
if ((chmod(file_private_key, 0600)) == -1) {
fprintf(stderr,
- "Failed to change permissions for private key file!\n"
+ "Failed to change permissions for private key file!\n"
"Permissions for your private key file must be 0600.\n");
return FALSE;
}
memset(pub, 0, sizeof(pub));
snprintf(pub, sizeof(pub) - 1, "%s/%s",
get_irssi_dir(), SILC_CLIENT_PUBLIC_KEY_NAME);
-
+
/* Try loading first with "" passphrase, for those that didn't set
passphrase for private key, and only if that fails let it prompt
for passphrase. */
- ret = silc_load_key_pair(pub, prv, "", &irssi_pubkey, &irssi_privkey);
+ ret = silc_load_key_pair(pub, prv, "", &client->pkcs, &client->public_key,
+ &client->private_key);
if (!ret)
- ret = silc_load_key_pair(pub, prv, NULL, &irssi_pubkey, &irssi_privkey);
-
- if (!ret)
- SILC_LOG_ERROR(("Could not load key pair"));
-
+ ret = silc_load_key_pair(pub, prv, NULL, &client->pkcs,
+ &client->public_key, &client->private_key);
return ret;
}
#undef PACKAGE
#undef VERSION
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_ops.h"
#include "silc-core.h"
/*
silc-channels.c : irssi
- Copyright (C) 2000 - 2001, 2004, 2006, 2007 Timo Sirainen
- Pekka Riikonen <priikone@silcnet.org>
+ Copyright (C) 2000 - 2001, 2004 Timo Sirainen
+ Pekka Riikonen <priikone@poseidon.pspt.fi>
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
#include "silc-commands.h"
void sig_mime(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
- const char *blob, const char *nick, int verified)
+ const char *blob, const char *nick, int verified)
{
- unsigned char *message;
- SilcUInt32 message_len;
- SilcMime mime;
+ char type[128], enc[128];
+ unsigned char *data, *message;
+ SilcUInt32 data_len, message_len;
if (!(IS_SILC_SERVER(server)))
return;
message = silc_unescape_data(blob, &message_len);
- mime = silc_mime_decode(NULL, message, message_len);
- if (!mime) {
+ memset(type, 0, sizeof(type));
+ memset(enc, 0, sizeof(enc));
+
+ if (!silc_mime_parse(message, message_len, NULL, 0, type, sizeof(type) - 1,
+ enc, sizeof(enc) - 1, &data, &data_len)) {
silc_free(message);
return;
}
printformat_module("fe-common/silc", server,
- channel == NULL ? NULL : channel->name,
- MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
- nick == NULL ? "[<unknown>]" : nick,
- silc_mime_get_field(mime, "Content-Type"));
+ channel == NULL ? NULL : channel->name,
+ MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
+ nick == NULL ? "[<unknown>]" : nick, type);
silc_free(message);
- silc_mime_free(mime);
+
}
SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
const char *channels, int automatic)
{
char **list, **tmp;
+ char *channel, *key;
SILC_CHANNEL_REC *chanrec;
+ CHANNEL_SETUP_REC *schannel;
+ GString *tmpstr;
list = g_strsplit(channels, ",", -1);
for (tmp = list; *tmp != NULL; tmp++) {
if (chanrec)
continue;
- silc_command_exec(server, "JOIN", *tmp);
+ channel = *tmp;
+ key = strchr(channel, ' ');
+ if (key != NULL) {
+ *key = '\0';
+ key++;
+ }
+ tmpstr = g_string_new(NULL);
+
+ schannel = channel_setup_find(channel, server->connrec->chatnet);
+ if (key && *key != '\0')
+ g_string_sprintfa(tmpstr, "%s %s", channel, key);
+ else if (schannel->password && schannel->password[0] != '\0')
+ g_string_sprintfa(tmpstr, "%s %s", channel, schannel->password);
+ else
+ g_string_sprintfa(tmpstr, "%s", channel);
+
+ silc_command_exec(server, "JOIN", tmpstr->str);
+
+ g_string_free(tmpstr, FALSE);
}
g_strfreev(list);
static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
{
- if (IS_SILC_SERVER(server) && server->conn)
+ if (IS_SILC_SERVER(server) && server->conn && server->conn->sock)
silc_command_exec(server, "QUIT", msg);
}
+static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
+{
+ silc_client_stop(silc_client);
+}
+
/* Find Irssi channel entry by SILC channel entry */
SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
char *message = NULL;
int target_type;
void *free_arg;
- SilcBool sign = FALSE;
CMD_SILC_SERVER(server);
if (!IS_SILC_SERVER(server) || !server->connected)
if (target != NULL) {
if (target_type == SEND_TARGET_CHANNEL) {
- sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
- settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
if (silc_send_channel(server, target, (message != NULL ? message : msg),
SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
- (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
+ (g_hash_table_lookup(optlist, "sign") != NULL ?
+ SILC_MESSAGE_FLAG_SIGNED : 0))) {
if (g_hash_table_lookup(optlist, "sign"))
signal_emit("message silc signed_own_action", 3, server, msg, target);
else
signal_emit("message silc own_action", 3, server, msg, target);
}
} else {
- sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
- settings_get_bool("sign_private_messages") ? TRUE : FALSE);
if (silc_send_msg(server, target, (message != NULL ? message : msg),
(message != NULL ? strlen(message) : strlen(msg)),
SILC_MESSAGE_FLAG_ACTION | SILC_MESSAGE_FLAG_UTF8 |
- (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
+ (g_hash_table_lookup(optlist, "sign") != NULL ?
+ SILC_MESSAGE_FLAG_SIGNED : 0))) {
if (g_hash_table_lookup(optlist, "sign"))
signal_emit("message silc signed_own_private_action", 3,
server, msg, target);
char *message = NULL;
int target_type;
void *free_arg;
- SilcBool sign;
CMD_SILC_SERVER(server);
if (!IS_SILC_SERVER(server) || !server->connected)
if (target != NULL) {
if (target_type == SEND_TARGET_CHANNEL) {
- sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
- settings_get_bool("sign_channel_messages") ? TRUE : FALSE);
if (silc_send_channel(server, target, (message != NULL ? message : msg),
SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
- (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
+ (g_hash_table_lookup(optlist, "sign") != NULL ?
+ SILC_MESSAGE_FLAG_SIGNED : 0))) {
if (g_hash_table_lookup(optlist, "sign"))
signal_emit("message silc signed_own_notice", 3, server, msg, target);
else
signal_emit("message silc own_notice", 3, server, msg, target);
}
} else {
- sign = (g_hash_table_lookup(optlist, "sign") ? TRUE :
- settings_get_bool("sign_private_messages") ? TRUE : FALSE);
if (silc_send_msg(server, target, (message != NULL ? message : msg),
(message != NULL ? strlen(message) : strlen(msg)),
SILC_MESSAGE_FLAG_NOTICE | SILC_MESSAGE_FLAG_UTF8 |
- (sign ? SILC_MESSAGE_FLAG_SIGNED : 0))) {
+ (g_hash_table_lookup(optlist, "sign") != NULL ?
+ SILC_MESSAGE_FLAG_SIGNED : 0))) {
if (g_hash_table_lookup(optlist, "sign"))
signal_emit("message silc signed_own_private_notice", 3,
server, msg, target);
}
typedef struct {
- SILC_SERVER_REC *server;
int type; /* 1 = msg, 2 = channel */
- SilcBool responder;
+ bool responder;
+ SILC_SERVER_REC *server;
} *KeyInternal;
/* Key agreement callback that is called after the key agreement protocol
SilcClientConnection conn,
SilcClientEntry client_entry,
SilcKeyAgreementStatus status,
- SilcSKEKeyMaterial key,
+ SilcSKEKeyMaterial *key,
void *context)
{
KeyInternal i = (KeyInternal)context;
/* Set the private key for this client */
silc_client_del_private_message_key(client, conn, client_entry);
silc_client_add_private_message_key_ske(client, conn, client_entry,
- NULL, NULL, key);
+ NULL, NULL, key, i->responder);
printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT_PRIVMSG,
client_entry->nickname);
break;
case SILC_KEY_AGREEMENT_ERROR:
- case SILC_KEY_AGREEMENT_NO_MEMORY:
printformat_module("fe-common/silc", i->server, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT_ERROR, client_entry->nickname);
break;
static void silc_client_command_key_get_clients(SilcClient client,
SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
void *context)
{
KeyGetClients internal = (KeyGetClients)context;
WI_ITEM_REC *item)
{
SilcClientConnection conn;
- SilcClientEntry client_entry = NULL;
- SilcDList clients;
+ SilcClientEntry *entrys, client_entry = NULL;
+ SilcUInt32 entry_count;
SILC_CHANNEL_REC *chanrec = NULL;
SilcChannelEntry channel_entry = NULL;
- char nickname[128 + 1], *tmp;
+ char *nickname = NULL, *tmp;
int command = 0, port = 0, type = 0;
char *hostname = NULL;
KeyInternal internal = NULL;
unsigned char **argv;
SilcUInt32 *argv_lens, *argv_types;
char *bindhost = NULL;
- SilcChannelPrivateKey ch = NULL;
- SilcDList ckeys;
- SilcBool udp = FALSE;
- int i;
CMD_SILC_SERVER(server);
if (type == 1) {
if (argv[2][0] == '*') {
- strcpy(nickname, "*");
+ nickname = strdup("*");
} else {
/* Parse the typed nickname. */
- if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
+ if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
return;
}
/* Find client entry */
- clients = silc_client_get_clients_local(silc_client, conn, nickname,
- argv[2]);
- if (!clients) {
+ entrys = silc_client_get_clients_local(silc_client, conn, nickname,
+ argv[2], &entry_count);
+ if (!entrys) {
KeyGetClients inter = silc_calloc(1, sizeof(*inter));
inter->server = server;
inter->data = strdup(data);
silc_client_command_key_get_clients, inter);
goto out;
}
-
- client_entry = silc_dlist_get(clients);
- silc_client_list_free(silc_client, conn, clients);
+ client_entry = entrys[0];
+ silc_free(entrys);
}
}
if (argc >= 5) {
char *cipher = NULL, *hmac = NULL;
- if (argc >= 6)
- cipher = argv[5];
- if (argc >= 7)
- hmac = argv[6];
-
if (type == 1 && client_entry) {
/* Set private message key */
+ bool responder = FALSE;
+
silc_client_del_private_message_key(silc_client, conn, client_entry);
+
+ if (argc >= 6) {
+ if (!strcasecmp(argv[5], "-responder"))
+ responder = TRUE;
+ else
+ cipher = argv[5];
+ }
+ if (argc >= 7) {
+ if (!strcasecmp(argv[6], "-responder"))
+ responder = TRUE;
+ else
+ hmac = argv[6];
+ }
+ if (argc >= 8) {
+ if (!strcasecmp(argv[7], "-responder"))
+ responder = TRUE;
+ }
+
silc_client_add_private_message_key(silc_client, conn, client_entry,
cipher, hmac,
- argv[4], argv_lens[4]);
+ argv[4], argv_lens[4],
+ (argv[4][0] == '*' ?
+ TRUE : FALSE), responder);
+
+ /* Send the key to the remote client so that it starts using it
+ too. */
+ /* XXX for now we don't do this. This feature is pretty stupid
+ and should perhaps be removed altogether from SILC.
+ silc_client_send_private_message_key(silc_client, conn,
+ client_entry, TRUE);
+ */
} else if (type == 2) {
/* Set private channel key */
if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
goto out;
}
+ if (argc >= 6)
+ cipher = argv[5];
+ if (argc >= 7)
+ hmac = argv[6];
+
if (!silc_client_add_channel_private_key(silc_client, conn,
channel_entry, NULL,
cipher, hmac,
silc_client_del_private_message_key(silc_client, conn, client_entry);
} else if (type == 2) {
/* Unset channel key(s) */
+ SilcChannelPrivateKey *keys;
+ SilcUInt32 keys_count;
int number;
if (argc == 4)
if (argc > 4) {
number = atoi(argv[4]);
- ckeys = silc_client_list_channel_private_keys(silc_client, conn,
- channel_entry);
- if (!ckeys)
+ keys = silc_client_list_channel_private_keys(silc_client, conn,
+ channel_entry,
+ &keys_count);
+ if (!keys)
goto out;
- if (!number || number > silc_dlist_count(ckeys)) {
- silc_dlist_uninit(ckeys);
+ if (!number || number > keys_count) {
+ silc_client_free_channel_private_keys(keys, keys_count);
goto out;
}
- for (i = 0; i < number; i++)
- ch = silc_dlist_get(ckeys);
- if (!ch)
- goto out;
-
silc_client_del_channel_private_key(silc_client, conn, channel_entry,
- ch);
- silc_dlist_uninit(ckeys);
+ keys[number - 1]);
+ silc_client_free_channel_private_keys(keys, keys_count);
}
goto out;
silc_client_free_private_message_keys(keys, keys_count);
} else if (type == 2) {
- int len;
+ SilcChannelPrivateKey *keys;
+ SilcUInt32 keys_count;
+ int k, i, len;
char buf[1024];
- ckeys = silc_client_list_channel_private_keys(silc_client, conn,
- channel_entry);
+ keys = silc_client_list_channel_private_keys(silc_client, conn,
+ channel_entry,
+ &keys_count);
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_CH_PRIVATE_KEY_LIST,
channel_entry->channel_name);
- if (!ckeys)
+ if (!keys)
goto out;
- while ((ch = silc_dlist_get(ckeys))) {
+ for (k = 0; k < keys_count; k++) {
memset(buf, 0, sizeof(buf));
strncat(buf, " ", 2);
- len = strlen(silc_cipher_get_name(ch->cipher));
- strncat(buf, silc_cipher_get_name(ch->cipher),
+ len = strlen(silc_cipher_get_name(keys[k]->cipher));
+ strncat(buf, silc_cipher_get_name(keys[k]->cipher),
len > 16 ? 16 : len);
if (len < 16)
for (i = 0; i < 16 - len; i++)
strcat(buf, " ");
strcat(buf, " ");
- len = strlen(silc_hmac_get_name(ch->hmac));
- strncat(buf, silc_hmac_get_name(ch->hmac), len > 16 ? 16 : len);
+ len = strlen(silc_hmac_get_name(keys[k]->hmac));
+ strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
if (len < 16)
for (i = 0; i < 16 - len; i++)
strcat(buf, " ");
silc_say(silc_client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", buf);
}
- silc_dlist_uninit(ckeys);
+ silc_client_free_channel_private_keys(keys, keys_count);
}
goto out;
if (argc >= 5)
hostname = argv[4];
- if (argc >= 6) {
- if (!strcasecmp(argv[5], "UDP"))
- udp = TRUE;
- else
- port = atoi(argv[5]);
- }
- if (argc >= 7)
- udp = TRUE;
+ if (argc >= 6)
+ port = atoi(argv[5]);
internal = silc_calloc(1, sizeof(*internal));
internal->type = type;
if (!hostname) {
if (settings_get_bool("use_auto_addr")) {
+
hostname = (char *)settings_get_str("auto_public_ip");
/* If the hostname isn't set, treat this case as if auto_public_ip
if (argc >= 5)
hostname = argv[4];
- if (argc >= 6) {
- if (!strcasecmp(argv[5], "UDP"))
- udp = TRUE;
- else
- port = atoi(argv[5]);
- }
- if (argc >= 7)
- udp = TRUE;
+ if (argc >= 6)
+ port = atoi(argv[5]);
internal = silc_calloc(1, sizeof(*internal));
internal->type = type;
command = 6;
if (type == 2) {
/* Unset channel key(s) */
+ SilcChannelPrivateKey *keys;
+ SilcUInt32 keys_count;
int number;
- ckeys = silc_client_list_channel_private_keys(silc_client, conn,
- channel_entry);
- if (!ckeys)
+ keys = silc_client_list_channel_private_keys(silc_client, conn,
+ channel_entry,
+ &keys_count);
+ if (!keys)
goto out;
if (argc == 4) {
chanrec->cur_key++;
- if (chanrec->cur_key >= silc_dlist_count(ckeys))
+ if (chanrec->cur_key >= keys_count)
chanrec->cur_key = 0;
}
if (argc > 4) {
number = atoi(argv[4]);
- if (!number || number > silc_dlist_count(ckeys))
+ if (!number || number > keys_count)
chanrec->cur_key = 0;
else
chanrec->cur_key = number - 1;
}
- for (i = 0; i < chanrec->cur_key; i++)
- ch = silc_dlist_get(ckeys);
- if (!ch)
- goto out;
-
/* Set the current channel private key */
silc_client_current_channel_private_key(silc_client, conn,
- channel_entry, ch);
+ channel_entry,
+ keys[chanrec->cur_key]);
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
- SILCTXT_CH_PRIVATE_KEY_CHANGE, i + 1,
+ SILCTXT_CH_PRIVATE_KEY_CHANGE, chanrec->cur_key + 1,
channel_entry->channel_name);
- silc_dlist_uninit(ckeys);
+ silc_client_free_channel_private_keys(keys, keys_count);
goto out;
}
}
}
if (command == 4 && client_entry) {
- SilcClientConnectionParams params;
-
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT, argv[2]);
internal->responder = TRUE;
-
- memset(¶ms, 0, sizeof(params));
- params.local_ip = hostname;
- params.bind_ip = bindhost;
- params.local_port = port;
- params.udp = udp;
- params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
-
silc_client_send_key_agreement(
- silc_client, conn, client_entry, ¶ms,
- irssi_pubkey, irssi_privkey,
+ silc_client, conn, client_entry, hostname,
+ bindhost, port,
+ settings_get_int("key_exchange_timeout_secs"),
keyagr_completion, internal);
if (!hostname)
silc_free(internal);
}
if (command == 5 && client_entry && hostname) {
- SilcClientConnectionParams params;
-
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_KEY_AGREEMENT_NEGOTIATE, argv[2]);
internal->responder = FALSE;
-
- memset(¶ms, 0, sizeof(params));
- if (udp) {
- if (settings_get_bool("use_auto_addr")) {
- params.local_ip = (char *)settings_get_str("auto_public_ip");
- if ((params.local_ip) && (*params.local_ip == '\0')) {
- params.local_ip = silc_net_localip();
- } else {
- params.bind_ip = (char *)settings_get_str("auto_bind_ip");
- if ((params.bind_ip) && (*params.bind_ip == '\0'))
- params.bind_ip = NULL;
- params.local_port = settings_get_int("auto_bind_port");
- }
- }
- if (!params.local_ip)
- params.local_ip = silc_net_localip();
- }
- params.udp = udp;
- params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
-
- silc_client_perform_key_agreement(silc_client, conn, client_entry, ¶ms,
- irssi_pubkey, irssi_privkey,
+ silc_client_perform_key_agreement(silc_client, conn, client_entry,
hostname, port, keyagr_completion,
internal);
goto out;
}
out:
- return;
+ silc_free(nickname);
}
void silc_list_key(const char *pub_filename, int verbose)
{
SilcPublicKey public_key;
SilcPublicKeyIdentifier ident;
- SilcSILCPublicKey silc_pubkey;
char *fingerprint, *babbleprint;
unsigned char *pk;
SilcUInt32 pk_len;
+ SilcPKCS pkcs;
SilcUInt32 key_len = 0;
int is_server_key = (strstr(pub_filename, "serverkeys") != NULL);
- if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
- printformat_module("fe-common/silc", NULL, NULL,
- MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
- pub_filename);
- return;
- }
-
- /* Print only SILC public keys */
- if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
- printformat_module("fe-common/silc", NULL, NULL,
- MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
- pub_filename);
- return;
- }
+ if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
+ SILC_PKCS_FILE_PEM) == FALSE)
+ if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
+ SILC_PKCS_FILE_BIN) == FALSE) {
+ printformat_module("fe-common/silc", NULL, NULL,
+ MSGLEVEL_CRAP, SILCTXT_LISTKEY_LOADPUB,
+ pub_filename);
+ return;
+ }
- silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
- ident = &silc_pubkey->identifier;
+ ident = silc_pkcs_decode_identifier(public_key->identifier);
pk = silc_pkcs_public_key_encode(public_key, &pk_len);
fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
- key_len = silc_pkcs_public_key_get_len(public_key);
+
+ if (silc_pkcs_alloc(public_key->name, &pkcs)) {
+ key_len = silc_pkcs_public_key_set(pkcs, public_key);
+ silc_pkcs_free(pkcs);
+ }
printformat_module("fe-common/silc", NULL, NULL,
MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_FILE,
if (verbose)
printformat_module("fe-common/silc", NULL, NULL,
MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_ALG,
- silc_pkcs_get_name(public_key));
+ public_key->name);
if (key_len && verbose)
printformat_module("fe-common/silc", NULL, NULL,
MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_BITS,
(unsigned int)key_len);
- if (ident->version && verbose)
- printformat_module("fe-common/silc", NULL, NULL,
- MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_VER,
- ident->version);
if (ident->realname && (!is_server_key || verbose))
printformat_module("fe-common/silc", NULL, NULL,
MSGLEVEL_CRAP, SILCTXT_LISTKEY_PUB_RN,
silc_free(babbleprint);
silc_free(pk);
silc_pkcs_public_key_free(public_key);
+ silc_pkcs_free_identifier(ident);
+
}
+
void silc_list_keys_in_dir(const char *dirname, const char *where)
{
DIR *dir;
dir = opendir(dirname);
if (dir == NULL)
- cmd_return_error(CMDERR_ERRNO);
+ cmd_return_error(CMDERR_ERRNO);
printformat_module("fe-common/silc", NULL, NULL,
MSGLEVEL_CRAP, SILCTXT_LISTKEY_LIST,
list_key:
silc_list_key(path, TRUE);
+
}
/* Lists locally saved client and server public keys. */
signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_add("server connected", (SIGNAL_FUNC) sig_connected);
signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
+ signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
signal_add("mime", (SIGNAL_FUNC) sig_mime);
command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
+ signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
signal_remove("mime", (SIGNAL_FUNC) sig_mime);
command_unbind("part", (SIGNAL_FUNC) command_part);
}
bool silc_queue_command_call(SilcClient client,
- SilcClientConnection conn,
- const char *command_line, ...)
+ SilcClientConnection conn,
+ const char *command_line, ...)
{
va_list ap;
char *cmd = (char *) command_line;
return TRUE;
}
-bool silc_queue_get_state(SilcClientConnection conn)
-{
+bool silc_queue_get_state(SilcClientConnection conn) {
return g_hash_table_lookup(cmd_queues, conn) != NULL;
}
silc-core.c
- Author: Pekka Riikonen <priikone@silcnet.org>
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 2001 - 2007 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
static int idletag = -1;
-/* SILC Client */
SilcClient silc_client = NULL;
extern SilcClientOperations ops;
-/* Our keypair */
-SilcPublicKey irssi_pubkey = NULL;
-SilcPrivateKey irssi_privkey = NULL;
-
-char *opt_nickname = NULL;
-char *opt_hostname = NULL;
-
-/* Default hash function */
-SilcHash sha1hash = NULL;
-
void silc_expandos_init(void);
void silc_expandos_deinit(void);
static void silc_init_userinfo(void)
{
- const char *set, *nick, *user_name, *str;
- char *tmp;
+ const char *set, *nick, *user_name;
+ char *str;
/* check if nick/username/realname wasn't read from setup.. */
set = settings_get_str("real_name");
str != NULL ? str : silc_get_real_name());
}
- /* Check that real name is UTF-8 encoded */
- set = settings_get_str("real_name");
- if (!silc_utf8_valid(set, strlen(set))) {
- int len = silc_utf8_encoded_len(set, strlen(set), SILC_STRING_LOCALE);
- tmp = silc_calloc(len, sizeof(*tmp));
- if (tmp) {
- silc_utf8_encode(set, strlen(set), SILC_STRING_LOCALE, tmp, len);
- settings_set_str("real_name", tmp);
- silc_free(tmp);
- }
- }
-
/* username */
user_name = settings_get_str("user_name");
if (user_name == NULL || *user_name == '\0') {
/* alternate nick */
set = settings_get_str("alternate_nick");
if (set == NULL || *set == '\0') {
- tmp = g_strconcat(nick, "_", NULL);
- settings_set_str("alternate_nick", tmp);
- g_free(tmp);
+ str = g_strconcat(nick, "_", NULL);
+ settings_set_str("alternate_nick", str);
+ g_free(str);
}
/* host name */
return TRUE;
}
-static bool silc_log_stderr(SilcLogType type, char *message, void *context)
+static void silc_nickname_format_parse(const char *nickname,
+ char **ret_nickname)
{
- fprintf(stderr, "%s: %s\n",
- (type == SILC_LOG_INFO ? "[Info]" :
- type == SILC_LOG_WARNING ? "[Warning]" : "[Error]"), message);
- return TRUE;
+ silc_parse_userfqdn(nickname, ret_nickname, NULL);
}
static void silc_register_cipher(SilcClient client, const char *cipher)
const char *arg, void *data)
{
if (strcmp(opt->longName, "nick") == 0) {
- g_free(opt_nickname);
- opt_nickname = g_strdup(arg);
+ g_free(silc_client->nickname);
+ silc_client->nickname = g_strdup(arg);
}
if (strcmp(opt->longName, "hostname") == 0) {
- silc_free(opt_hostname);
- opt_hostname = strdup(arg);
+ silc_free(silc_client->hostname);
+ silc_client->hostname = g_strdup(arg);
}
if (strcmp(opt->longName, "list-ciphers") == 0) {
silc_pkcs_register_default();
silc_hash_register_default();
silc_hmac_register_default();
- silc_create_key_pair(opt_pkcs, opt_bits, NULL, NULL,
+ silc_create_key_pair(opt_pkcs, opt_bits, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, TRUE);
exit(0);
}
silc_pkcs_register_default();
silc_hash_register_default();
silc_hmac_register_default();
- silc_show_public_key_file((char *)arg);
+ silc_show_public_key((char *)arg);
exit(0);
}
}
-/* Called to indicate the client library has stopped. */
-
-static void
-silc_stopped(SilcClient client, void *context)
-{
- SILC_LOG_DEBUG(("Client library has stopped"));
- if (idletag != -1)
- g_source_remove(idletag);
- signal_emit("chat protocol deinit", 1,
- chat_protocol_find("SILC"));
-}
-
-static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
-{
- silc_client_stop(silc_client, silc_stopped, NULL);
-}
-
-/* Called to indicate the client library is running. */
-
-static void
-silc_running(SilcClient client, void *context)
-{
- SILC_LOG_DEBUG(("Client library is running"));
-}
-
static void sig_init_finished(void)
{
/* Check ~/.silc directory and public and private keys */
- if (!silc_client_check_silc_dir()) {
- sleep(1);
- exit(1);
- return;
- }
+ if (!silc_client_check_silc_dir())
+ goto err;
/* Load public and private key */
- if (!silc_client_load_keys(silc_client)) {
- sleep(1);
- exit(1);
- return;
- }
+ if (!silc_client_load_keys(silc_client))
+ goto err;
/* Initialize the SILC client */
- opt_hostname = (opt_hostname ? opt_hostname : silc_net_localhost());
- if (!silc_client_init(silc_client, settings_get_str("user_name"),
- opt_hostname, settings_get_str("real_name"),
- silc_running, NULL)) {
- sleep(1);
- exit(1);
- return;
- }
-
- silc_log_set_callback(SILC_LOG_INFO, silc_log_misc, NULL);
- silc_log_set_callback(SILC_LOG_WARNING, silc_log_misc, NULL);
- silc_log_set_callback(SILC_LOG_ERROR, silc_log_misc, NULL);
- silc_log_set_callback(SILC_LOG_FATAL, silc_log_misc, NULL);
-
- silc_hash_alloc("sha1", &sha1hash);
+ if (!silc_client_init(silc_client))
+ goto err;
/* register SILC scheduler */
idletag = g_timeout_add(5, (GSourceFunc) my_silc_scheduler, NULL);
+
+ return;
+
+err:
+ sleep(2);
+ exit(1);
}
/* Init SILC. Called from src/fe-text/silc.c */
settings_add_str("server", "crypto_default_hmac", SILC_DEFAULT_HMAC);
settings_add_int("server", "key_exchange_timeout_secs", 120);
settings_add_int("server", "key_exchange_rekey_secs", 3600);
- settings_add_bool("server", "key_exchange_rekey_pfs", FALSE);
+ settings_add_int("server", "connauth_request_secs", 2);
settings_add_int("server", "heartbeat", 300);
settings_add_bool("server", "ignore_message_signatures", FALSE);
settings_add_str("server", "session_filename", "session.$chatnet");
- settings_add_bool("server", "sign_channel_messages", FALSE);
- settings_add_bool("server", "sign_private_messages", FALSE);
/* Requested Attributes settings */
settings_add_bool("silc", "attr_allow", TRUE);
signal_add("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
- signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
silc_init_userinfo();
- silc_log_set_callback(SILC_LOG_INFO, silc_log_stderr, NULL);
- silc_log_set_callback(SILC_LOG_WARNING, silc_log_stderr, NULL);
- silc_log_set_callback(SILC_LOG_ERROR, silc_log_stderr, NULL);
- silc_log_set_callback(SILC_LOG_FATAL, silc_log_stderr, NULL);
-
/* Initialize client parameters */
memset(¶ms, 0, sizeof(params));
strcat(params.nickname_format, "%n@%h%a");
+ params.nickname_parse = silc_nickname_format_parse;
+ params.rekey_secs = settings_get_int("key_exchange_rekey_secs");
+ params.connauth_request_secs = settings_get_int("connauth_request_secs");
/* Allocate SILC client */
silc_client = silc_client_alloc(&ops, ¶ms, NULL, silc_version_string);
silc_register_hmac(silc_client, def_hmac);
silc_pkcs_register_default();
+ /* Get user information */
+ silc_client->username = g_strdup(settings_get_str("user_name"));
+ silc_client->nickname = g_strdup(settings_get_str("nick"));
+ if (settings_get_str("hostname") == NULL ||
+ *(settings_get_str("hostname")) == '\0')
+ silc_client->hostname = silc_net_localhost();
+ else
+ silc_client->hostname = g_strdup(settings_get_str("hostname"));
+ silc_client->realname = g_strdup(settings_get_str("real_name"));
+
+ silc_log_set_callback(SILC_LOG_INFO, silc_log_misc, NULL);
+ silc_log_set_callback(SILC_LOG_WARNING, silc_log_misc, NULL);
+ silc_log_set_callback(SILC_LOG_ERROR, silc_log_misc, NULL);
+ silc_log_set_callback(SILC_LOG_FATAL, silc_log_misc, NULL);
+
/* Register SILC to the irssi */
rec = g_new0(CHAT_PROTOCOL_REC, 1);
rec->name = "SILC";
if (idletag != -1)
g_source_remove(idletag);
- if (opt_hostname)
- silc_free(opt_hostname);
- if (opt_nickname)
- g_free(opt_nickname);
-
+ signal_emit("chat protocol deinit", 1,
+ chat_protocol_find("SILC"));
signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
- signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
-
- silc_hash_free(sha1hash);
silc_queue_deinit();
silc_server_deinit();
chat_protocol_unregister("SILC");
- silc_pkcs_public_key_free(irssi_pubkey);
- silc_pkcs_private_key_free(irssi_privkey);
+ g_free(silc_client->username);
+ g_free(silc_client->realname);
+ silc_free(silc_client->hostname);
+ silc_pkcs_free(silc_client->pkcs);
+ silc_pkcs_private_key_free(silc_client->private_key);
+ silc_pkcs_public_key_free(silc_client->public_key);
silc_client_free(silc_client);
}
#define SILC_CLIENT_DEF_PKCS_LEN 2048
extern SilcClient silc_client;
-extern SilcHash sha1hash;
-extern SilcPublicKey irssi_pubkey;
-extern SilcPrivateKey irssi_privkey;
-extern char *opt_nickname;
#define IS_SILC_ITEM(rec) (IS_SILC_CHANNEL(rec) || IS_SILC_QUERY(rec))
#include "silc-servers.h"
+#define SILC_CLIENT_LAG_PING_ID 0x1337
+
static int timeout_tag;
-static SilcBool lag_event_pong(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap);
+static void lag_event_pong(SILC_SERVER_REC *server,
+ SilcClientCommandReplyContext cmd);
static void lag_get(SILC_SERVER_REC *server)
{
g_get_current_time(&server->lag_sent);
server->lag_last_check = time(NULL);
- /* Send PING */
- idp = silc_id_payload_encode(&server->conn->remote_id.u.server_id,
- SILC_ID_SERVER);
+ /* register pending callback & send ping */
+ silc_client_command_pending(server->conn, SILC_COMMAND_PING,
+ SILC_CLIENT_LAG_PING_ID,
+ (SilcCommandCb)lag_event_pong, (void *)server);
+ idp = silc_id_payload_encode(server->conn->remote_id, SILC_ID_SERVER);
silc_client_command_send(silc_client, server->conn,
- SILC_COMMAND_PING, lag_event_pong, server,
- 1, 1, silc_buffer_data(idp),
- silc_buffer_len(idp));
+ SILC_COMMAND_PING, SILC_CLIENT_LAG_PING_ID,
+ 1, 1, idp->data, idp->len);
silc_buffer_free(idp);
}
-static SilcBool lag_event_pong(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
+static void lag_event_pong(SILC_SERVER_REC *server,
+ SilcClientCommandReplyContext cmd)
{
- SILC_SERVER_REC *server = context;
GTimeVal now;
- if (status != SILC_STATUS_OK) {
+ if (cmd->error != SILC_STATUS_OK) {
+
/* if the ping failed for some reason, try it again */
lag_get(server);
- return TRUE;
+ return;
+
}
if (server->lag_sent.tv_sec == 0) {
- /* not expecting lag reply. */
- return TRUE;
+ /* not expecting lag reply.. */
+ return;
}
g_get_current_time(&now);
memset(&server->lag_sent, 0, sizeof(server->lag_sent));
signal_emit("server lag", 1, server);
-
- return TRUE;
}
static int sig_check_lag(void)
{
/* silc-client will need those... silc-plugin uses irc defaults */
settings_add_int("misc", "lag_check_time", 60);
- settings_add_int("misc", "lag_max_before_disconnect", 300);
+ settings_add_int("misc", "lag_max_before_disconnect", 300);
timeout_tag = g_timeout_add(1000, (GSourceFunc) sig_check_lag, NULL);
}
/*
silc-nicklist.c : irssi
- Copyright (C) 2000, 2003, 2006 Timo Sirainen, Pekka Riikonen
+ Copyright (C) 2000, 2003 Timo Sirainen, 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
return NULL;
if (!user->client)
return NULL;
- if (!user->client->nickname[0])
+ if (!user->client->nickname)
return NULL;
rec = g_new0(SILC_NICK_REC, 1);
SILC_NICK_REC *silc_nicklist_find(SILC_CHANNEL_REC *channel,
SilcClientEntry client)
{
- if (!client || !client->nickname[0])
+ if (!client || !client->nickname)
return NULL;
return (SILC_NICK_REC *)nicklist_find_unique(CHANNEL(channel),
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 Pekka Riikonen
+ Copyright (C) 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
const char *sv;
SilcUInt32 tmp_len, mask;
SilcAttributeObjService service;
- SilcMime mime;
+ SilcAttributeObjMime mime;
SilcAttributeObjGeo geo;
SilcAttributeObjDevice dev;
SilcAttributeObjPk pk;
bool allowed;
memset(&service, 0, sizeof(service));
+ memset(&mime, 0, sizeof(mime));
memset(&geo, 0, sizeof(geo));
memset(&dev, 0, sizeof(dev));
memset(&pk, 0, sizeof(pk));
SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
tmp = silc_file_readfile(sv, &tmp_len);
if (tmp) {
- mime = silc_mime_decode(NULL, tmp, tmp_len);
- if (mime)
- silc_client_attribute_add(silc_client, conn,
- SILC_ATTRIBUTE_STATUS_MESSAGE, mime,
- sizeof(*mime));
+ tmp[tmp_len] = 0;
+ mime.mime = (const unsigned char *)tmp;
+ mime.mime_len = tmp_len;
+ silc_client_attribute_add(silc_client, conn,
+ SILC_ATTRIBUTE_STATUS_MESSAGE, &mime,
+ sizeof(mime));
}
silc_free(tmp);
}
SILC_SERVER_REC *server;
char *name;
SilcAttributeObjPk userpk;
- SilcPublicKey public_key;
SilcVCardStruct vcard;
- SilcMime message;
- SilcMime extension;
+ SilcAttributeObjMime message;
+ SilcAttributeObjMime extension;
bool nopk;
} *AttrVerify;
case SILC_ATTRIBUTE_STATUS_MESSAGE:
{
- verify->message = silc_mime_alloc();
- if (!verify->message)
- continue;
- if (!silc_attribute_get_object(attr, (void *)verify->message,
- sizeof(*verify->message)))
+ if (!silc_attribute_get_object(attr, (void *)&verify->message,
+ sizeof(verify->message)))
continue;
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE,
case SILC_ATTRIBUTE_EXTENSION:
{
- verify->extension = silc_mime_alloc();
- if (!verify->extension)
- continue;
- if (!silc_attribute_get_object(attr, (void *)verify->extension,
- sizeof(*verify->extension)))
+ if (!silc_attribute_get_object(attr, (void *)&verify->extension,
+ sizeof(verify->extension)))
continue;
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ATTR_EXTENSION,
/* Handle the signature verifications and public key verifying here */
- if (verify->userpk.data) {
- SilcPKCSType type = 0;
-
- if (!strcmp(verify->userpk.type, "silc-rsa"))
- type = SILC_PKCS_SILC;
- else if (!strcmp(verify->userpk.type, "ssh-rsa"))
- type = SILC_PKCS_SSH2;
- else if (!strcmp(verify->userpk.type, "x509v3-sign-rsa"))
- type = SILC_PKCS_X509V3;
- else if (!strcmp(verify->userpk.type, "pgp-sign-rsa"))
- type = SILC_PKCS_OPENPGP;
-
- silc_pkcs_public_key_alloc(type, verify->userpk.data,
- verify->userpk.data_len,
- &verify->public_key);
- }
-
- if (usersign.data) {
+ if (usersign.data && !strcmp(verify->userpk.type, "silc-rsa")) {
/* Verify the signature now */
+ SilcPublicKey public_key;
+ SilcPKCS pkcs;
unsigned char *verifyd;
SilcUInt32 verify_len;
- if (verify->public_key) {
+ if (silc_pkcs_public_key_decode(verify->userpk.data,
+ verify->userpk.data_len,
+ &public_key)) {
+ silc_pkcs_alloc("rsa", &pkcs);
verifyd = silc_attribute_get_verify_data(attrs, FALSE, &verify_len);
- if (verifyd && silc_pkcs_verify(verify->public_key,
- usersign.data,
- usersign.data_len,
- verifyd, verify_len,
- sha1hash)) {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_VERIFIED);
- } else {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
+ if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)){
+ if (silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
+ usersign.data,
+ usersign.data_len,
+ verifyd, verify_len)) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_VERIFIED);
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
+ }
}
+ silc_pkcs_public_key_free(public_key);
silc_free(verifyd);
- } else {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
}
} else {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_NOT_PRESENT);
}
- if (serversign.data) {
+ if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) {
/* Verify the signature now */
SilcPublicKey public_key;
- SilcPKCSType type = 0;
+ SilcPKCS pkcs;
unsigned char *verifyd;
SilcUInt32 verify_len;
- if (!strcmp(verify->userpk.type, "silc-rsa"))
- type = SILC_PKCS_SILC;
- else if (!strcmp(verify->userpk.type, "ssh-rsa"))
- type = SILC_PKCS_SSH2;
- else if (!strcmp(verify->userpk.type, "x509v3-sign-rsa"))
- type = SILC_PKCS_X509V3;
- else if (!strcmp(verify->userpk.type, "pgp-sign-rsa"))
- type = SILC_PKCS_OPENPGP;
-
- if (silc_pkcs_public_key_alloc(type, serverpk.data,
- serverpk.data_len,
- &public_key)) {
+ if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len,
+ &public_key)) {
+ silc_pkcs_alloc("rsa", &pkcs);
verifyd = silc_attribute_get_verify_data(attrs, TRUE, &verify_len);
- if (verifyd && silc_pkcs_verify(public_key,
- serversign.data,
- serversign.data_len,
- verifyd, verify_len,
- sha1hash)) {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_VERIFIED);
- } else {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
+ if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) {
+ if (silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
+ serversign.data,
+ serversign.data_len,
+ verifyd, verify_len)) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_VERIFIED);
+ } else {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
+ }
}
silc_pkcs_public_key_free(public_key);
silc_free(verifyd);
- } else {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
}
}
- if (verify->public_key) {
- silc_verify_public_key(client, conn, SILC_CONN_CLIENT,
- verify->public_key,
+ if (verify->userpk.data) {
+ silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
+ verify->userpk.data, verify->userpk.data_len,
+ SILC_SKE_PK_TYPE_SILC,
silc_query_attributes_print_final, verify);
} else {
verify->nopk = TRUE;
static void silc_query_attributes_print_final(bool success, void *context)
{
AttrVerify verify = context;
+ SilcClient client = verify->client;
SILC_SERVER_REC *server = verify->server;
char *format = NULL;
unsigned char filename[256], *fingerprint = NULL, *tmp;
MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
/* Replace all whitespaces with `_'. */
- fingerprint = silc_hash_fingerprint(sha1hash,
+ fingerprint = silc_hash_fingerprint(client->sha1hash,
verify->userpk.data,
verify->userpk.data_len);
for (i = 0; i < strlen(fingerprint); i++)
static void silc_query_attributes_accept(const char *line, void *context)
{
AttrVerify verify = context;
+ SilcClient client = verify->client;
SILC_SERVER_REC *server = verify->server;
struct stat st;
struct passwd *pw;
goto out;
/* Replace all whitespaces with `_'. */
- fingerprint = silc_hash_fingerprint(sha1hash,
+ fingerprint = silc_hash_fingerprint(client->sha1hash,
verify->userpk.data,
verify->userpk.data_len);
for (i = 0; i < strlen(fingerprint); i++)
}
/* Save public key */
- if (verify->public_key) {
- memset(filename2, 0, sizeof(filename2));
- snprintf(filename2, sizeof(filename2) - 1, "%s/clientkey_%s.pub",
- filename, fingerprint);
- silc_pkcs_save_public_key(filename2, verify->public_key,
- SILC_PKCS_FILE_BASE64);
- }
+ memset(filename2, 0, sizeof(filename2));
+ snprintf(filename2, sizeof(filename2) - 1, "%s/clientkey_%s.pub",
+ filename, fingerprint);
+ silc_pkcs_save_public_key_data(filename2, verify->userpk.data,
+ verify->userpk.data_len,
+ SILC_PKCS_FILE_PEM);
/* Save extension data */
- if (verify->extension) {
+ if (verify->extension.mime) {
memset(filename2, 0, sizeof(filename2));
snprintf(filename2, sizeof(filename2) - 1, "%s/extension.mime",
filename);
- tmp = silc_mime_encode(verify->extension, &len);
- if (tmp)
- silc_file_writefile(filename2, tmp, len);
+ silc_file_writefile(filename2, verify->extension.mime,
+ verify->extension.mime_len);
}
/* Save MIME message data */
- if (verify->message) {
+ if (verify->message.mime) {
memset(filename2, 0, sizeof(filename2));
snprintf(filename2, sizeof(filename2) - 1, "%s/status_message.mime",
filename);
- tmp = silc_mime_encode(verify->message, &len);
- if (tmp)
- silc_file_writefile(filename2, tmp, len);
+ silc_file_writefile(filename2, verify->message.mime,
+ verify->message.mime_len);
}
printformat_module("fe-common/silc", server, NULL,
/*
silc-server.c : irssi
- Copyright (C) 2000 - 2007 Timo Sirainen
+ Copyright (C) 2000 - 2005 Timo Sirainen
Pekka Riikonen <priikone@silcnet.org>
This program is free software; you can redistribute it and/or modify
#include "settings.h"
#include "servers-setup.h"
+#include "channels-setup.h"
#include "client_ops.h"
#include "silc-servers.h"
cmd_return_error_value(CMDERR_NOT_JOINED, FALSE);
}
- return silc_client_send_channel_message(silc_client, server->conn,
- rec->entry, NULL, flags, sha1hash,
- msg, strlen(msg));
+ silc_client_send_channel_message(silc_client, server->conn, rec->entry,
+ NULL, flags, msg, strlen(msg), TRUE);
+ return TRUE;
}
typedef struct {
static void silc_send_msg_clients(SilcClient client,
SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
void *context)
{
PRIVMSG_REC *rec = context;
SILC_SERVER_REC *server = rec->server;
SilcClientEntry target;
- char nickname[128 + 1];
- SilcDList lclients = NULL;
+ char *nickname = NULL;
- if (!clients) {
+ if (!clients_count) {
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
"%s: There is no such client", rec->nick);
} else {
- if (silc_dlist_count(clients) > 1) {
- silc_parse_userfqdn(rec->nick, nickname, sizeof(nickname), NULL, 0);
+ if (clients_count > 1) {
+ silc_parse_userfqdn(rec->nick, &nickname, NULL);
/* Find the correct one. The rec->nick might be a formatted nick
so this will find the correct one. */
- clients = lclients =
- silc_client_get_clients_local(silc_client, server->conn,
- nickname, rec->nick);
+ clients = silc_client_get_clients_local(silc_client, server->conn,
+ nickname, rec->nick,
+ &clients_count);
if (!clients) {
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
"%s: There is no such client", rec->nick);
+ silc_free(nickname);
goto out;
}
+ silc_free(nickname);
}
- target = silc_dlist_get(clients);
+ target = clients[0];
/* Still check for exact math for nickname, this compares the
real (formatted) nickname and the nick (maybe formatted) that
- user gave. This is to assure that `nick' does not match
+ use gave. This is to assure that `nick' does not match
`nick@host'. */
- if (!silc_utf8_strcasecmp(rec->nick, target->nickname)) {
+ if (!silc_utf8_strcasecmp(rec->nick, clients[0]->nickname)) {
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
"%s: There is no such client", rec->nick);
goto out;
/* Send the private message */
silc_client_send_private_message(client, conn, target,
- rec->flags, sha1hash,
- rec->msg, rec->len);
+ rec->flags,
+ rec->msg, rec->len,
+ TRUE);
}
out:
- silc_client_list_free(silc_client, server->conn, lclients);
g_free(rec->nick);
g_free(rec->msg);
g_free(rec);
int msg_len, SilcMessageFlags flags)
{
PRIVMSG_REC *rec;
- char nickname[128 + 1];
- SilcDList clients;
- SilcClientEntry target;
- int ret;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
+ char *nickname = NULL;
- if (!silc_parse_userfqdn(nick, nickname, sizeof(nickname), NULL, 0)) {
+ if (!silc_parse_userfqdn(nick, &nickname, NULL)) {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_BAD_NICK, nick);
return FALSE;
/* Find client entry */
clients = silc_client_get_clients_local(silc_client, server->conn,
- nickname, nick);
+ nickname, nick, &clients_count);
if (!clients) {
rec = g_new0(PRIVMSG_REC, 1);
rec->nick = g_strdup(nick);
rec->len = msg_len;
/* Could not find client with that nick, resolve it from server. */
- silc_client_get_clients_whois(silc_client, server->conn,
- nickname, NULL, NULL,
- silc_send_msg_clients, rec);
+ silc_client_get_clients(silc_client, server->conn,
+ nickname, NULL, silc_send_msg_clients, rec);
+ silc_free(nickname);
return TRUE;
}
/* Send the private message directly */
- target = silc_dlist_get(clients);
- ret = silc_client_send_private_message(silc_client, server->conn,
- target, flags, sha1hash,
- msg, msg_len);
-
- silc_client_list_free(silc_client, server->conn, clients);
-
- return ret;
+ silc_free(nickname);
+ silc_client_send_private_message(silc_client, server->conn,
+ clients[0], flags,
+ msg, msg_len, TRUE);
+ return TRUE;
}
void silc_send_mime(SILC_SERVER_REC *server, int channel, const char *to,
silc_client_send_channel_message(silc_client, server->conn, rec->entry,
NULL, SILC_MESSAGE_FLAG_DATA |
(sign ? SILC_MESSAGE_FLAG_SIGNED : 0),
- sha1hash, unescaped_data,
- unescaped_data_len);
+ unescaped_data, unescaped_data_len, TRUE);
} else {
silc_send_msg(server, (char *)to, unescaped_data, unescaped_data_len,
SILC_MESSAGE_FLAG_DATA |
silc_free(unescaped_data);
}
-static int isnickflag_func(SERVER_REC *server, char flag)
+static int isnickflag_func(char flag)
{
return flag == '@' || flag == '+';
}
return FALSE;
}
-const char *get_nick_flags(SERVER_REC *server)
+const char *get_nick_flags(void)
{
return "@\0\0";
}
{
char *message = NULL, *t = NULL;
int len;
- SilcBool sign;
g_return_if_fail(server != NULL);
g_return_if_fail(target != NULL);
silc_utf8_encode(msg, strlen(msg), SILC_STRING_LOCALE, message, len);
}
- if (target_type == SEND_TARGET_CHANNEL) {
- sign = settings_get_bool("sign_channel_messages");
+ if (target_type == SEND_TARGET_CHANNEL)
silc_send_channel(server, target, message ? message : msg,
- SILC_MESSAGE_FLAG_UTF8 |
- (sign ? SILC_MESSAGE_FLAG_SIGNED : 0));
- } else {
- sign = settings_get_bool("sign_private_messages");
+ SILC_MESSAGE_FLAG_UTF8);
+ else {
if (!silc_term_utf8()) {
len = silc_utf8_encoded_len(target, strlen(target), SILC_STRING_LOCALE);
t = silc_calloc(len + 1, sizeof(*t));
silc_send_msg(server, t ? t : target, message ? message : msg,
message ? strlen(message) : strlen(msg),
- SILC_MESSAGE_FLAG_UTF8 |
- (sign ? SILC_MESSAGE_FLAG_SIGNED : 0));
+ SILC_MESSAGE_FLAG_UTF8);
}
silc_free(message);
silc_free(t);
}
-/* Connection callback */
-
-static void silc_connect_cb(SilcClient client,
- SilcClientConnection conn,
- SilcClientConnectionStatus status,
- SilcStatus error,
- const char *message,
- void *context)
+void silc_send_heartbeat(SilcSocketConnection sock,
+ void *hb_context)
{
- SILC_SERVER_REC *server = context;
- char *file;
-
- SILC_LOG_DEBUG(("Connection callback %p, status %d, error %d, message %s",
- conn, status, error, message ? message : "N/A"));
-
- server->op = NULL;
-
- switch (status) {
- case SILC_CLIENT_CONN_SUCCESS:
- if (server->disconnected) {
- silc_client_close_connection(client, conn);
- return;
- }
-
- /* We have successfully connected to server */
-
- /* Enable queueing until we have our requested nick */
- if (((opt_nickname &&
- strcmp(opt_nickname, conn->local_entry->nickname)) ||
- (settings_get_str("nick") &&
- strcmp(settings_get_str("nick"), conn->local_entry->nickname))) &&
- !strcmp(conn->local_entry->nickname, conn->local_entry->username))
- silc_queue_enable(conn);
-
- /* Put default attributes */
- silc_query_attributes_default(silc_client, conn);
-
- server->connected = TRUE;
- server->conn = conn;
- server->conn->context = server;
- signal_emit("event connected", 1, server);
- break;
-
- case SILC_CLIENT_CONN_SUCCESS_RESUME:
- if (server->disconnected) {
- silc_client_close_connection(client, conn);
- return;
- }
-
- /* We have successfully resumed old detached session */
- server->connected = TRUE;
- server->conn = conn;
- server->conn->context = server;
- signal_emit("event connected", 1, server);
-
- /* Put default attributes */
- silc_query_attributes_default(silc_client, conn);
+ SILC_SERVER_REC *server = SILC_SERVER(hb_context);
- /* Remove the detach data now */
- file = silc_get_session_filename(server);
- unlink(file);
- silc_free(file);
- break;
-
- case SILC_CLIENT_CONN_DISCONNECTED:
- /* Server disconnected */
- if (server->conn && server->conn->local_entry) {
- nicklist_rename_unique(SERVER(server),
- server->conn->local_entry, server->nick,
- server->conn->local_entry,
- silc_client->username);
- silc_change_nick(server, silc_client->username);
- }
-
- if (message)
- silc_say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Server closed connection: %s (%d) %s",
- silc_get_status_message(error), error,
- message ? message : "");
-
- if (server->conn)
- server->conn->context = NULL;
- server->conn = NULL;
- server->connection_lost = TRUE;
- if (!server->disconnected)
- server_disconnect(SERVER(server));
- server_unref(SERVER(server));
- break;
+ if (server == NULL)
+ return;
- default:
- file = silc_get_session_filename(server);
- if (silc_file_size(file) > 0)
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_CRAP, SILCTXT_REATTACH_FAILED, file);
- silc_free(file);
-
- server->connection_lost = TRUE;
- server->conn = NULL;
- if (server->conn)
- server->conn->context = NULL;
- if (!server->disconnected)
- server_disconnect(SERVER(server));
- server_unref(SERVER(server));
- break;
- }
+ silc_client_send_packet(silc_client, server->conn, SILC_PACKET_HEARTBEAT,
+ NULL, 0);
}
-/* Called after TCP stream has been created */
-
-static void sig_connected_stream_created(SilcSocketStreamStatus status,
- SilcStream stream, void *context)
+static void sig_connected(SILC_SERVER_REC *server)
{
- SILC_SERVER_REC *server = context;
+ SilcClientConnection conn;
SilcClientConnectionParams params;
char *file;
+ int fd;
- server->tcp_op = NULL;
- if (!stream) {
- server->connection_lost = TRUE;
- server_disconnect(SERVER(server));
+ if (!IS_SILC_SERVER(server))
return;
- }
-
- if (server->disconnected) {
- silc_stream_destroy(stream);
- return;
- }
-
- /* Set connection parameters */
- memset(¶ms, 0, sizeof(params));
- params.nickname = (opt_nickname ? (char *)opt_nickname :
- (char *)settings_get_str("nick"));
- params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
- params.rekey_secs = settings_get_int("key_exchange_rekey_secs");
- params.pfs = settings_get_bool("key_exchange_rekey_pfs");
/* Try to read detached session data and use it if found. */
+ memset(¶ms, 0, sizeof(params));
file = silc_get_session_filename(server);
params.detach_data = silc_file_readfile(file, ¶ms.detach_data_len);
if (params.detach_data)
params.detach_data[params.detach_data_len] = 0;
+
+ /* Add connection to the client library */
+ conn = silc_client_add_connection(silc_client, ¶ms,
+ server->connrec->address,
+ server->connrec->port,
+ server);
+ server->conn = conn;
+
if (params.detach_data)
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_REATTACH, server->tag);
- silc_free(file);
-
- /* Start key exchange */
- server->op = silc_client_key_exchange(silc_client, ¶ms,
- irssi_pubkey, irssi_privkey,
- stream, SILC_CONN_SERVER,
- silc_connect_cb, server);
- if (!server->op) {
- server->connection_lost = TRUE;
- server_disconnect(SERVER(server));
- silc_stream_destroy(stream);
- return;
- }
- server_ref(SERVER(server));
+ silc_free(params.detach_data);
+
+ fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
+
+ /* Start key exchange with the server */
+ silc_client_start_key_exchange(silc_client, conn, fd);
+
+ /* Put default attributes */
+ silc_query_attributes_default(silc_client, conn);
+
+ /* initialize heartbeat sending */
+ if (settings_get_int("heartbeat") > 0)
+ silc_socket_set_heartbeat(conn->sock, settings_get_int("heartbeat"),
+ (void *)server,
+ (SilcSocketConnectionHBCb)silc_send_heartbeat,
+ silc_client->schedule);
+
server->ftp_sessions = silc_dlist_init();
server->isnickflag = isnickflag_func;
server->ischannel = ischannel_func;
server->send_message = (void *) send_message;
}
-static void sig_connected(SILC_SERVER_REC *server)
-{
- int fd;
-
- if (!IS_SILC_SERVER(server))
- return;
-
- /* Wrap the socket to TCP stream */
- fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
- server->tcp_op =
- silc_socket_tcp_stream_create(fd, TRUE, FALSE,
- silc_client->schedule,
- sig_connected_stream_created, server);
-}
-
static void sig_disconnected(SILC_SERVER_REC *server)
{
if (!IS_SILC_SERVER(server))
silc_dlist_uninit(server->ftp_sessions);
- if (server->conn) {
- /* Close connection */
+ if (server->conn && server->conn->sock != NULL) {
silc_client_close_connection(silc_client, server->conn);
- } else if (server->op) {
- /* Abort on going connecting (key exchange) */
- silc_async_abort(server->op, NULL, NULL);
- server->op = NULL;
- } else if (server->tcp_op) {
- /* Abort on going TCP stream creation */
- silc_async_abort(server->tcp_op, NULL, NULL);
- server->tcp_op = NULL;
- }
- /* SILC closes the handle */
- g_io_channel_unref(net_sendbuffer_handle(server->handle));
- net_sendbuffer_destroy(server->handle, FALSE);
- server->handle = NULL;
+ /* SILC closes the handle */
+ g_io_channel_unref(net_sendbuffer_handle(server->handle));
+ net_sendbuffer_destroy(server->handle, FALSE);
+ server->handle = NULL;
+ }
}
SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
chans = g_string_new(NULL);
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *channel = tmp->data;
-
- g_string_sprintfa(chans, "%s,", channel->name);
+ CHANNEL_SETUP_REC *schannel;
+
+ if ((schannel = channel_setup_find(channel->name, server->connrec->chatnet)) &&
+ schannel->password)
+ g_string_sprintfa(chans, "%s %s,", channel->name,
+ schannel->password);
+ else
+ g_string_sprintfa(chans, "%s,", channel->name);
}
if (chans->len > 0)
/* SYNTAX: WHOIS [<nickname>[@<hostname>]] [-details] [-pubkey <pubkeyfile>] [<count>] */
/* SYNTAX: WHOWAS <nickname>[@<hostname>] [<count>] */
/* SYNTAX: CLOSE <server> [<port>] */
+/* SYNTAX: SHUTDOWN */
/* SYNTAX: MOTD [<server>] */
/* SYNTAX: LIST [<channel>] */
/* SYNTAX: ME <message> */
/* SYNTAX: NOTICE [-sign] [-channel] <target> <message> */
/* SYNTAX: PART [<channel>] */
/* SYNTAX: PING */
+/* SYNTAX: SCONNECT <server> [<port>] */
/* SYNTAX: USERS <channel> */
/* SYNTAX: FILE SEND <filepath> <nickname> [<local IP> [<local port>]] [-no-listener]*/
/* SYNTAX: FILE ACCEPT [<nickname>] */
signal_stop();
}
+/* SCONNECT command. Calls actually SILC's CONNECT command since Irssi
+ has CONNECT command for other purposes. */
+
+static void command_sconnect(const char *data, SILC_SERVER_REC *server)
+{
+ CMD_SILC_SERVER(server);
+ if (!IS_SILC_SERVER(server) || !server->connected) {
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Not connected to server");
+ return;
+ }
+
+ silc_command_exec(server, "CONNECT", data);
+ signal_stop();
+}
+
/* SMSG command, to send digitally signed messages */
static void command_smsg(const char *data, SILC_SERVER_REC *server,
if (ftp == SILC_LIST_END)
return;
- if (status == SILC_CLIENT_FILE_MONITOR_ERROR ||
- status == SILC_CLIENT_FILE_MONITOR_DISCONNECT) {
+ if (status == SILC_CLIENT_FILE_MONITOR_ERROR) {
if (error == SILC_CLIENT_FILE_NO_SUCH_FILE)
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_FILE_ERROR_NO_SUCH_FILE,
else
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_FILE_ERROR, client_entry->nickname);
- silc_schedule_task_add_timeout(silc_client->schedule,
- silc_client_file_close_later, ftp,
- 1, 0);
+ silc_schedule_task_add(silc_client->schedule, 0,
+ silc_client_file_close_later, ftp,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_dlist_del(server->ftp_sessions, ftp);
if (ftp == server->current_session) {
server->current_session = NULL;
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_FILE_TRANSMITTED, filepath, fsize,
client_entry->nickname, ftp->kps);
- silc_schedule_task_add_timeout(silc_client->schedule,
- silc_client_file_close_later, ftp,
- 1, 0);
+ silc_schedule_task_add(silc_client->schedule, 0,
+ silc_client_file_close_later, ftp,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_dlist_del(server->ftp_sessions, ftp);
if (ftp == server->current_session) {
server->current_session = NULL;
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_FILE_RECEIVED, filepath, fsize,
client_entry->nickname, ftp->kps);
- silc_schedule_task_add_timeout(silc_client->schedule,
- silc_client_file_close_later, ftp,
- 1, 0);
+ silc_schedule_task_add(silc_client->schedule, 0,
+ silc_client_file_close_later, ftp,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_dlist_del(server->ftp_sessions, ftp);
if (ftp == server->current_session) {
server->current_session = NULL;
static void silc_client_command_file_get_clients(SilcClient client,
SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
void *context)
{
FileGetClients internal = (FileGetClients)context;
WI_ITEM_REC *item)
{
SilcClientConnection conn;
- SilcClientEntry client_entry;
- SilcDList entries;
+ SilcClientEntry *entrys, client_entry;
SilcClientFileError ret;
- char nickname[128 + 1], *tmp;
+ SilcUInt32 entry_count;
+ char *nickname = NULL, *tmp;
unsigned char **argv;
SilcUInt32 argc;
SilcUInt32 *argv_lens, *argv_types;
SilcUInt32 local_port = 0;
SilcUInt32 session_id;
bool do_not_bind = FALSE;
- SilcClientConnectionParams params;
CMD_SILC_SERVER(server);
if (!server || !IS_SILC_SERVER(server) || !server->connected)
cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
/* Parse the typed nickname. */
- if (!silc_parse_userfqdn(argv[3], nickname, sizeof(nickname), NULL, 0)) {
+ if (!silc_parse_userfqdn(argv[3], &nickname, NULL)) {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[3]);
goto out;
}
/* Find client entry */
- entries = silc_client_get_clients_local(silc_client, conn, nickname,
- argv[3]);
- if (!entries) {
+ entrys = silc_client_get_clients_local(silc_client, conn, nickname,
+ argv[3], &entry_count);
+ if (!entrys) {
FileGetClients inter = silc_calloc(1, sizeof(*inter));
inter->server = server;
inter->data = strdup(data);
silc_client_command_file_get_clients, inter);
goto out;
}
- silc_dlist_start(entries);
- client_entry = silc_dlist_get(entries);
+ client_entry = entrys[0];
+ silc_free(entrys);
if (argc >= 5) {
if (!strcasecmp(argv[4], "-no-listener"))
do_not_bind = TRUE;
}
- memset(¶ms, 0, sizeof(params));
- if (!do_not_bind) {
- if (local_ip)
- params.local_ip = strdup(local_ip);
- params.local_port = local_port;
- if (!params.local_ip && settings_get_bool("use_auto_addr")) {
- params.local_ip = (char *)settings_get_str("auto_public_ip");
- if ((params.local_ip) && (*params.local_ip == '\0')) {
- params.local_ip = silc_net_localip();
- } else {
- params.bind_ip = (char *)settings_get_str("auto_bind_ip");
- if ((params.bind_ip) && (*params.bind_ip == '\0'))
- params.bind_ip = NULL;
- params.local_port = settings_get_int("auto_bind_port");
- }
- }
- if (!params.local_ip)
- params.local_ip = silc_net_localip();
- }
- params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
-
- ret = silc_client_file_send(silc_client, conn, client_entry, ¶ms,
- irssi_pubkey, irssi_privkey,
- silc_client_file_monitor, server, argv[2],
- &session_id);
+ ret =
+ silc_client_file_send(silc_client, conn, silc_client_file_monitor,
+ server, local_ip, local_port, do_not_bind,
+ client_entry, argv[2], &session_id);
if (ret == SILC_CLIENT_FILE_OK) {
ftp = silc_calloc(1, sizeof(*ftp));
ftp->session_id = session_id;
client_entry->nickname, argv[2]);
}
- silc_client_list_free(silc_client, server->conn, entries);
break;
case 2:
/* Parse the typed nickname. */
if (argc >= 3) {
- if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
+ if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
goto out;
}
/* Find client entry */
- entries = silc_client_get_clients_local(silc_client, conn, nickname,
- argv[2]);
- if (!entries) {
+ entrys = silc_client_get_clients_local(silc_client, conn, nickname,
+ argv[2], &entry_count);
+ if (!entrys) {
FileGetClients inter = silc_calloc(1, sizeof(*inter));
inter->server = server;
inter->data = strdup(data);
silc_client_command_file_get_clients, inter);
goto out;
}
- silc_dlist_start(entries);
- client_entry = silc_dlist_get(entries);
- silc_client_list_free(silc_client, server->conn, entries);
+ client_entry = entrys[0];
+ silc_free(entrys);
} else {
if (!server->current_session) {
printformat_module("fe-common/silc", server, NULL,
goto out;
}
- memset(¶ms, 0, sizeof(params));
- if (settings_get_bool("use_auto_addr")) {
- params.local_ip = (char *)settings_get_str("auto_public_ip");
- if ((params.local_ip) && (*params.local_ip == '\0')) {
- params.local_ip = silc_net_localip();
- } else {
- params.bind_ip = (char *)settings_get_str("auto_bind_ip");
- if ((params.bind_ip) && (*params.bind_ip == '\0'))
- params.bind_ip = NULL;
- params.local_port = settings_get_int("auto_bind_port");
- }
- }
- if (!params.local_ip)
- params.local_ip = silc_net_localip();
- params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
-
- ret = silc_client_file_receive(silc_client, conn, ¶ms,
- irssi_pubkey, irssi_privkey,
+ ret = silc_client_file_receive(silc_client, conn,
silc_client_file_monitor, server, NULL,
server->current_session->session_id,
NULL, NULL);
silc_dlist_start(server->ftp_sessions);
while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
if (ftp->client_entry == client_entry && !ftp->filepath) {
- memset(¶ms, 0, sizeof(params));
- if (settings_get_bool("use_auto_addr")) {
- params.local_ip = (char *)settings_get_str("auto_public_ip");
- if ((params.local_ip) && (*params.local_ip == '\0')) {
- params.local_ip = silc_net_localip();
- } else {
- params.bind_ip = (char *)settings_get_str("auto_bind_ip");
- if ((params.bind_ip) && (*params.bind_ip == '\0'))
- params.bind_ip = NULL;
- params.local_port = settings_get_int("auto_bind_port");
- }
- }
- if (!params.local_ip)
- params.local_ip = silc_net_localip();
- params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
-
- ret = silc_client_file_receive(silc_client, conn, ¶ms,
- irssi_pubkey, irssi_privkey,
+ ret = silc_client_file_receive(silc_client, conn,
silc_client_file_monitor, server,
NULL, ftp->session_id, NULL, NULL);
if (ret != SILC_CLIENT_FILE_OK) {
case 3:
/* Parse the typed nickname. */
if (argc >= 3) {
- if (!silc_parse_userfqdn(argv[2], nickname, sizeof(nickname), NULL, 0)) {
+ if (!silc_parse_userfqdn(argv[2], &nickname, NULL)) {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
goto out;
}
/* Find client entry */
- entries = silc_client_get_clients_local(silc_client, conn, nickname,
- argv[2]);
- if (!entries) {
+ entrys = silc_client_get_clients_local(silc_client, conn, nickname,
+ argv[2], &entry_count);
+ if (!entrys) {
FileGetClients inter = silc_calloc(1, sizeof(*inter));
inter->server = server;
inter->data = strdup(data);
silc_client_command_file_get_clients, inter);
goto out;
}
- silc_dlist_start(entries);
- client_entry = silc_dlist_get(entries);
- silc_client_list_free(silc_client, server->conn, entries);
+ client_entry = entrys[0];
+ silc_free(entrys);
} else {
if (!server->current_session) {
printformat_module("fe-common/silc", server, NULL,
}
out:
- return;
+ silc_free(nickname);
}
void silc_server_init(void)
command_bind_silc("ping", MODULE_NAME, (SIGNAL_FUNC) command_self);
command_bind_silc("motd", MODULE_NAME, (SIGNAL_FUNC) command_self);
command_bind_silc("close", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind_silc("shutdown", MODULE_NAME, (SIGNAL_FUNC) command_self);
command_bind_silc("getkey", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind_silc("sconnect", MODULE_NAME, (SIGNAL_FUNC) command_sconnect);
command_bind_silc("file", MODULE_NAME, (SIGNAL_FUNC) command_file);
command_bind_silc("detach", MODULE_NAME, (SIGNAL_FUNC) command_self);
command_bind_silc("watch", MODULE_NAME, (SIGNAL_FUNC) command_self);
command_unbind("motd", (SIGNAL_FUNC) command_self);
command_unbind("ban", (SIGNAL_FUNC) command_self);
command_unbind("close", (SIGNAL_FUNC) command_self);
+ command_unbind("shutdown", (SIGNAL_FUNC) command_self);
command_unbind("getkey", (SIGNAL_FUNC) command_self);
+ command_unbind("sconnect", (SIGNAL_FUNC) command_sconnect);
command_unbind("file", (SIGNAL_FUNC) command_file);
command_unbind("detach", (SIGNAL_FUNC) command_self);
command_unbind("watch", (SIGNAL_FUNC) command_self);
bool silc_term_utf8(void)
{
const char *str;
- str = settings_get_str("term_charset");
+ str = settings_get_str("term_type");
if (str)
if (g_strcasecmp(str, "utf-8") == 0)
return TRUE;
SilcDList ftp_sessions;
FtpSession current_session;
-
+
gpointer chanqueries;
SilcClientConnection conn;
- SilcAsyncOperation op; /* Key exchange operation handle */
- SilcAsyncOperation tcp_op; /* TCP stream creation operation handle */
SilcUInt32 umode;
} SILC_SERVER_REC;
SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn);
void silc_server_connect(SERVER_REC *server);
-/* Return a string of all channels in server in server->channels_join()
+/* Return a string of all channels in server in server->channels_join()
format */
char *silc_server_get_channels(SILC_SERVER_REC *server);
void silc_command_exec(SILC_SERVER_REC *server,
# GNU General Public License for more details.
#
-SILCD_SUBDIR=
-
#ifdef SILC_DIST_TOOLKIT
if test x$without_silcd = xfalse; then
#endif SILC_DIST_TOOLKIT
-SILCD_SUBDIR=silcd
-
# Logs directory
#
LOGSDIR="$silc_prefix/logs"
#ifdef SILC_DIST_TOOLKIT
fi # without_silcd = false
#endif SILC_DIST_TOOLKIT
-
-AC_SUBST(SILCD_SUBDIR)
#endif SILC_DIST_SERVER
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2003 Pekka Riikonen
+ Copyright (C) 1997 - 2006 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
*/
/* Send abort notification */
- silc_ske_abort(ctx->ske, ctx->ske->status);
+ if (ctx->ske)
+ silc_ske_abort(ctx->ske, ctx->ske->status);
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
* Error occured
*/
- if (ctx->pfs == TRUE)
+ if (ctx->pfs == TRUE && ctx->ske)
/* Send abort notification */
silc_ske_abort(ctx->ske, ctx->ske->status);
+++ /dev/null
-Authors of SILC Map.
-
-Pekka Riikonen <priikone@iki.fi>
+++ /dev/null
-Sat Apr 23 18:49:09 EEST 2005 Pekka Riikonen <priikone@silcnet.org>
-
- * First release, SILC Map 1.0
+++ /dev/null
-#
-# Makefile.am
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2003 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 = silcmap
-
-silcmap_SOURCES = \
- silcmap.c \
- silcmap_bitmap.c \
- silcmap_command.c \
- silcmap_client.c \
- silcmap_html.c
-
-LIBS = $(SILC_COMMON_LIBS) -lsilcclient -lsilc -lm
-LDADD =
-
-EXTRA_DIST = *.h silcmap.conf example.server.com_706.pub default.fnt
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-The SILC Map
-============
-
-SILC Map is a utility which can be used to visualize the topology of a
-SILC network. It can create maps which indicate the exact global position
-of the servers and it can create HTML pages out of the information it
-gathers from the servers. It is also possible to create a HTML map
-page which allows the user to click the servers on the map image to get
-more detailed information of the server. The links between the routers
-and servers can also be drawn on the map image.
-
-The HTML pages that SILC Map creates are by default crude looking. This
-is intentional feature to allow the user to easily embed the data pages
-into existing web site. This can be done for example by using PHP, server
-side includes or similar method.
-
-
-SILC Map Config File
-====================
-
-By default the SILC Map reads the silcmap.conf file. Please read the
-example silcmap.conf file to learn all the possible commands and
-configuration options you can use to alter the behavior of the SILC Map.
-
-
-Running the SILC Map
-====================
-
-After you have configured the silcmap.conf file, simply run the ./silcmap
-program. It reads the file, the source map image, creates the connections
-to SILC servers and producess the target image and HTML pages. After the
-map is created the silcmap program exits. If you want to periodically run
-the silcmap to generate maps you may create for example an at (see at(1))
-job on your local system.
-
-
-Getting Map Images
-==================
-
-We do not distribute any map images with the SILC Map package. However,
-you may download map images for free from NASA at:
-http://earthobservatory.nasa.gov/Newsroom/BlueMarble/.
-
-
-Contact
-=======
-
-Feedback and comments are welcome. Bug reports should be sent to the
-SILC development mailing list.
-
-Official SILC project web site : http://silcnet.org/
-FTP archive for SILC project : ftp://ftp.silcnet.org/
-Development mailing list address : silc-devel@lists.silcnet.org
-
+++ /dev/null
-#ifdef SILC_DIST_SILCMAP
-#
-# apps/silcmap/configure.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.
-#
-
-#
-# Makefile outputs
-#
-AC_CONFIG_FILES(
-apps/silcmap/Makefile
-)
-#endif SILC_DIST_SILCMAP
+++ /dev/null
-/*
-
- data.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 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 DATA_H
-#define DATA_H
-
-/* Bitmap context */
-typedef struct {
- char width;
- char height;
- unsigned char data[32 * 32];
-} MapBitmap;
-
-/* Circle */
-const MapBitmap silc_map_circle =
-{
- 6, 7,
- { 0, 1, 1, 1, 1, 0,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 0, 1, 1, 1, 1, 0
- }
-};
-
-/* Rectangle */
-const MapBitmap silc_map_rectangle =
-{
- 6, 7,
- { 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1
- }
-};
-
-#endif /* DATA_H */
+++ /dev/null
------BEGIN SILC PUBLIC KEY-----
-AAAA/QADcnNhAGZVTj1zaWxjLW9wZXIsIEhOPXNpbGMuc2lsY25ldC5vcmcsIFJOPVNJTEM
-gUm91dGVyIEFkbWluLCBFPXNpbGMtb3BlckBzaWxjbmV0Lm9yZywgTz1TSUxDIFByb2plY3
-QsIEM9U0sAAAAEAAAAfwAAAIAhKuTYfWdQ5UxB6ICuYCO13+gFIXZne3ciTm4c0AiHUoRat
-5Pd116FhO2ktkVZC8QS6IfRso5BkaYtRyp7qsficnXxZmFH5nBctXvlZ5zFWiDLsDz6TKI0
-5ib/T9EyRblNIpzQVrJsopvrz0mYmZKxUuu/e06EbdvpoubeHj6xLQ==
------END SILC PUBLIC KEY-----
+++ /dev/null
-/*
-
- silcmap.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 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 "silcincludes.h"
-#include "silcclient.h"
-#include "silcversion.h"
-#include "silcmap.h"
-
-/* Allocates new SilcMap context and the SilcClient in it. */
-
-SilcMap silc_map_alloc(const char *conffile)
-{
- SilcMap map = silc_calloc(1, sizeof(*map));
- if (!map)
- return NULL;
-
- /* Allocate client */
- map->client = silc_client_alloc(&silc_map_client_ops, NULL, NULL, NULL);
- if (!map->client) {
- silc_free(map);
- return NULL;
- }
-
- map->client->username = strdup("silcmap");
- map->client->hostname = silc_net_localhost();
- map->client->realname = strdup("silcmap");
-
- /* Init the client */
- if (!silc_client_init(map->client)) {
- silc_client_free(map->client);
- silc_free(map);
- return NULL;
- }
-
- /* Load new key pair if it exists, create if it doesn't. */
- if (!silc_load_key_pair("silcmap.pub", "silcmap.prv", "",
- &map->client->pkcs,
- &map->client->public_key,
- &map->client->private_key)) {
- /* The keys don't exist. Let's generate us a key pair then! There's
- nice ready routine for that too. Let's do 1024 bit RSA key pair. */
- if (!silc_create_key_pair("rsa", 1024, "silcmap.pub",
- "silcmap.prv", NULL, "",
- &map->client->pkcs,
- &map->client->public_key,
- &map->client->private_key, FALSE)) {
- fprintf(stderr, "Could not create new key pair");
- silc_client_free(map->client);
- silc_free(map);
- return NULL;
- }
- }
-
- map->conffile = strdup(conffile);
-
- return map;
-}
-
-/* Free the SilcMap context and all data in it. */
-
-void silc_map_free(SilcMap map)
-{
- SilcMapConnection mapconn;
- SilcMapCommand cmd;
- char *h;
- int i;
-
- silc_free(map->conffile);
- silc_free(map->bitmap);
-
- if (map->client) {
- silc_free(map->client->username);
- silc_free(map->client->realname);
- silc_free(map->client->hostname);
- silc_client_free(map->client);
- }
-
- if (map->conns) {
- silc_dlist_start(map->conns);
- while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
- silc_dlist_start(mapconn->hostnames);
- while ((h = silc_dlist_get(mapconn->hostnames)) != SILC_LIST_END)
- silc_free(h);
- silc_dlist_uninit(mapconn->hostnames);
-
- silc_dlist_start(mapconn->ips);
- while ((h = silc_dlist_get(mapconn->ips)) != SILC_LIST_END)
- silc_free(h);
- silc_dlist_uninit(mapconn->ips);
-
- silc_dlist_start(mapconn->commands);
- while ((cmd = silc_dlist_get(mapconn->commands)) != SILC_LIST_END) {
- silc_free(cmd->filename);
- silc_free(cmd->text);
- silc_free(cmd);
- }
- silc_dlist_uninit(mapconn->commands);
-
- silc_free(mapconn->public_key);
- silc_free(mapconn->country);
- silc_free(mapconn->city);
- silc_free(mapconn->admin);
- silc_free(mapconn->description);
- silc_free(mapconn->html_url);
- silc_free(mapconn->up_color);
- silc_free(mapconn->up_text_color);
- silc_free(mapconn->down_color);
- silc_free(mapconn->down_text_color);
- silc_free(mapconn->data.motd);
- memset(mapconn, 'F', sizeof(*mapconn));
- silc_free(mapconn);
- }
- silc_dlist_uninit(map->conns);
- }
-
- for (i = 0; i < map->writemaphtml_count; i++) {
- silc_free(map->writemaphtml[i].filename);
- silc_free(map->writemaphtml[i].text);
- }
- silc_free(map->writemaphtml);
-
- for (i = 0; i < map->cut_count; i++)
- silc_free(map->cut[i].filename);
- silc_free(map->cut);
-
- silc_free(map->writemap.filename);
- silc_free(map->writehtml.filename);
- silc_free(map->writehtml.text);
- silc_free(map->writerel.filename);
- silc_free(map->writerel.text);
-
- silc_free(map);
-}
-
-/* Starts the actual silcmap by parsing the commands script. */
-
-SILC_TASK_CALLBACK(silc_map_start)
-{
- SilcMap map = context;
-
- /* Load default font */
- silc_map_load_font(map, "default.fnt");
-
- /* Start command parsing. Most of the commands are executed when they
- are parsed so most of the real magic happens here. */
- if (!silc_map_commands_parse(map, map->conffile)) {
- /* Program stops */
- silc_schedule_stop(map->client->schedule);
- }
-}
-
-/* Long command line options */
-static struct option long_opts[] =
-{
- { "config-file", 1, NULL, 'f' },
- { "debug", 2, NULL, 'd' },
- { "help", 0, NULL, 'h' },
- { "version", 0, NULL,'V' },
-
- { NULL, 0, NULL, 0 }
-};
-
-static void silc_map_usage(void)
-{
- printf(""
-"Usage: silcmap [options]\n"
-"\n"
-" Generic Options:\n"
-" -f --config-file=FILE Alternate SILC Map configuration file\n"
-" -d --debug=string Enable debugging\n"
-" -h --help Display this message and exit\n"
-" -V --version Display version and exit\n"
-"\n");
- exit(0);
-}
-
-int main(int argc, char **argv)
-{
- SilcMap map;
- int opt, option_index;
- char *filename = NULL;
-
- if (argc > 1) {
- while ((opt = getopt_long(argc, argv, "f:d:hV",
- long_opts, &option_index)) != EOF) {
- switch(opt) {
- case 'h':
- silc_map_usage();
- break;
- case 'V':
- printf("SILC Map, version %s\n", silc_dist_version);
- printf("(c) 2003 Pekka Riikonen <priikone@silcnet.org>\n");
- exit(0);
- break;
- case 'd':
-#ifdef SILC_DEBUG
- silc_debug = TRUE;
- silc_debug_hexdump = TRUE;
- if (optarg)
- silc_log_set_debug_string(optarg);
- silc_log_quick = TRUE;
-#else
- fprintf(stderr,
- "Run-time debugging is not enabled. To enable it recompile\n"
- "the server with --enable-debug configuration option.\n");
-#endif
- break;
- case 'f':
- filename = strdup(optarg);
- break;
- default:
- silc_map_usage();
- break;
- }
- }
- }
-
- /* Allocate map context */
- if (!filename)
- filename = strdup("silcmap.conf");
- map = silc_map_alloc(filename);
- if (!map)
- return 1;
-
- /* Schedule for command script parsing */
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_start, map, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
- /* Run the silcmap client */
- silc_client_run(map->client);
-
- /* Cleanup */
- silc_client_stop(map->client);
- silc_map_free(map);
- silc_free(filename);
-
- return 0;
-}
+++ /dev/null
-#
-# Map drawing script file
-#
-# Command : server { ... }
-# Description : Specifies a server to connect, fetch statistics, draw the
-# server on map and to show its status on the map. See the
-# example server command below for all parameters of this
-# command.
-#
-# Command : loadmap { filename = <filename>; };
-# Example : loadmap { filename = "world_map.ppm"; };
-# Description : Load the source bitmap image file to be used as the map
-#
-# Command : writemap { filename = <filename>; };
-# Example : writemap { filename = "map.ppm"; };
-# Description : Write the target bitmap image file
-#
-# Command : writemaphtml { filename = <filename>; image = <filename>;
-# cut_lat = <lat>; cut_lon = <lon>; };
-# Example : writemaphtml { filename = "htmlmap.map"; image = "map.jpg"; };
-# Description : Write the gathered information as as HTML map page. This
-# allows the user to click the specified points of URLs.
-# The html_url parameter in server will specify the
-# URL that will be used in the HTML map. If omitted the
-# filename created by writehml command is used. The <cut_lat>
-# and <cut_lon> are specified if the <image> is a portion of
-# the original map image. In this case the lat and lon specify
-# which portion it is.
-#
-# Command : writehtml { filename = <filename>; class = <class>; };
-# Example : writehtml { filename = "index.html"; };
-# Description : Write the gathered information as HTML pages. Every server
-# command will have their own HTML file. The filename is
-# based on the hostname of the server. The index HTML file
-# will include list of the servers. The generated HTML files
-# are quite raw and are intended to be embedded into user's
-# own website. If <class> is defined it is used as the
-# CSS class in the created HTML page.
-#
-# Command : writerel { filename = <filename>; class = <class;> };
-# Example : writerel { filename = "reliability.html"; };
-# Description : Writes a reliability graph of the servers. When SILC Map
-# is run several times the uptime statistics of the servers
-# that measure the reliability of the servers are drawn into
-# the reliability graph. The uptime statistics will be
-# saved into corresponding server filename. If <class>
-# is defined it is used as the CSS class in the created HTML
-# file.
-#
-# Command : cut { lat = <lat>; lon = <lon>; width = <width>;
-# height = <height>; filename = <filename>; };
-# Example : cut { lat = "20"; lon = "5"; width = "1000"; height = "700";
-# filename = "map_chunk.ppm"; };
-# Description : Cuts a chunk from the source image at specified location.
-# The chunk will be <width> * <height> pixels in size. The
-# <filename> is the output bitmap file where the chunk is saved.
-#
-# Command : rectangle { lat = <lat>; lon = <lon>; color = <color>;
-# label = <label>; lposx = <x>; lposy = <y>;
-# lcolor = <label color>; };
-# Example : rectangle { lat = "-31 30"; lon = "0"; color = "0 0 255";
-# label = "text"; lposx = "-10", lposy = "15"; };
-# Description : Draws a rectangle at specified location. The center of the
-# rectangle will be at specified location. If the <label>
-# is specified, that text will appear with the rectangle at the
-# <lposx> and <lposy> pixel location in relation to the
-# rectangle. If <lcolor> is omitted the <color> is used.
-#
-# Command : circle { lat = <lat>; lon = <lon>; color = <color>;
-# label = <label>; lposx = <x>; lposy = <y>;
-# lcolor = <label color>; };
-# Example : circle { lat = "31 30"; lon = "0"; color = "255 255 255"; };
-# Description : Draws a circle at specified location. The center of the
-# circle will be at specified location. If the <label>
-# is specified, that text will appear with the circle at the
-# <lposx> and <lposy> pixel location in relation to the
-# circle. If <lcolor> is omitted the <color> is used.
-#
-# Command : line { a_lat = <lat>; a_lon = <lon>; b_lat = <lat>;
-# b_lon = <lon>; width = <width>; color = <color>; };
-# Description : Draws a straight line between points a and b. The <width>
-# is line width in pixels. If omitted, default is 1.
-#
-# Command : text { lat = <lat>; lon = <lon>; color = <color>;
-# text = <text>; };
-# Example : text { lat = "63 42 13", lon = "23 17 34", color = "0 0 255";
-# text = "This is an example text"; };
-# Description : Prints the text <text> at the specified location
-#
-# The <lat> is in format DD MM SS, where DD is degrees, MM minutes, and
-# SS seconds. If DD is positive the latitude is north bound, if negative
-# it is south bound. At least DD must be specified.
-#
-# The <lon> is in format DD MM SS, where DD is degrees, MM minutes, and
-# SS seconds. If DD is positive the longitude is east bound, if negative
-# it is west bound. At least DD must be specified.
-#
-# The <color> is in format RRR GGG BBB, where RRR is red, GGG green and
-# BBB blue, between 0 - 255.
-#
-
-loadmap { filename = "map.ppm"; };
-writemaphtml { filename = "map.html"; image = "map.jpg"; };
-
-server {
- # Server details
- hostname = "eample.server.com";
- ip = "10.2.1.1";
- port = "706";
- public_key = "example.server.com_706.pub";
- country = "Finland";
- city = "Kuopio";
- admin = "pekka";
- description = "";
-
- # Connection parameters
- connect = false;
- connect_timeout = "30";
-
- # URL used in writemaphtml and writehtml, instead of hostname
- #html_url = "";
-
- # Statistics to fetch
- starttime = true;
- uptime = true;
- clients = true;
- channels = true;
- server_ops = true;
- router_ops = true;
- cell_clients = true;
- cell_channels = true;
- cell_servers = true;
- all_clients = true;
- all_channels = true;
- all_servers = true;
- all_routers = true;
- all_server_ops = true;
- all_router_ops = true;
-
- # Fetch message of the day
- motd = true;
-
- # Status colors when server is either up or down
- up_color = "150 200 190";
- down_color = "150 0 0";
- up_text_color = "60 200 200";
- down_text_color = "150 0 0";
-
- # Draw this server on the map
- rectangle { lat = "36 00"; lon = "25 00";
- label = "example.server.com";
- lposx = "-30"; lposy = "10"; };
-};
-
-writemap { filename = "testi2.ppm"; };
+++ /dev/null
-/*
-
- silcmap.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2004 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 SILCMAP_H
-#define SILCMAP_H
-
-/* Font context */
-typedef struct {
- int height;
- struct {
- char width;
- unsigned char data[16 * 16];
- } font[94];
-} MapFonts;
-
-/* SilcMap command context. */
-typedef struct {
- /* Map command datas */
- char *filename;
- SilcInt32 x;
- SilcInt32 y;
- SilcInt32 x2;
- SilcInt32 y2;
- SilcUInt32 width;
- SilcUInt32 height;
- char *text;
- SilcInt32 lposx;
- SilcInt32 lposy;
- char *alat;
- char *alon;
- char *blat;
- char *blon;
-
- SilcInt16 r;
- SilcInt16 g;
- SilcInt16 b;
- SilcInt16 lr;
- SilcInt16 lg;
- SilcInt16 lb;
- unsigned int color_set : 1;
- unsigned int lcolor_set : 1;
-
- /* Command */
- unsigned int loadmap : 1;
- unsigned int writemap : 1;
- unsigned int writehtml : 1;
- unsigned int writemaphtml : 1;
- unsigned int writerel : 1;
- unsigned int cut : 1;
- unsigned int draw_line : 1;
- unsigned int draw_text : 1;
- unsigned int draw_circle : 1;
- unsigned int draw_rectangle : 1;
-} *SilcMapCommand, SilcMapCommandStruct;
-
-/* The SilcMap context. */
-typedef struct {
- /* Connection data */
- SilcClient client; /* SILC Client context */
- char *conffile; /* Config file name */
- SilcDList conns; /* Connections */
- SilcUInt32 conns_num; /* Number of created connections */
- SilcUInt32 conn_num; /* Current number of processed connections */
-
- /* Bitmap data */
- unsigned char *bitmap; /* Loaded bitmap image */
- SilcUInt32 bitmap_size; /* Size of bitmap */
- SilcUInt32 width; /* Bitmap width in pixels */
- SilcUInt32 height; /* Bitmap height in pixels */
- SilcUInt32 maxcolor; /* Max color value in bitmap */
- MapFonts font; /* Current font */
-
- /* Output methods */
- SilcMapCommandStruct loadmap;
- SilcMapCommandStruct writemap;
- SilcMapCommandStruct writehtml;
- SilcMapCommandStruct writerel;
- SilcMapCommandStruct *writemaphtml;
- SilcMapCommandStruct *cut;
- SilcUInt32 writemaphtml_count;
- SilcUInt32 cut_count;
-} *SilcMap;
-
-/* SilcMap connecetion context. */
-typedef struct {
- /* Server and connection details */
- SilcDList hostnames;
- SilcDList ips;
- int port;
- char *public_key;
- char *country;
- char *city;
- char *admin;
- char *description;
- int connect_timeout;
- char *html_url;
-
- /* Flags */
- unsigned int connect : 1;
- unsigned int starttime : 1;
- unsigned int uptime : 1;
- unsigned int clients : 1;
- unsigned int channels : 1;
- unsigned int server_ops : 1;
- unsigned int router_ops : 1;
- unsigned int cell_clients : 1;
- unsigned int cell_channels : 1;
- unsigned int cell_servers : 1;
- unsigned int all_clients : 1;
- unsigned int all_channels : 1;
- unsigned int all_servers : 1;
- unsigned int all_routers : 1;
- unsigned int all_server_ops : 1;
- unsigned int all_router_ops : 1;
- unsigned int motd : 1;
- unsigned int down : 1;
- unsigned int stats_received : 1;
- unsigned int motd_received : 1;
-
- /* Gathered data */
- struct {
- SilcUInt32 starttime;
- SilcUInt32 uptime;
- SilcUInt32 clients;
- SilcUInt32 channels;
- SilcUInt32 server_ops;
- SilcUInt32 router_ops;
- SilcUInt32 cell_clients;
- SilcUInt32 cell_channels;
- SilcUInt32 cell_servers;
- SilcUInt32 all_clients;
- SilcUInt32 all_channels;
- SilcUInt32 all_servers;
- SilcUInt32 all_routers;
- SilcUInt32 all_server_ops;
- SilcUInt32 all_router_ops;
- char *motd;
- } data;
-
- /* Status colors */
- char *up_color;
- char *down_color;
- char *up_text_color;
- char *down_text_color;
-
- /* Map commands */
- SilcDList commands;
-
- /* Back pointers */
- SilcMap map;
- SilcClientConnection conn;
-} *SilcMapConnection;
-
-extern SilcClientOperations silc_map_client_ops;
-
-SilcMap silc_map_alloc(const char *conffile);
-void silc_map_free(SilcMap map);
-bool silc_map_commands_parse(SilcMap map, const char *filename);
-void silc_map_connect(SilcMap map, SilcMapConnection mapconn);
-bool silc_map_load_ppm(SilcMap map, const char *filename);
-bool silc_map_write_ppm(SilcMap map, const char *filename);
-bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
- SilcUInt32 width, SilcUInt32 height,
- SilcMap *ret_map);
-bool silc_map_draw(SilcMap map,
- SilcInt32 x, SilcInt32 y,
- const unsigned char *bitmap,
- SilcUInt32 width, SilcUInt32 height);
-bool silc_map_draw_raw(SilcMap map,
- SilcInt32 x, SilcInt32 y,
- const unsigned char *bitmap,
- SilcUInt32 width, SilcUInt32 height,
- SilcInt16 r, SilcInt16 g, SilcInt16 b);
-bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
- SilcInt32 a_x, SilcInt32 a_y,
- SilcInt32 b_x, SilcInt32 b_y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b);
-bool silc_map_draw_text(SilcMap map, const char *text,
- SilcInt32 x, SilcInt32 y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b);
-bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b,
- const char *label, SilcInt32 lposx, SilcInt32 lposy,
- SilcInt16 lr, SilcInt16 lg, SilcInt16 lb);
-bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b,
- const char *label, SilcInt32 lposx,
- SilcInt32 lposy,
- SilcInt16 lr, SilcInt16 lg, SilcInt16 lb);
-double silc_map_parse_pos(char *pos);
-int silc_map_lon2x(SilcMap map, char *latitude);
-int silc_map_lat2y(SilcMap map, char *longitude);
-bool silc_map_parse_color(const char *color,
- SilcInt16 *r, SilcInt16 *g, SilcInt16 *b);
-bool silc_map_load_font(SilcMap map, const char *filename);
-bool silc_map_writehtml(SilcMap map, SilcMapConnection mapconn);
-bool silc_map_writehtml_index(SilcMap map);
-bool silc_map_writemaphtml(SilcMap map);
-bool silc_map_writerel(SilcMap map, SilcMapConnection mapconn);
-bool silc_map_writerelhtml(SilcMap map);
-
-#endif /* SILCMAP_H */
+++ /dev/null
-/*
-
- silcmap_bitmap.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2004 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 "silcincludes.h"
-#include "silcclient.h"
-#include <math.h>
-#include "silcmap.h"
-#include "data.h"
-
-/******* Bitmap Routines *****************************************************/
-
-/* Load a bitmap file. The file is the map image that is loaded into
- the SilcMap context. This is no perfect PPM loader. */
-
-bool silc_map_load_ppm(SilcMap map, const char *filename)
-{
- int fd;
- char type[3];
- unsigned char header[80];
- int ret, retval = TRUE, i;
-
- SILC_LOG_DEBUG(("Load PPM '%s'", filename));
-
- fd = open(filename, O_RDONLY, 0600);
- if (fd < 0) {
- fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
- return FALSE;
- }
-
- /* Read file header */
- memset(header, 0, sizeof(header));
- ret = read(fd, (void *)header, sizeof(header) - 1);
- if (ret < 0) {
- fprintf(stderr, "read: %s: %s\n", strerror(errno), filename);
- return FALSE;
- }
-
- /* Read width and height */
- ret = sscanf(header, "%s %ld %ld %ld\n", type,
- (unsigned long *)&map->width,
- (unsigned long *)&map->height,
- (unsigned long *)&map->maxcolor);
- if (ret < 4) {
- fprintf(stderr, "Invalid PPM file");
- retval = FALSE;
- goto out;
- }
-
- for (i = sizeof(header) - 1; i >= 0; i--)
- if (header[i] == '\n' || header[i] == ' ')
- break;
- lseek(fd, i + 1, SEEK_SET);
-
- /* Read the picture */
- map->bitmap_size = map->width * 3 * map->height;
- map->bitmap = silc_malloc(map->bitmap_size);
- ret = read(fd, map->bitmap, map->bitmap_size);
- if (ret < 0) {
- fprintf(stderr, "read: %s\n", strerror(errno));
- retval = FALSE;
- goto out;
- }
-
- out:
- close(fd);
- return retval;
-}
-
-/* Write the map into a bitmap file. */
-
-bool silc_map_write_ppm(SilcMap map, const char *filename)
-{
- int fd;
- int retval = TRUE;
- char header[80];
-
- SILC_LOG_DEBUG(("Write PPM '%s'", filename));
-
- fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
- if (fd < 0) {
- fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
- return FALSE;
- }
-
- /* Write the header */
- memset(header, 0, sizeof(header));
- snprintf(header, sizeof(header) - 1, "P6 %ld %ld %ld\n",
- (unsigned long)map->width,
- (unsigned long)map->height,
- (unsigned long)map->maxcolor);
- write(fd, header, strlen(header));
-
- /* Write the bitmap */
- write(fd, map->bitmap, map->bitmap_size);
- close(fd);
-
- return retval;
-}
-
-/* Cut the map into a `width' * `height' size chunk at `x' and `y'. This
- returns the allocated map bitmap into `ret_bitmap'. The original map
- is not modified. */
-
-bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
- SilcUInt32 width, SilcUInt32 height,
- SilcMap *ret_map)
-{
- int i;
-
- SILC_LOG_DEBUG(("cut"));
-
- /* Sanity checks */
- if (height > map->height - y) {
- fprintf(stderr, "Requesting too much height: %ld\n",
- (unsigned long)height);
- return FALSE;
- }
- if (width > map->width - x) {
- fprintf(stderr, "Requesting too much width: %ld\n",
- (unsigned long)width);
- return FALSE;
- }
-
- /* Compute coordinates in the bitmap */
- y = (map->width * 3) * y;
- x = (x * 3);
-
- /* Allocate new SilcMap context */
- *ret_map = silc_calloc(1, sizeof(**ret_map));
- (*ret_map)->width = width;
- (*ret_map)->height = height;
- (*ret_map)->maxcolor = map->maxcolor;
- (*ret_map)->bitmap_size = (width * 3) * height;
- (*ret_map)->bitmap = silc_malloc((*ret_map)->bitmap_size);
-
- /* Copy the requested area */
- for (i = 0; i < height; i++) {
- memcpy((*ret_map)->bitmap + (i * width * 3),
- map->bitmap + y + x, width * 3);
-
- /* Next line */
- y += (map->width * 3);
- }
-
- return TRUE;
-}
-
-/* Draw a bitmap indicated by `bitmap' of size of `width' * 'height'
- into the SilcMap context into the coordinates `x' and `y' (the upper left
- corner of the bitmap will be at x and y). The `bitmap' must be RGB
- color bitmap. */
-
-bool silc_map_draw(SilcMap map,
- SilcInt32 x, SilcInt32 y,
- const unsigned char *bitmap,
- SilcUInt32 width, SilcUInt32 height)
-{
- int i, k;
- unsigned char val;
-
- /* Compute coordinates in the bitmap */
- y = (map->width * 3) * y;
- x = (x * 3);
-
- /* Draw the bitmap into the map bitmap */
- for (i = 0; i < height; i++) {
- for (k = 0; k < width; k++) {
- val = bitmap[i * (width * 3) + (k * 3)];
- map->bitmap[y + x + (k * 3) ] = val; /* R */
-
- val = bitmap[i * (width * 3) + (k * 3) + 1];
- map->bitmap[y + x + (k * 3) + 1] = val; /* G */
-
- val = bitmap[i * (width * 3) + (k * 3) + 2];
- map->bitmap[y + x + (k * 3) + 2] = val; /* B */
- }
-
- /* Next line */
- y += (map->width * 3);
- }
-
- return TRUE;
-}
-
-/* Same as silc_map_draw but the `bitmap' is a grayscale bitmap
- and the RGB color information is provided as argument to this function. */
-
-bool silc_map_draw_raw(SilcMap map,
- SilcInt32 x, SilcInt32 y,
- const unsigned char *bitmap,
- SilcUInt32 width, SilcUInt32 height,
- SilcInt16 r, SilcInt16 g, SilcInt16 b)
-{
- int i, k;
- unsigned char val;
-
- /* Compute coordinates in the bitmap */
- y = (map->width * 3) * y;
- x = (x * 3);
-
- /* Draw the bitmap into the map bitmap */
- for (i = 0; i < height; i++) {
- for (k = 0; k < width; k++) {
- val = bitmap[i * width + k];
- if (val != 0) {
- map->bitmap[y + x + (k * 3) ] = r; /* R */
- map->bitmap[y + x + (k * 3) + 1] = g; /* G */
- map->bitmap[y + x + (k * 3) + 2] = b; /* B */
- }
- }
-
- /* Next line */
- y += (map->width * 3);
- }
-
- return TRUE;
-}
-
-/* Draw a straight line between points a and b. The coordinates for the
- points are provided as arguments. The `width' is the line width in
- pixels. The RGB color for the line can be provided too. Implements
- DDA algorithm. */
-
-bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
- SilcInt32 a_x, SilcInt32 a_y,
- SilcInt32 b_x, SilcInt32 b_y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b)
-{
- unsigned char p[3] = { r, g, b };
- int xdiff, ydiff, i;
- double x, y, slox, sloy;
-
- SILC_LOG_DEBUG(("draw_line"));
-
- /* Compute the difference of points */
- xdiff = b_x - a_x;
- ydiff = b_y - a_y;
- if (!xdiff && !ydiff)
- return FALSE;
-
- /* Draw the line */
- if (abs(xdiff) > abs(ydiff)) {
- sloy = (double)ydiff / (double)xdiff;
- y = a_y + 0.5; /* rounding */
- if (xdiff > 0) {
- for (x = a_x; x <= b_x; x++) {
- for (i = 0; i < width; i++)
- silc_map_draw(map, x + i, floor(y), p, 1, 1);
- y += sloy;
- }
- } else {
- for (x = a_x; x >= b_x; x--) {
- for (i = 0; i < width; i++)
- silc_map_draw(map, x + i, floor(y), p, 1, 1);
- y -= sloy;
- }
- }
- } else {
- slox = (double)xdiff / (double)ydiff;
- x = a_x + 0.5; /* rounding */
- if (ydiff > 0) {
- for (y = a_y; y <= b_y; y++) {
- for (i = 0; i < width; i++)
- silc_map_draw(map, floor(x + i), y, p, 1, 1);
- x += slox;
- }
- } else {
- for (y = a_y; y >= b_y; y--) {
- for (i = 0; i < width; i++)
- silc_map_draw(map, floor(x + i), y, p, 1, 1);
- x -= slox;
- }
- }
- }
-
- return TRUE;
-}
-
-/* Print the text string `text' on the bitmap at `x' and `y'. The color
- for the text can be provided as argument. */
-
-bool silc_map_draw_text(SilcMap map, const char *text,
- SilcInt32 x, SilcInt32 y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b)
-{
- int k, w;
- int c;
-
- SILC_LOG_DEBUG(("draw_text"));
-
- /* Write the text. */
- w = 0;
- for (k = 0; k < strlen(text); k++) {
- c = text[k] - 33;
- silc_map_draw_raw(map, x + w, y,
- map->font.font[c].data,
- map->font.font[c].width,
- map->font.height, r, g, b);
- w += map->font.font[c].width;
- }
-
- return TRUE;
-}
-
-/* Draw circle on the bitmap map at `x' and `y'. The center of the
- circle will be at the `x' and `y'. If the `label' is provided the
- text will appear with the circle at `lposx' and `lposy' in relation
- with the circle. */
-
-bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b,
- const char *label, SilcInt32 lposx, SilcInt32 lposy,
- SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
-{
- bool ret;
-
- SILC_LOG_DEBUG(("draw_circle"));
-
- y = y - (silc_map_circle.height / 2);
- x = x - (silc_map_circle.width / 2);
-
- ret = silc_map_draw_raw(map, x, y,
- silc_map_circle.data,
- silc_map_circle.width, silc_map_circle.height,
- r, g, b);
- if (!ret)
- return FALSE;
-
- if (label)
- ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
-
- return ret;
-}
-
-/* Draw rectangle on the bitmap map at `x' and `y'. The center of the
- rectangle will be at the `x' and `y'. If the `label' is provided the
- text will appear with the circle at `lposx' and `lposy' in relation
- with the circle. */
-
-bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
- SilcInt16 r, SilcInt16 g, SilcInt16 b,
- const char *label,
- SilcInt32 lposx, SilcInt32 lposy,
- SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
-{
- bool ret;
-
- SILC_LOG_DEBUG(("draw_rectangle"));
-
- y = y - (silc_map_rectangle.height / 2);
- x = x - (silc_map_rectangle.width / 2);
-
- ret = silc_map_draw_raw(map, x, y,
- silc_map_rectangle.data, silc_map_rectangle.width,
- silc_map_rectangle.height,
- r, g, b);
- if (!ret)
- return FALSE;
-
- if (label)
- ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
-
- return ret;
-}
-
-/* Parses the degree position string. For example, longitude 40 23 10,
- as in 40 degrees, 23 minutes and 10 seconds east. Negative degree is to
- West. For latitude positive is north and negative south. */
-
-double silc_map_parse_pos(char *pos)
-{
- double d = 0, m = 0, s = 0;
- int ret;
-
- ret = sscanf(pos, "%lf %lf %lf", &d, &m, &s);
- if (ret < 1) {
- fprintf(stderr, "Malfromed position string '%s'\n", pos);
- return 0;
- }
-
- if (d < 0) {
- m = (m < 0 ? m : -m);
- s = (s < 0 ? s : -s);
- }
-
- return ((d < 0 ? -1 : d > 0 ? 1 : 0) *
- abs(d) + (m / 60) + (s / 3600));
-}
-
-/* Converts longitude into position in the bitmap */
-
-int silc_map_lon2x(SilcMap map, char *longitude)
-{
- double meridian, aspmul, lon;
-
- /* Parse position string */
- lon = silc_map_parse_pos(longitude);
-
- /* Compute "aspect ratio multiplier" to get the position in the map. */
- meridian = (double)map->width / (double)2.0;
- aspmul = meridian / 180.0;
-
- /* Compute the position in the bitmap map */
- return (int)(double)(meridian + (lon * aspmul));
-}
-
-/* Converts latitude into position in the bitmap */
-
-int silc_map_lat2y(SilcMap map, char *latitude)
-{
- double meridian, aspmul, lat;
-
- /* Parse position string */
- lat = silc_map_parse_pos(latitude);
-
- /* Compute "aspect ratio multiplier" to get the position in the map. */
- meridian = (double)map->height / (double)2.0;
- aspmul = meridian / 90.0;
-
- /* Compute the position in the bitmap map */
- return (int)(double)(meridian - (lat * aspmul));
-}
-
-/* Parses RGB color string. */
-
-bool silc_map_parse_color(const char *color,
- SilcInt16 *r, SilcInt16 *g, SilcInt16 *b)
-{
- int ret;
- int rr, gg, bb;
-
- ret = sscanf(color, "%d %d %d", &rr, &gg, &bb);
- if (ret < 3) {
- fprintf(stderr, "Invalid color string: %s\n", color);
- return FALSE;
- }
-
- *r = (SilcInt16)rr;
- *g = (SilcInt16)gg;
- *b = (SilcInt16)bb;
-
- return TRUE;
-}
-
-/* Loads a font file. The font file format is the following:
-
- height\n
- width
- font data
- width
- font data
- etc.
-
- If this function is called multiple times the new font replaces the
- old font. */
-
-bool silc_map_load_font(SilcMap map, const char *filename)
-{
- FILE *fp;
- int i, x, y;
-
- /* Load the file */
- fp = fopen(filename, "r");
- if (!fp) {
- fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
- return FALSE;
- }
-
- /* Read the font height */
- i = fscanf(fp, "%d\n", &map->font.height);
- if (i < 1)
- return FALSE;
-
- /* Read the font data */
- for (i = 0; i < 94; i++) {
- map->font.font[i].width = fgetc(fp);
-
- for (y = 0; y < map->font.height; y++)
- for (x = 0; x < map->font.font[i].width; x++)
- map->font.font[i].data[(y * map->font.font[i].width) + x] = fgetc(fp);
- }
-
- return TRUE;
-}
+++ /dev/null
-/*
-
- silcmap_client.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2004 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 "silcincludes.h"
-#include "silcclient.h"
-#include "silcmap.h"
-
-/******* Map Client Routines *************************************************/
-
-SILC_TASK_CALLBACK(silc_map_process_done)
-{
- SilcMap map = context;
-
- /* Program stops */
- silc_schedule_stop(map->client->schedule);
-}
-
-/* This function processes the data that was gathered from the server
- and producess the outputs and the map. */
-
-void silc_map_process_data(SilcMap map, SilcMapConnection mapconn)
-{
- SilcMapCommand cmd;
- SilcMap ret_map;
- SilcInt16 r, g, b, lr, lg, lb;
- int i;
-
- map->conn_num++;
-
- SILC_LOG_DEBUG(("Processing the data from server (%d/%d)",
- map->conn_num, map->conns_num));
-
- if (map->conn_num != map->conns_num)
- return;
-
- /* Load the map image to be processed */
- silc_free(map->bitmap);
- if (!map->loadmap.loadmap || !map->loadmap.filename) {
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_process_done, map, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- return;
- }
-
- if (!silc_map_load_ppm(map, map->loadmap.filename)) {
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_process_done, map, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- return;
- }
-
- /* Now process all received data one by one */
- silc_dlist_start(map->conns);
- while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
-
- /* Change colors according to server status */
- silc_map_parse_color(mapconn->up_color, &r, &g, &b);
- silc_map_parse_color(mapconn->up_text_color, &lr, &lg, &lb);
- if (mapconn->down) {
- silc_map_parse_color(mapconn->down_color, &r, &g, &b);
- silc_map_parse_color(mapconn->down_text_color, &lr, &lg, &lb);
- }
-
- /* Execute the map commands */
- silc_dlist_start(mapconn->commands);
- while ((cmd = silc_dlist_get(mapconn->commands)) != SILC_LIST_END) {
- if (cmd->alon && cmd->alat) {
- cmd->x = silc_map_lon2x(map, cmd->alon);
- cmd->y = silc_map_lat2y(map, cmd->alat);
- if (cmd->blon && cmd->blat) {
- cmd->x2 = silc_map_lon2x(map, cmd->blon);
- cmd->y2 = silc_map_lat2y(map, cmd->blat);
- }
- }
-
- if (cmd->cut) {
- if (silc_map_cut(map, cmd->x, cmd->y, cmd->width,
- cmd->height, &ret_map)) {
- silc_map_write_ppm(ret_map, cmd->filename);
- silc_map_free(ret_map);
- }
- continue;
- }
-
- if (cmd->draw_line) {
- if (cmd->color_set) {
- r = cmd->r;
- g = cmd->g;
- b = cmd->b;
- }
- silc_map_draw_line(map, cmd->width, cmd->x, cmd->y, cmd->x2, cmd->y2,
- r, g, b);
- continue;
- }
-
- if (cmd->draw_text) {
- if (cmd->color_set) {
- lr = cmd->r;
- lg = cmd->g;
- lb = cmd->b;
- }
- silc_map_draw_text(map, cmd->text, cmd->x, cmd->y, lr, lg, lb);
- continue;
- }
-
- if (cmd->draw_circle) {
- if (cmd->color_set) {
- r = cmd->r;
- g = cmd->g;
- b = cmd->b;
- }
- if (cmd->lcolor_set) {
- lr = cmd->lr;
- lg = cmd->lg;
- lb = cmd->lb;
- }
- silc_map_draw_circle(map, cmd->x, cmd->y, r, g, b,
- cmd->text, cmd->lposx, cmd->lposy, lr, lg, lb);
- continue;
- }
-
- if (cmd->draw_rectangle) {
- if (cmd->color_set) {
- r = cmd->r;
- g = cmd->g;
- b = cmd->b;
- }
- if (cmd->lcolor_set) {
- lr = cmd->lr;
- lg = cmd->lg;
- lb = cmd->lb;
- }
- silc_map_draw_rectangle(map, cmd->x, cmd->y, r, g, b,
- cmd->text, cmd->lposx, cmd->lposy, lr, lg, lb);
- continue;
- }
- }
-
- /* Write the html data file */
- if (map->writehtml.writehtml)
- silc_map_writehtml(map, mapconn);
-
- /* Write uptime reliability data */
- if (map->writerel.writerel)
- silc_map_writerel(map, mapconn);
- }
-
- SILC_LOG_DEBUG(("All connections processed"));
-
- /* Produce output */
- if (map->writemap.writemap)
- silc_map_write_ppm(map, map->writemap.filename);
- for (i = 0; i < map->cut_count; i++) {
- if (map->cut[i].alon && map->cut[i].alat) {
- map->cut[i].x = silc_map_lon2x(map, map->cut[i].alon);
- map->cut[i].y = silc_map_lat2y(map, map->cut[i].alat);
- }
- if (silc_map_cut(map, map->cut[i].x, map->cut[i].y, map->cut[i].width,
- map->cut[i].height, &ret_map)) {
- silc_map_write_ppm(ret_map, map->cut[i].filename);
- silc_map_free(ret_map);
- }
- }
-
- /* Write the HTML index file */
- if (map->writehtml.writehtml)
- silc_map_writehtml_index(map);
-
- /* Write the HTML map file(s) */
- silc_map_writemaphtml(map);
-
- /* Write uptime reliability graph */
- if (map->writerel.writerel)
- silc_map_writerelhtml(map);
-
- /* Schedule to stop */
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_process_done, map, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-
-/* Timeout callback to detect if server is down. */
-
-SILC_TASK_CALLBACK(silc_map_connect_timeout)
-{
- SilcMapConnection mapconn = context;
-
- SILC_LOG_DEBUG(("Connection timeout"));
-
- silc_schedule_task_del_by_context(mapconn->map->client->schedule, mapconn);
-
- /* The server is down. */
- mapconn->down = TRUE;
-
- /* Continue to produce the data and the map. */
- silc_map_process_data(mapconn->map, mapconn);
-}
-
-/* Timeout callback to detect if server is down. */
-
-SILC_TASK_CALLBACK(silc_map_data_timeout)
-{
- SilcMapConnection mapconn = context;
-
- SILC_LOG_DEBUG(("data timeout"));
-
- silc_schedule_task_del_by_context(mapconn->map->client->schedule, mapconn);
-
- /* The server is down. */
- mapconn->down = TRUE;
-
- /* Close connection, we didn't get any data. */
- SILC_LOG_DEBUG(("Closing connection to %s:%d", mapconn->conn->remote_host,
- mapconn->conn->remote_port));
- silc_client_close_connection(mapconn->conn->client, mapconn->conn);
-
- /* Continue to produce the data and the map. */
- silc_map_process_data(mapconn->map, mapconn);
-}
-
-/* Close connection to server */
-
-SILC_TASK_CALLBACK(silc_map_connect_close)
-{
- SilcMapConnection mapconn = context;
-
- SILC_LOG_DEBUG(("Closing connection to %s:%d", mapconn->conn->remote_host,
- mapconn->conn->remote_port));
-
- silc_client_close_connection(mapconn->conn->client, mapconn->conn);
-
- /* Continue to produce the data and the map. */
- silc_map_process_data(mapconn->map, mapconn);
-}
-
-/* Create connection to remote server to gather information about it. */
-
-void silc_map_connect(SilcMap map, SilcMapConnection mapconn)
-{
- char *ip;
-
- if (!mapconn->connect) {
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_connect_timeout, mapconn, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- return;
- }
-
- /* First configure IP is used to connect. */
- silc_dlist_start(mapconn->ips);
- ip = silc_dlist_get(mapconn->ips);
-
- SILC_LOG_DEBUG(("Creating connection to server %s:%d", ip, mapconn->port));
-
- /* Create connection. We'll continue in the silc_connected after
- connection is created. */
- silc_client_connect_to_server(map->client, NULL,
- mapconn->port, ip, mapconn);
-
- /* Set connect timeout to detect if the server is down. */
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_connect_timeout, mapconn,
- mapconn->connect_timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-
-
-/******* SILC Client Operations **********************************************/
-
-/* "say" client operation is a message from the client library to the
- application. It may include error messages or something else. We
- just dump them to screen. */
-
-static void
-silc_say(SilcClient client, SilcClientConnection conn,
- SilcClientMessageType type, char *msg, ...)
-{
-
-}
-
-
-/* Message for a channel. The `sender' is the sender of the message
- The `channel' is the channel. The `message' is the message. Note
- that `message' maybe NULL. The `flags' indicates message flags
- and it is used to determine how the message can be interpreted
- (like it may tell the message is multimedia message). */
-
-static void
-silc_channel_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessagePayload payload,
- SilcChannelPrivateKey key, SilcMessageFlags flags,
- const unsigned char *message,
- SilcUInt32 message_len)
-{
-
-}
-
-
-/* Private message to the client. The `sender' is the sender of the
- message. The message is `message'and maybe NULL. The `flags'
- indicates message flags and it is used to determine how the message
- can be interpreted (like it may tell the message is multimedia
- message). */
-
-static void
-silc_private_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcMessagePayload payload,
- SilcMessageFlags flags,
- const unsigned char *message,
- SilcUInt32 message_len)
-{
-
-}
-
-
-/* Notify message to the client. The notify arguments are sent in the
- same order as servers sends them. The arguments are same as received
- from the server except for ID's. If ID is received application receives
- the corresponding entry to the ID. For example, if Client ID is received
- application receives SilcClientEntry. Also, if the notify type is
- for channel the channel entry is sent to application (even if server
- does not send it because client library gets the channel entry from
- the Channel ID in the packet's header). */
-
-static void
-silc_notify(SilcClient client, SilcClientConnection conn,
- SilcNotifyType type, ...)
-{
-
-}
-
-
-/* Command handler. This function is called always in the command function.
- If error occurs it will be called as well. `conn' is the associated
- client connection. `cmd_context' is the command context that was
- originally sent to the command. `success' is FALSE if error occurred
- during command. `command' is the command being processed. It must be
- noted that this is not reply from server. This is merely called just
- after application has called the command. Just to tell application
- that the command really was processed. */
-
-static void
-silc_command(SilcClient client, SilcClientConnection conn,
- SilcClientCommandContext cmd_context, bool success,
- SilcCommand command, SilcStatus status)
-{
-
-}
-
-
-/* Command reply handler. This function is called always in the command reply
- function. If error occurs it will be called as well. Normal scenario
- is that it will be called after the received command data has been parsed
- and processed. The function is used to pass the received command data to
- the application.
-
- `conn' is the associated client connection. `cmd_payload' is the command
- payload data received from server and it can be ignored. It is provided
- if the application would like to re-parse the received command data,
- however, it must be noted that the data is parsed already by the library
- thus the payload can be ignored. `success' is FALSE if error occurred.
- In this case arguments are not sent to the application. The `status' is
- the command reply status server returned. The `command' is the command
- reply being processed. The function has variable argument list and each
- command defines the number and type of arguments it passes to the
- application (on error they are not sent). */
-
-static void
-silc_command_reply(SilcClient client, SilcClientConnection conn,
- SilcCommandPayload cmd_payload, bool success,
- SilcCommand command, SilcStatus status, ...)
-{
- SilcMapConnection mapconn = conn->context;
- va_list va;
-
- /* If error occurred in client library with our command, print the error */
- if (status != SILC_STATUS_OK)
- fprintf(stderr, "COMMAND REPLY %s: %s\n",
- silc_get_command_name(command),
- silc_get_status_message(status));
-
- if (!success)
- return;
-
- va_start(va, status);
-
- switch (command) {
- case SILC_COMMAND_STATS:
- {
- unsigned char *stats = va_arg(va, unsigned char *);
- SilcUInt32 stats_len = va_arg(va, SilcUInt32);
- SilcBufferStruct buf;
-
- SILC_LOG_DEBUG(("STATS command reply from %s", conn->sock->hostname));
-
- /* Get statistics structure */
- silc_buffer_set(&buf, stats, stats_len);
- silc_buffer_unformat(&buf,
- SILC_STR_UI_INT(&mapconn->data.starttime),
- SILC_STR_UI_INT(&mapconn->data.uptime),
- SILC_STR_UI_INT(&mapconn->data.clients),
- SILC_STR_UI_INT(&mapconn->data.channels),
- SILC_STR_UI_INT(&mapconn->data.server_ops),
- SILC_STR_UI_INT(&mapconn->data.router_ops),
- SILC_STR_UI_INT(&mapconn->data.cell_clients),
- SILC_STR_UI_INT(&mapconn->data.cell_channels),
- SILC_STR_UI_INT(&mapconn->data.cell_servers),
- SILC_STR_UI_INT(&mapconn->data.all_clients),
- SILC_STR_UI_INT(&mapconn->data.all_channels),
- SILC_STR_UI_INT(&mapconn->data.all_servers),
- SILC_STR_UI_INT(&mapconn->data.all_routers),
- SILC_STR_UI_INT(&mapconn->data.all_server_ops),
- SILC_STR_UI_INT(&mapconn->data.all_router_ops),
- SILC_STR_END);
-
- mapconn->stats_received = TRUE;
- }
- break;
-
- case SILC_COMMAND_MOTD:
- {
- char *motd = va_arg(va, char *);
-
- SILC_LOG_DEBUG(("MOTD command reply"));
-
- mapconn->data.motd = motd ? strdup(motd) : NULL;
- mapconn->motd_received = motd ? TRUE : FALSE;
- }
- break;
-
- default:
- SILC_LOG_DEBUG(("Unsupported command reply"));
- break;
- };
-
- va_end(va);
-
- if (mapconn->motd && !mapconn->motd_received)
- return;
- if (!mapconn->stats_received)
- return;
-
- silc_schedule_task_del_by_context(client->schedule, mapconn);
-
- /* All data is gathered, time to disconnect from the server. */
- silc_schedule_task_add(client->schedule, 0,
- silc_map_connect_close, mapconn, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-
-
-/* Called to indicate that connection was either successfully established
- or connecting failed. This is also the first time application receives
- the SilcClientConnection objecet which it should save somewhere.
- If the `success' is FALSE the application must always call the function
- silc_client_close_connection. */
-
-static void
-silc_connected(SilcClient client, SilcClientConnection conn,
- SilcClientConnectionStatus status)
-{
- SilcMapConnection mapconn = conn->context;
- SilcMap map = mapconn->map;
-
- silc_schedule_task_del_by_context(client->schedule, mapconn);
-
- if (status != SILC_CLIENT_CONN_SUCCESS) {
- fprintf(stderr, "Could not connect to server %s\n",
- conn->remote_host ? conn->remote_host : "");
- silc_client_close_connection(client, conn);
-
- /* Mark that this server is down. */
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_connect_timeout, mapconn, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- return;
- }
-
- if (mapconn->down) {
- /* Already timeouted */
- SILC_LOG_DEBUG(("Connection already timedout"));
- silc_client_close_connection(client, conn);
- return;
- }
-
- SILC_LOG_DEBUG(("Connected to server %s:%d", conn->remote_host,
- conn->remote_port));
-
- mapconn->conn = conn;
-
- /* Get statistics */
- silc_client_command_call(client, conn, "STATS");
-
- /* Get motd if requested */
- if (mapconn->motd) {
- char motd[256];
- char *hostname;
- silc_dlist_start(mapconn->hostnames);
- hostname = silc_dlist_get(mapconn->hostnames);
- memset(motd, 0, sizeof(motd));
- silc_strncat(motd, sizeof(motd), "MOTD ", 5);
- silc_strncat(motd, sizeof(motd), hostname, strlen(hostname));
- silc_client_command_call(client, conn, motd);
- }
-
- /* Set data timeout to detect if the server is down. */
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_data_timeout, mapconn,
- mapconn->connect_timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-
-
-/* Called to indicate that connection was disconnected to the server.
- The `status' may tell the reason of the disconnection, and if the
- `message' is non-NULL it may include the disconnection message
- received from server. */
-
-static void
-silc_disconnected(SilcClient client, SilcClientConnection conn,
- SilcStatus status, const char *message)
-{
- SilcMapConnection mapconn = conn->context;
-
- silc_schedule_task_del_by_context(client->schedule, mapconn);
-
- SILC_LOG_DEBUG(("Disconnected from server %s:%d", conn->remote_host,
- conn->remote_port));
-
- /* Mark that this server is down. */
- silc_schedule_task_add(map->client->schedule, 0,
- silc_map_connect_timeout, mapconn, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
- mapconn->conn = NULL;
-}
-
-
-/* Find authentication method and authentication data by hostname and
- port. The hostname may be IP address as well. When the authentication
- method has been resolved the `completion' callback with the found
- authentication method and authentication data is called. The `conn'
- may be NULL. */
-
-static void
-silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, SilcUInt16 port,
- SilcGetAuthMeth completion,
- void *context)
-{
- /* No auth */
- completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
-}
-
-
-/* Verifies received public key. The `conn_type' indicates which entity
- (server, client etc.) has sent the public key. If user decides to trust
- the application may save the key as trusted public key for later
- use. The `completion' must be called after the public key has been
- verified. */
-
-static void
-silc_verify_public_key(SilcClient client, SilcClientConnection conn,
- SilcSocketType conn_type, unsigned char *pk,
- SilcUInt32 pk_len, SilcSKEPKType pk_type,
- SilcVerifyPublicKey completion, void *context)
-{
- /* Accept all keys without verification */
- completion(TRUE, context);
-}
-
-
-/* Ask (interact, that is) a passphrase from user. The passphrase is
- returned to the library by calling the `completion' callback with
- the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
- if not then the library will attempt to encode. */
-
-static void
-silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
- SilcAskPassphrase completion, void *context)
-{
- completion(NULL, 0, context);
-}
-
-
-/* Notifies application that failure packet was received. This is called
- if there is some protocol active in the client. The `protocol' is the
- protocol context. The `failure' is opaque pointer to the failure
- indication. Note, that the `failure' is protocol dependant and
- application must explicitly cast it to correct type. Usually `failure'
- is 32 bit failure type (see protocol specs for all protocol failure
- types). */
-
-static void
-silc_failure(SilcClient client, SilcClientConnection conn,
- SilcProtocol protocol, void *failure)
-{
- fprintf(stderr, "Connecting failed (protocol failure)\n");
-}
-
-
-/* Asks whether the user would like to perform the key agreement protocol.
- This is called after we have received an key agreement packet or an
- reply to our key agreement packet. This returns TRUE if the user wants
- the library to perform the key agreement protocol and FALSE if it is not
- desired (application may start it later by calling the function
- silc_client_perform_key_agreement). If TRUE is returned also the
- `completion' and `context' arguments must be set by the application. */
-
-static bool
-silc_key_agreement(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry, const char *hostname,
- SilcUInt16 port, SilcKeyAgreementCallback *completion,
- void **context)
-{
- return FALSE;
-}
-
-
-/* Notifies application that file transfer protocol session is being
- requested by the remote client indicated by the `client_entry' from
- the `hostname' and `port'. The `session_id' is the file transfer
- session and it can be used to either accept or reject the file
- transfer request, by calling the silc_client_file_receive or
- silc_client_file_close, respectively. */
-
-static void
-silc_ftp(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry, SilcUInt32 session_id,
- const char *hostname, SilcUInt16 port)
-{
-
-}
-
-
-/* Delivers SILC session detachment data indicated by `detach_data' to the
- application. If application has issued SILC_COMMAND_DETACH command
- the client session in the SILC network is not quit. The client remains
- in the network but is detached. The detachment data may be used later
- to resume the session in the SILC Network. The appliation is
- responsible of saving the `detach_data', to for example in a file.
-
- The detachment data can be given as argument to the functions
- silc_client_connect_to_server, or silc_client_add_connection when
- creating connection to remote server, inside SilcClientConnectionParams
- structure. If it is provided the client library will attempt to resume
- the session in the network. After the connection is created
- successfully, the application is responsible of setting the user
- interface for user into the same state it was before detaching (showing
- same channels, channel modes, etc). It can do this by fetching the
- information (like joined channels) from the client library. */
-
-static void
-silc_detach(SilcClient client, SilcClientConnection conn,
- const unsigned char *detach_data, SilcUInt32 detach_data_len)
-{
-
-}
-
-/* This structure and all the functions were taken from the
- lib/silcclient/client_ops_example.c. */
-SilcClientOperations silc_map_client_ops = {
- silc_say,
- silc_channel_message,
- silc_private_message,
- silc_notify,
- silc_command,
- silc_command_reply,
- silc_connected,
- silc_disconnected,
- silc_get_auth_method,
- silc_verify_public_key,
- silc_ask_passphrase,
- silc_failure,
- silc_key_agreement,
- silc_ftp,
- silc_detach
-};
+++ /dev/null
-/*
-
- silcmap_command.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2004 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 "silcincludes.h"
-#include "silcclient.h"
-#include "silcmap.h"
-
-/******* Command Script Parsing **********************************************/
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_server);
-SILC_CONFIG_CALLBACK(silc_map_cmd_loadmap);
-SILC_CONFIG_CALLBACK(silc_map_cmd_writemap);
-SILC_CONFIG_CALLBACK(silc_map_cmd_writemaphtml);
-SILC_CONFIG_CALLBACK(silc_map_cmd_writehtml);
-SILC_CONFIG_CALLBACK(silc_map_cmd_writerel);
-SILC_CONFIG_CALLBACK(silc_map_cmd_cut);
-SILC_CONFIG_CALLBACK(silc_map_cmd_rectangle);
-SILC_CONFIG_CALLBACK(silc_map_cmd_circle);
-SILC_CONFIG_CALLBACK(silc_map_cmd_line);
-SILC_CONFIG_CALLBACK(silc_map_cmd_text);
-
-static const SilcConfigTable silc_map_table_loadmap[] =
-{
- { "filename", SILC_CONFIG_ARG_STR, silc_map_cmd_loadmap, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_writemap[] =
-{
- { "filename", SILC_CONFIG_ARG_STR, silc_map_cmd_writemap, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_writemaphtml[] =
-{
- { "filename", SILC_CONFIG_ARG_STR, silc_map_cmd_writemaphtml, NULL },
- { "image", SILC_CONFIG_ARG_STR, silc_map_cmd_writemaphtml, NULL },
- { "cut_lat", SILC_CONFIG_ARG_STRE, silc_map_cmd_writemaphtml, NULL },
- { "cut_lon", SILC_CONFIG_ARG_STRE, silc_map_cmd_writemaphtml, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_writehtml[] =
-{
- { "filename", SILC_CONFIG_ARG_STR, silc_map_cmd_writehtml, NULL },
- { "class", SILC_CONFIG_ARG_STRE, silc_map_cmd_writehtml, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_writerel[] =
-{
- { "filename", SILC_CONFIG_ARG_STR, silc_map_cmd_writerel, NULL },
- { "class", SILC_CONFIG_ARG_STRE, silc_map_cmd_writerel, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_cut[] =
-{
- { "lat", SILC_CONFIG_ARG_STR, silc_map_cmd_cut, NULL },
- { "lon", SILC_CONFIG_ARG_STR, silc_map_cmd_cut, NULL },
- { "width", SILC_CONFIG_ARG_INT, silc_map_cmd_cut, NULL },
- { "height", SILC_CONFIG_ARG_INT, silc_map_cmd_cut, NULL },
- { "filename", SILC_CONFIG_ARG_STR, silc_map_cmd_cut, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_rectangle[] =
-{
- { "lat", SILC_CONFIG_ARG_STR, silc_map_cmd_rectangle, NULL },
- { "lon", SILC_CONFIG_ARG_STR, silc_map_cmd_rectangle, NULL },
- { "color", SILC_CONFIG_ARG_STR, silc_map_cmd_rectangle, NULL },
- { "label", SILC_CONFIG_ARG_STR, silc_map_cmd_rectangle, NULL },
- { "lposx", SILC_CONFIG_ARG_INT, silc_map_cmd_rectangle, NULL },
- { "lposy", SILC_CONFIG_ARG_INT, silc_map_cmd_rectangle, NULL },
- { "lcolor", SILC_CONFIG_ARG_STR, silc_map_cmd_rectangle, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_circle[] =
-{
- { "lat", SILC_CONFIG_ARG_STR, silc_map_cmd_circle, NULL },
- { "lon", SILC_CONFIG_ARG_STR, silc_map_cmd_circle, NULL },
- { "color", SILC_CONFIG_ARG_STR, silc_map_cmd_circle, NULL },
- { "label", SILC_CONFIG_ARG_STR, silc_map_cmd_circle, NULL },
- { "lposx", SILC_CONFIG_ARG_INT, silc_map_cmd_circle, NULL },
- { "lposy", SILC_CONFIG_ARG_INT, silc_map_cmd_circle, NULL },
- { "lcolor", SILC_CONFIG_ARG_STR, silc_map_cmd_circle, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_line[] =
-{
- { "a_lat", SILC_CONFIG_ARG_STR, silc_map_cmd_line, NULL },
- { "a_lon", SILC_CONFIG_ARG_STR, silc_map_cmd_line, NULL },
- { "b_lat", SILC_CONFIG_ARG_STR, silc_map_cmd_line, NULL },
- { "b_lon", SILC_CONFIG_ARG_STR, silc_map_cmd_line, NULL },
- { "width", SILC_CONFIG_ARG_STR, silc_map_cmd_line, NULL },
- { "color", SILC_CONFIG_ARG_STR, silc_map_cmd_line, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_text[] =
-{
- { "lat", SILC_CONFIG_ARG_STR, silc_map_cmd_text, NULL },
- { "lon", SILC_CONFIG_ARG_STR, silc_map_cmd_text, NULL },
- { "color", SILC_CONFIG_ARG_STR, silc_map_cmd_text, NULL },
- { "text", SILC_CONFIG_ARG_STR, silc_map_cmd_text, NULL },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_server[] =
-{
- /* Details */
- { "hostname", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "ip", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "port", SILC_CONFIG_ARG_INT, silc_map_cmd_server, NULL },
- { "public_key", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "country", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "city", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "admin", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "description", SILC_CONFIG_ARG_STRE, silc_map_cmd_server, NULL },
- { "html_url", SILC_CONFIG_ARG_STRE, silc_map_cmd_server, NULL },
-
- /* Connect params */
- { "connect", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "connect_timeout", SILC_CONFIG_ARG_INT, silc_map_cmd_server, NULL },
-
- /* Statistics */
- { "starttime", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "uptime", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "clients", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "channels", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "server_ops", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "router_ops", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "cell_clients", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "cell_channels", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "cell_servers", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "all_clients", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "all_channels", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "all_servers", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "all_routers", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "all_server_ops", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "all_router_ops", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
- { "motd", SILC_CONFIG_ARG_TOGGLE, silc_map_cmd_server, NULL },
-
- /* Colors */
- { "up_color", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "down_color", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "up_text_color", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
- { "down_text_color", SILC_CONFIG_ARG_STR, silc_map_cmd_server, NULL },
-
- /* Map commands */
- { "cut", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_cut, silc_map_table_cut },
- { "rectangle", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_rectangle, silc_map_table_rectangle },
- { "circle", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_circle, silc_map_table_circle },
- { "line", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_line, silc_map_table_line },
- { "text", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_text, silc_map_table_text },
- { NULL },
-};
-
-static const SilcConfigTable silc_map_table_main[] =
-{
- { "server", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_server, silc_map_table_server },
- { "loadmap", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_loadmap, silc_map_table_loadmap },
- { "writemap", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_writemap, silc_map_table_writemap },
- { "writemaphtml", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_writemaphtml, silc_map_table_writemaphtml },
- { "writehtml", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_writehtml, silc_map_table_writehtml },
- { "writerel", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_writerel, silc_map_table_writerel },
- { "cut", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_cut, silc_map_table_cut },
- { "rectangle", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_rectangle, silc_map_table_rectangle },
- { "circle", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_circle, silc_map_table_circle },
- { "line", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_line, silc_map_table_line },
- { "text", SILC_CONFIG_ARG_BLOCK,
- silc_map_cmd_text, silc_map_table_text },
- { NULL },
-};
-
-/* Command datas. Used when command is outside server { } section. */
-static char *filename = NULL;
-static char *lat = NULL;
-static char *lon = NULL;
-static char *lat2 = NULL;
-static char *lon2 = NULL;
-static SilcUInt32 width = 0;
-static SilcUInt32 height = 0;
-static SilcInt16 r = 0;
-static SilcInt16 g = 0;
-static SilcInt16 b = 0;
-static SilcInt16 lr = -1;
-static SilcInt16 lg = -1;
-static SilcInt16 lb = -1;
-static char *text = NULL;
-static SilcInt32 lposx = 0;
-static SilcInt32 lposy = 0;
-static bool color_set = FALSE;
-static bool lcolor_set = FALSE;
-
-/* Current server section. */
-SilcMapConnection curr_conn = NULL;
-
-/* Command: server, performs the connection to the remote server and
- gathers statistical information. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_server)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
-
- if (!map->loadmap.loadmap) {
- fprintf(stderr, "You must call loadmap command before server command\n");
- return SILC_CONFIG_ESILENT;
- }
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- SILC_LOG_DEBUG(("Server config parsed"));
-
- if (!curr_conn->ips) {
- fprintf(stderr, "IP must be configured\n");
- return SILC_CONFIG_EMISSFIELDS;
- }
- if (!curr_conn->hostnames) {
- fprintf(stderr, "Hostname must be configured\n");
- return SILC_CONFIG_EMISSFIELDS;
- }
- if (!curr_conn->port) {
- fprintf(stderr, "Port must be configured\n");
- return SILC_CONFIG_EMISSFIELDS;
- }
-
- /* The server data is now gathered. We continue by creating the
- connection to the server and executing the requested commands. */
- silc_map_connect(map, curr_conn);
- map->conns_num++;
-
- /* Cleanup */
- curr_conn = NULL;
-
- return retval;
- }
-
- /* Mark the current parsed server */
- if (!curr_conn) {
- curr_conn = silc_calloc(1, sizeof(*curr_conn));
- if (!curr_conn)
- return SILC_CONFIG_ESILENT;
-
- curr_conn->hostnames = silc_dlist_init();
- curr_conn->ips = silc_dlist_init();
- curr_conn->commands = silc_dlist_init();
- curr_conn->map = map;
- if (!map->conns)
- map->conns = silc_dlist_init();
- silc_dlist_add(map->conns, curr_conn);
- }
-
- if (!strcmp(name, "hostname")) {
- silc_dlist_add(curr_conn->hostnames, strdup((char *)val));
- } else if (!strcmp(name, "ip")) {
- silc_dlist_add(curr_conn->ips, strdup((char *)val));
- } else if (!strcmp(name, "port")) {
- curr_conn->port = (SilcUInt32)*(int *)val;
- } else if (!strcmp(name, "public_key")) {
- curr_conn->public_key = strdup((char *)val);
- } else if (!strcmp(name, "country")) {
- curr_conn->country = strdup((char *)val);
- } else if (!strcmp(name, "city")) {
- curr_conn->city = strdup((char *)val);
- } else if (!strcmp(name, "admin")) {
- curr_conn->admin = strdup((char *)val);
- } else if (!strcmp(name, "description")) {
- curr_conn->description = strdup((char *)val);
- } else if (!strcmp(name, "html_url")) {
- curr_conn->html_url = strdup((char *)val);
- } else if (!strcmp(name, "connect")) {
- curr_conn->connect = (bool)*(int *)val;
- } else if (!strcmp(name, "connect_timeout")) {
- curr_conn->connect_timeout = (SilcUInt32)*(int *)val;
- } else if (!strcmp(name, "starttime")) {
- curr_conn->starttime = (bool)*(int *)val;
- } else if (!strcmp(name, "uptime")) {
- curr_conn->uptime = (bool)*(int *)val;
- } else if (!strcmp(name, "clients")) {
- curr_conn->clients = (bool)*(int *)val;
- } else if (!strcmp(name, "channels")) {
- curr_conn->channels = (bool)*(int *)val;
- } else if (!strcmp(name, "server_ops")) {
- curr_conn->server_ops = (bool)*(int *)val;
- } else if (!strcmp(name, "router_ops")) {
- curr_conn->router_ops = (bool)*(int *)val;
- } else if (!strcmp(name, "cell_clients")) {
- curr_conn->cell_clients = (bool)*(int *)val;
- } else if (!strcmp(name, "cell_channels")) {
- curr_conn->cell_channels = (bool)*(int *)val;
- } else if (!strcmp(name, "cell_servers")) {
- curr_conn->cell_servers = (bool)*(int *)val;
- } else if (!strcmp(name, "all_clients")) {
- curr_conn->all_clients = (bool)*(int *)val;
- } else if (!strcmp(name, "all_channels")) {
- curr_conn->all_channels = (bool)*(int *)val;
- } else if (!strcmp(name, "all_servers")) {
- curr_conn->all_servers = (bool)*(int *)val;
- } else if (!strcmp(name, "all_routers")) {
- curr_conn->all_routers = (bool)*(int *)val;
- } else if (!strcmp(name, "all_server_ops")) {
- curr_conn->all_server_ops = (bool)*(int *)val;
- } else if (!strcmp(name, "all_router_ops")) {
- curr_conn->all_router_ops = (bool)*(int *)val;
- } else if (!strcmp(name, "motd")) {
- curr_conn->motd = (bool)*(int *)val;
- } else if (!strcmp(name, "up_color")) {
- curr_conn->up_color = strdup((char *)val);
- } else if (!strcmp(name, "down_color")) {
- curr_conn->down_color = strdup((char *)val);
- } else if (!strcmp(name, "up_text_color")) {
- curr_conn->up_text_color = strdup((char *)val);
- } else if (!strcmp(name, "down_text_color")) {
- curr_conn->down_text_color = strdup((char *)val);
- } else {
- retval = SILC_CONFIG_ESILENT;
- }
-
- return retval;
-}
-
-/* Command: loadmap, loadmaps the bitmap map image. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_loadmap)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!filename)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("loadmap: file: %s", filename));
-
- map->loadmap.filename = strdup(filename);
- map->loadmap.loadmap = TRUE;
-
- /* Cleanup */
- silc_free(filename);
- filename = NULL;
-
- return retval;
- }
-
- if (!strcmp(name, "filename"))
- filename = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: writemap, writemap the map into bitmap file. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_writemap)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!filename)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("writemap: file: %s", filename));
-
- map->writemap.filename = strdup(filename);
- map->writemap.writemap = TRUE;
-
- /* Cleanup */
- silc_free(filename);
- filename = NULL;
-
- return retval;
- }
-
- if (!strcmp(name, "filename"))
- filename = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: writemaphtml, writes HTML map of the image map. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_writemaphtml)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- int i;
- if (!filename)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("writemaphtml: file: %s", filename));
-
- /* Will generate HTML map page */
- i = map->writemaphtml_count;
- map->writemaphtml = silc_realloc(map->writemaphtml,
- sizeof(*map->writemaphtml) * (i + 1));
- map->writemaphtml[i].filename = filename;
- map->writemaphtml[i].text = text;
- if (lon)
- map->writemaphtml[i].alon = strdup(lon);
- if (lat)
- map->writemaphtml[i].alat = strdup(lat);
- map->writemaphtml[i].writemaphtml = TRUE;
- map->writemaphtml_count++;
-
- /* Clean up */
- silc_free(lat);
- silc_free(lon);
- filename = NULL;
- text = NULL;
- lat = lon = NULL;
-
- return retval;
- }
-
- if (!strcmp(name, "filename"))
- filename = strdup((char *)val);
- else if (!strcmp(name, "image"))
- text = strdup((char *)val);
- else if (!strcmp(name, "cut_lat"))
- lat = strdup((char *)val);
- else if (!strcmp(name, "cut_lon"))
- lon = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: writehtml, writes the gathered data into HTML pages. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_writehtml)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!filename)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("writehtml: file: %s", filename));
-
- /* Will generate HTML pages */
- map->writehtml.filename = filename;
- map->writehtml.text = text; /* class */
- map->writehtml.writehtml = TRUE;
- filename = text = NULL;
-
- return retval;
- }
- if (!strcmp(name, "filename"))
- filename = strdup((char *)val);
- else if (!strcmp(name, "class"))
- text = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: writerel, writes the uptime reliability graph. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_writerel)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!filename)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("writerel: file: %s", filename));
-
- /* Will generate uptime reliability graph */
- map->writerel.filename = filename;
- map->writerel.text = text; /* class */
- map->writerel.writerel = TRUE;
- filename = text = NULL;
-
- return retval;
- }
- if (!strcmp(name, "filename"))
- filename = strdup((char *)val);
- else if (!strcmp(name, "class"))
- text = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: cut, cut's a specified area from the map. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_cut)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
- bool ret;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- SilcMap map2;
- int i;
-
- if (!filename || !lat || !lon || !width || !height)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("cut: lat: %s lon: %s w: %ld h: %ld file: %s",
- lat, lon, width, height, filename));
-
- /* Execute directly if not inside connection block */
- if (!curr_conn) {
- if (!map->conns_num) {
- /* Before any connection blocks */
-
- /* Cut the chunk from the map. */
- ret = silc_map_cut(map, silc_map_lon2x(map, lon),
- silc_map_lat2y(map, lat),
- width, height, &map2);
- if (ret) {
- /* Writemap the chunk. */
- ret = silc_map_write_ppm(map2, filename);
- silc_map_free(map2);
- }
- if (!ret)
- retval = SILC_CONFIG_ESILENT;
- } else {
- /* After all connection blocks */
- i = map->cut_count;
- map->cut = silc_realloc(map->cut, sizeof(*map->cut) * (i + 1));
- map->cut[i].filename = strdup(filename);
- map->cut[i].alon = strdup(lon);
- map->cut[i].alat = strdup(lat);
- map->cut[i].width = width;
- map->cut[i].height = height;
- map->cut[i].cut = TRUE;
- map->cut_count++;
- }
- } else {
- SilcMapCommand cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return SILC_CONFIG_ESILENT;
-
- silc_dlist_add(curr_conn->commands, cmd);
- cmd->filename = strdup(filename);
- cmd->alon = strdup(lon);
- cmd->alat = strdup(lat);
- cmd->width = width;
- cmd->height = height;
- cmd->cut = TRUE;
- }
-
- /* Cleanup */
- silc_free(filename);
- silc_free(lat);
- silc_free(lon);
- filename = NULL;
- lat = NULL;
- lon = NULL;
- width = 0;
- height = 0;
-
- return retval;
- }
-
- if (!strcmp(name, "lat"))
- lat = strdup((char *)val);
- else if (!strcmp(name, "lon"))
- lon = strdup((char *)val);
- else if (!strcmp(name, "width"))
- width = (SilcUInt32)*(int *)val;
- else if (!strcmp(name, "height"))
- height = (SilcUInt32)*(int *)val;
- else if (!strcmp(name, "filename"))
- filename = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: rectangle, draws a rectangle on the map. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_rectangle)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
- bool ret;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!lat || !lon)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("rectangle: lat: %s lon: %s color: %d %d %d",
- lat, lon, r, g, b));
-
- if (lr == -1) {
- lr = r;
- lg = g;
- lb = b;
- }
-
- /* Execute directly if not for connection */
- if (!curr_conn && map->bitmap) {
- /* Draw the rectangle */
- ret = silc_map_draw_rectangle(map, silc_map_lon2x(map, lon),
- silc_map_lat2y(map, lat),
- r, g, b, text, lposx, lposy, lr, lg, lb);
- if (!ret)
- retval = SILC_CONFIG_ESILENT;
- } else {
- SilcMapCommand cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return SILC_CONFIG_ESILENT;
-
- silc_dlist_add(curr_conn->commands, cmd);
- cmd->r = r;
- cmd->g = g;
- cmd->b = b;
- cmd->lr = lr;
- cmd->lg = lg;
- cmd->lb = lb;
- cmd->alon = strdup(lon);
- cmd->alat = strdup(lat);
- cmd->text = text ? strdup(text) : NULL;
- cmd->lposx = lposx;
- cmd->lposy = lposy;
- cmd->draw_rectangle = TRUE;
- cmd->color_set = color_set;
- cmd->lcolor_set = lcolor_set;
- }
-
- /* Cleanup */
- silc_free(text);
- silc_free(lat);
- silc_free(lon);
- text = NULL;
- lat = NULL;
- lon = NULL;
- lposx = 0;
- lposy = 0;
- lr = lg = lb = -1;
- color_set = lcolor_set = FALSE;
-
- return retval;
- }
-
- if (!strcmp(name, "lat"))
- lat = strdup((char *)val);
- else if (!strcmp(name, "lon"))
- lon = strdup((char *)val);
- else if (!strcmp(name, "color")) {
- if (!silc_map_parse_color((const char *)val, &r, &g, &b))
- retval = SILC_CONFIG_ESILENT;
- color_set = TRUE;
- } else if (!strcmp(name, "label"))
- text = strdup((char *)val);
- else if (!strcmp(name, "lposx"))
- lposx = (SilcInt32)*(int *)val;
- else if (!strcmp(name, "lposy"))
- lposy = (SilcInt32)*(int *)val;
- else if (!strcmp(name, "lcolor")) {
- if (!silc_map_parse_color((const char *)val, &lr, &lg, &lb))
- retval = SILC_CONFIG_ESILENT;
- lcolor_set = TRUE;
- } else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: circle, draws a circle on the map. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_circle)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
- bool ret;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!lat || !lon)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("circle: lat: %s lon: %s color: %d %d %d",
- lat, lon, r, g, b));
-
- if (lr == -1) {
- lr = r;
- lg = g;
- lb = b;
- }
-
- /* Execute directly if not for connection */
- if (!curr_conn && map->bitmap) {
- /* Draw the circle */
- ret = silc_map_draw_circle(map, silc_map_lon2x(map, lon),
- silc_map_lat2y(map, lat),
- r, g, b, text, lposx, lposy, lr, lg, lb);
- if (!ret)
- retval = SILC_CONFIG_ESILENT;
- } else {
- SilcMapCommand cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return SILC_CONFIG_ESILENT;
-
- silc_dlist_add(curr_conn->commands, cmd);
- cmd->r = r;
- cmd->g = g;
- cmd->b = b;
- cmd->lr = lr;
- cmd->lg = lg;
- cmd->lb = lb;
- cmd->alon = strdup(lon);
- cmd->alat = strdup(lat);
- cmd->text = text ? strdup(text) : NULL;
- cmd->lposx = lposx;
- cmd->lposy = lposy;
- cmd->draw_circle = TRUE;
- cmd->color_set = color_set;
- cmd->lcolor_set = lcolor_set;
- }
-
- /* Cleanup */
- silc_free(text);
- silc_free(lat);
- silc_free(lon);
- text = NULL;
- lat = NULL;
- lon = NULL;
- lposx = 0;
- lposy = 0;
- lr = lg = lb = -1;
- color_set = lcolor_set = FALSE;
-
- return retval;
- }
-
- if (!strcmp(name, "lat"))
- lat = strdup((char *)val);
- else if (!strcmp(name, "lon"))
- lon = strdup((char *)val);
- else if (!strcmp(name, "color")) {
- if (!silc_map_parse_color((const char *)val, &r, &g, &b))
- retval = SILC_CONFIG_ESILENT;
- color_set = TRUE;
- } else if (!strcmp(name, "label"))
- text = strdup((char *)val);
- else if (!strcmp(name, "lposx"))
- lposx = (SilcInt32)*(int *)val;
- else if (!strcmp(name, "lposy"))
- lposy = (SilcInt32)*(int *)val;
- else if (!strcmp(name, "lcolor")) {
- if (!silc_map_parse_color((const char *)val, &lr, &lg, &lb))
- retval = SILC_CONFIG_ESILENT;
- lcolor_set = TRUE;
- } else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: line, draws a line between two points in the map. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_line)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
- bool ret;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!lat || !lon || !lat2 || !lon2)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("line: alat: %s alon: %s blat: %s blon: %s "
- "width: %ld color: %d %d %d",
- lat, lon, lat2, lon2, width, r, g, b));
-
- if (!width)
- width = 1;
-
- /* Execute directly if not for connection */
- if (!curr_conn && map->bitmap) {
- /* Draw the line */
- ret = silc_map_draw_line(map, width,
- silc_map_lon2x(map, lon),
- silc_map_lat2y(map, lat),
- silc_map_lon2x(map, lon2),
- silc_map_lat2y(map, lat2),
- r, g, b);
- if (!ret)
- retval = SILC_CONFIG_ESILENT;
- } else {
- SilcMapCommand cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return SILC_CONFIG_ESILENT;
-
- silc_dlist_add(curr_conn->commands, cmd);
- cmd->r = r;
- cmd->g = g;
- cmd->b = b;
- cmd->alon = strdup(lon);
- cmd->alat = strdup(lat);
- cmd->blon = strdup(lon2);
- cmd->blat = strdup(lat2);
- cmd->width = width;
- cmd->draw_line = TRUE;
- cmd->color_set = color_set;
- }
-
- /* Cleanup */
- silc_free(lat);
- silc_free(lon);
- silc_free(lat2);
- silc_free(lon2);
- lat = NULL;
- lon = NULL;
- lat2 = NULL;
- lon2 = NULL;
- width = 0;
- color_set = FALSE;
-
- return retval;
- }
-
- if (!strcmp(name, "a_lat"))
- lat = strdup((char *)val);
- else if (!strcmp(name, "a_lon"))
- lon = strdup((char *)val);
- else if (!strcmp(name, "b_lat"))
- lat2 = strdup((char *)val);
- else if (!strcmp(name, "b_lon"))
- lon2 = strdup((char *)val);
- else if (!strcmp(name, "width"))
- width = (SilcUInt32)*(int *)val;
- else if (!strcmp(name, "color")) {
- if (!silc_map_parse_color((const char *)val, &r, &g, &b))
- retval = SILC_CONFIG_ESILENT;
- color_set = TRUE;
- } else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Command: text, prints a text on the map. */
-
-SILC_CONFIG_CALLBACK(silc_map_cmd_text)
-{
- SilcMap map = context;
- int retval = SILC_CONFIG_OK;
- bool ret;
-
- if (type == SILC_CONFIG_ARG_BLOCK) {
- if (!lat || !lon || !text)
- return SILC_CONFIG_EMISSFIELDS;
-
- SILC_LOG_DEBUG(("text: lat: %s lon: %s color: %d %d %d text: %s",
- lat, lon, r, g, b, text));
-
- /* Execute directly if not for connection */
- if (!curr_conn && map->bitmap) {
- /* Print the text */
- ret = silc_map_draw_text(map, text,
- silc_map_lon2x(map, lon),
- silc_map_lat2y(map, lat),
- r, g, b);
- if (!ret)
- retval = SILC_CONFIG_ESILENT;
- } else {
- SilcMapCommand cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return SILC_CONFIG_ESILENT;
-
- silc_dlist_add(curr_conn->commands, cmd);
- cmd->r = r;
- cmd->g = g;
- cmd->b = b;
- cmd->alon = strdup(lon);
- cmd->alat = strdup(lat);
- cmd->text = text ? strdup(text) : NULL;
- cmd->draw_text = TRUE;
- cmd->color_set = color_set;
- }
-
- /* Cleanup */
- silc_free(text);
- silc_free(lat);
- silc_free(lon);
- text = NULL;
- lat = NULL;
- lon = NULL;
- color_set = FALSE;
-
- return retval;
- }
-
- if (!strcmp(name, "lat"))
- lat = strdup((char *)val);
- else if (!strcmp(name, "lon"))
- lon = strdup((char *)val);
- else if (!strcmp(name, "color")) {
- if (!silc_map_parse_color((const char *)val, &r, &g, &b))
- retval = SILC_CONFIG_ESILENT;
- color_set = TRUE;
- } else if (!strcmp(name, "text"))
- text = strdup((char *)val);
- else
- retval = SILC_CONFIG_ESILENT;
-
- return retval;
-}
-
-/* Parses the commands from the file `filename'. */
-
-bool silc_map_commands_parse(SilcMap map, const char *filename)
-{
- SilcConfigEntity ent;
- SilcConfigFile *file;
- bool retval = TRUE;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing commands"));
-
- /* Open commands file */
- file = silc_config_open(filename);
- if (!file) {
- fprintf(stderr, "Cannot open commands file '%s'\n", filename);
- return FALSE;
- }
-
- /* Parse the commands */
- ent = silc_config_init(file);
- silc_config_register_table(ent, silc_map_table_main, map);
- ret = silc_config_main(ent);
-
- SILC_LOG_DEBUG(("Parsing status: %s", silc_config_strerror(ret)));
-
- if (ret && ret != SILC_CONFIG_ESILENT) {
- fprintf(stderr, "Error parsing commands: %s, line %d\n",
- silc_config_strerror(ret), (int)silc_config_get_line(file));
- retval = FALSE;
- }
-
- /* Cleanup */
- silc_config_close(file);
- return retval;
-}
+++ /dev/null
-/*
-
- silcmap_html.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2004 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 "silcincludes.h"
-#include "silcclient.h"
-#include "silcmap.h"
-
-/* Write the HTML data file of the gathered data from the connection. */
-
-bool silc_map_writehtml(SilcMap map, SilcMapConnection mapconn)
-{
- FILE *fp;
- char *hostname;
- char filename[256], line[128];
- int begin;
-
- /* Generate data filename. First configure hostname is the filename */
- silc_dlist_start(mapconn->hostnames);
- hostname = silc_dlist_get(mapconn->hostnames);
- memset(filename, 0, sizeof(filename));
- snprintf(filename, sizeof(filename) - 1, "%s_%d.html", hostname,
- mapconn->port);
-
- /* Open for writing */
- fp = fopen(filename, "w+");
- if (!fp) {
- fprintf(stderr, "Could not open file '%s'\n", filename);
- return FALSE;
- }
-
- /* Write the HTML page */
-
- fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
- fprintf(fp, "<br /><hr ><br />\n");
-
- /* General stuff */
-
- fprintf(fp, "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n");
- silc_dlist_start(mapconn->hostnames);
- while ((hostname = silc_dlist_get(mapconn->hostnames)) != SILC_LIST_END)
- fprintf(fp, "<tr><td><b>Hostname</b></td><td> :</td><td> %s</td></tr>\n", hostname);
-
- silc_dlist_start(mapconn->ips);
- while ((hostname = silc_dlist_get(mapconn->ips)) != SILC_LIST_END)
- fprintf(fp, "<tr><td><b>IP</b></td><td> :</td><td> %s</td></tr>\n", hostname);
-
- fprintf(fp, "<tr><td><b>Port</b></td><td> :</td><td> %d</td></tr>\n", mapconn->port);
- fprintf(fp, "<tr><td><b>Country</b></td><td> :</td><td> %s</td></tr>\n", mapconn->country);
- fprintf(fp, "<tr><td><b>City</b></td><td> :</td><td> %s</td></tr>\n", mapconn->city);
- fprintf(fp, "<tr><td><b>Admin</b></td><td> :</td><td> %s</td></tr>\n", mapconn->admin);
- fprintf(fp, "</table>\n");
-
- /* Public key */
- if (mapconn->public_key) {
- SilcPublicKey public_key;
- SilcPublicKeyIdentifier ident;
- char *fingerprint, *babbleprint;
- unsigned char *pk;
- SilcUInt32 pk_len;
- SilcPKCS pkcs;
- SilcUInt32 key_len = 0;
- FILE *pd;
- unsigned char *pdd;
-
- fprintf(fp, " <br /><hr ><br />\n");
- fprintf(fp, "<b>Public Key:</b> <br />\n");
- fprintf(fp, "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n");
-
- if (silc_pkcs_load_public_key(mapconn->public_key, &public_key,
- SILC_PKCS_FILE_PEM) == FALSE)
- if (silc_pkcs_load_public_key(mapconn->public_key, &public_key,
- SILC_PKCS_FILE_BIN) == FALSE) {
- fprintf(stderr, "Could not load public key file `%s'\n",
- mapconn->public_key);
- return FALSE;
- }
-
- ident = silc_pkcs_decode_identifier(public_key->identifier);
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
-
- if (silc_pkcs_alloc(public_key->name, &pkcs)) {
- key_len = silc_pkcs_public_key_set(pkcs, public_key);
- silc_pkcs_free(pkcs);
- }
-
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Public key file</td><td> :</td><td> <a href=\"%s\">%s</a></td></tr>\n",
- mapconn->public_key, mapconn->public_key);
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Algorithm</td><td> :</td><td> %s</td></tr>\n", public_key->name);
- if (key_len) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Key length</td><td> :</td><td> %d bits</td></tr>\n", (unsigned int)key_len);
- }
- if (ident->realname) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Real name</td><td> :</td><td> %s</td></tr>\n", ident->realname);
- }
- if (ident->username) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Username</td><td> :</td><td> %s</td></tr>\n", ident->username);
- }
- if (ident->host) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Hostname</td><td> :</td><td> %s</td></tr>\n", ident->host);
- }
- if (ident->email) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Email</td><td> :</td><td> %s</td></tr>\n", ident->email);
- }
- if (ident->org) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Organization</td><td> :</td><td> %s</td></tr>\n", ident->org);
- }
- if (ident->country) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Country</td><td> :</td><td> %s</td></tr>\n", ident->country);
- }
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Fingerprint</td><td> :</td><td> <tt>%s</tt></td></tr>\n", fingerprint);
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Babbleprint</td><td> :</td><td> <tt>%s</tt></td></tr>\n", babbleprint);
- fprintf(fp, "</table>\n");
-
- pd = fopen(mapconn->public_key, "r");
- if (!pd)
- return FALSE;
-
- pk_len = silc_file_size(mapconn->public_key);
- pdd = silc_calloc(pk_len + 2, sizeof(*pdd));
- if (!pdd)
- return FALSE;
- fread(pdd, pk_len, 1, pd);
- pdd[pk_len] = EOF;
-
- fprintf(fp, "<br /><tt><small>\n");
- begin = 0;
- while ((begin = silc_gets(line, sizeof(line) - 1, pdd, pk_len + 1,
- begin)) != EOF)
- fprintf(fp, "%s<br />\n", line);
- fprintf(fp, "</small></tt><br />\n");
-
- fclose(pd);
- silc_free(pdd);
- silc_free(fingerprint);
- silc_free(babbleprint);
- silc_free(pk);
- silc_pkcs_public_key_free(public_key);
- silc_pkcs_free_identifier(ident);
- }
-
- /* Description */
- if (mapconn->description && mapconn->description[0]) {
- fprintf(fp, "<hr ><br />\n");
- fprintf(fp, "<b>Description:</b> <br />\n");
- fprintf(fp, "%s<br /> <br />\n", mapconn->description);
- }
-
- /* Status */
- if (mapconn->connect) {
- fprintf(fp, "<hr ><br />\n");
- fprintf(fp, "<b>Server status:</b> <br />\n");
- if (mapconn->down)
- fprintf(fp,
- "Server is currently down and unreachable. "
- "Please try again later to connect the server.<br />\n");
- else
- fprintf(fp,
- "Server is up and running<br />\n");
- }
-
- if (mapconn->connect && !mapconn->down) {
- int days, hours, mins, secs, uptime;
-
- uptime = mapconn->data.uptime;
- days = uptime / (24 * 60 * 60);
- uptime -= days * (24 * 60 * 60);
- hours = uptime / (60 * 60);
- uptime -= hours * (60 * 60);
- mins = uptime / 60;
- uptime -= mins * 60;
- secs = uptime;
-
- /* Statistics */
- fprintf(fp, "<br />\n");
- fprintf(fp, "<b>Server statistics:</b> <br />\n");
- fprintf(fp, "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n");
- if (mapconn->starttime) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Server start time</td><td> :</td><td> %s<td></tr>\n",
- silc_get_time(mapconn->data.starttime));
- }
- if (mapconn->uptime) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Server uptime</td><td> :</td><td> %d days %d hours %d mins %d secs<td></tr>\n",
- days, hours, mins, secs);
- }
- if (mapconn->clients) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Local clients</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.clients);
- }
- if (mapconn->channels) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Local channels</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.channels);
- }
- if (mapconn->server_ops) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Local server operators</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.server_ops);
- }
- if (mapconn->router_ops) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Local router operators</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.router_ops);
- }
- if (mapconn->cell_clients) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Cell clients</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.cell_clients);
- }
- if (mapconn->cell_channels) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Cell channels</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.cell_channels);
- }
- if (mapconn->cell_servers) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "Cell servers</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.cell_servers);
- }
- if (mapconn->all_clients) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "All SILC clients</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.all_clients);
- }
- if (mapconn->all_channels) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "All SILC channels</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.all_channels);
- }
- if (mapconn->all_servers) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "All SILC servers</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.all_servers);
- }
- if (mapconn->all_routers) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "All SILC routers</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.all_routers);
- }
- if (mapconn->all_server_ops) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "All SILC server operators</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.all_server_ops);
- }
- if (mapconn->all_router_ops) {
- fprintf(fp, "<tr><td> ");
- fprintf(fp, "All SILC router operators</td><td> :</td><td> %ld</td></tr>\n",
- (unsigned long)mapconn->data.all_router_ops);
- }
- fprintf(fp, "</table>\n");
- }
-
- /* motd */
- if (mapconn->motd && mapconn->data.motd) {
- fprintf(fp, " <br /><hr ><br />\n");
- fprintf(fp, "<b>Message of the Day:</b> <br />\n");
-
- fprintf(fp, "<br /><tt><small>\n");
- begin = 0;
- while ((begin = silc_gets(line, sizeof(line) - 1, mapconn->data.motd,
- strlen(mapconn->data.motd), begin)) != EOF)
- fprintf(fp, "%s<br />\n", line);
- fprintf(fp, "</small></tt>\n");
- }
-
- fprintf(fp, "<br />\n");
-
- fclose(fp);
- return TRUE;
-}
-
-/* Write the HTML index file that lists all servers. */
-
-bool silc_map_writehtml_index(SilcMap map)
-{
- SilcMapConnection mapconn;
- char *hostname, *ip, *class;
- FILE *fp;
-
- /* Open for writing */
- fp = fopen(map->writehtml.filename, "w+");
- if (!fp) {
- fprintf(stderr, "Could not open file '%s'\n", map->writehtml.filename);
- return FALSE;
- }
-
- /* Produce a simple HTML index file of all servers */
- class = map->writehtml.text ? map->writehtml.text : "silcmap";
-
- fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
- fprintf(fp, "<br />\n");
- fprintf(fp, "<table cellspacing=\"0\" cellpadding=\"0\" "
- "class=\"%s\" border=\"0\">\n", class);
- fprintf(fp,
- "<tr>\n"
- "<td align=\"center\" class=\"%s_header\"><b>Hostname</b></td>\n"
- "<td align=\"center\" class=\"%s_header\"><b>IPv4 Address</b></td>\n"
- "<td align=\"center\" class=\"%s_header\"><b>Port</b></td>\n"
- "<td align=\"center\" class=\"%s_header\"><b>Country</b></td>\n"
- "<td align=\"center\" class=\"%s_header\"><b>Oper</b></td>\n"
- "</tr>\n", class, class, class, class, class);
-
- silc_dlist_start(map->conns);
- while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
-
- silc_dlist_start(mapconn->hostnames);
- hostname = silc_dlist_get(mapconn->hostnames);
- silc_dlist_start(mapconn->ips);
- ip = silc_dlist_get(mapconn->ips);
-
- fprintf(fp, "<tr>\n");
- if (mapconn->html_url)
- fprintf(fp,
- "<td align = \"center\" class=\"%s\"> <a href=\"%s\">%s</a></td>\n", class, mapconn->html_url, hostname);
- else
- fprintf(fp,
- "<td align = \"center\" class=\"%s\"> <a href=\"%s_%d.html\">%s</a></td>\n", class, hostname, mapconn->port, hostname);
- fprintf(fp,
- "<td align = \"center\" class=\"%s\"> %s</td>\n"
- "<td align = \"center\" class=\"%s\"> %d</td>\n"
- "<td align = \"center\" class=\"%s\"> %s</td>\n"
- "<td align = \"center\" class=\"%s\"> %s</td>\n"
- "</tr>\n",
- class, ip, class, mapconn->port, class,
- mapconn->country, class, mapconn->admin);
- }
-
- fprintf(fp, "</table><br />\n");
-
- return TRUE;
-}
-
-/* Creates a HTML map file, which can be used to allow user to click
- URLs on the image at the specified locations. */
-
-bool silc_map_writemaphtml(SilcMap map)
-{
- SilcMapConnection mapconn;
- SilcMapCommand cmd, c;
- char *hostname, url[256];
- FILE *fp;
- int i, xx , yy, w, h;
-
- for (i = 0; i < map->writemaphtml_count; i++) {
- c = &map->writemaphtml[i];
- if (c->alon && c->alat) {
- c->x = silc_map_lon2x(map, c->alon);
- c->y = silc_map_lat2y(map, c->alat);
- }
-
- /* Open for writing */
- fp = fopen(c->filename, "w+");
- if (!fp) {
- fprintf(stderr, "Could not open file '%s'\n", c->filename);
- return FALSE;
- }
-
- /* The target may be portion of the original map, so we must make the
- new coordinates relative to the new map. */
- xx = c->x;
- yy = c->y;
-
- memset(url, 0, sizeof(url));
-
- fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
- fprintf(fp, "<img src=\"%s\" usemap=\"#map\" class=\"silcmap\">\n",
- c->text);
- fprintf(fp, "<map name=\"map\">\n");
-
- silc_dlist_start(map->conns);
- while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
- memset(url, 0, sizeof(url));
- if (mapconn->html_url && mapconn->html_url[0]) {
- silc_strncat(url, sizeof(url), mapconn->html_url,
- strlen(mapconn->html_url));
- } else {
- silc_dlist_start(mapconn->hostnames);
- hostname = silc_dlist_get(mapconn->hostnames);
- snprintf(url, sizeof(url) - 1, "%s_%d.html", hostname, mapconn->port);
- }
-
- /* Print the positions of various items on the map into the map file */
- silc_dlist_start(mapconn->commands);
- while ((cmd = silc_dlist_get(mapconn->commands)) != SILC_LIST_END) {
- if (cmd->alon && cmd->alat) {
- cmd->x = silc_map_lon2x(map, cmd->alon);
- cmd->y = silc_map_lat2y(map, cmd->alat);
- }
-
- if (cmd->draw_text) {
- w = strlen(cmd->text) * 5;
- h = map->font.height - 2;
- fprintf(fp,
- "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
- (int)(cmd->x - xx), (int)(cmd->y - yy), w, h, url);
- }
-
- if (cmd->draw_circle) {
- w = 4;
- fprintf(fp,
- "<area shape=\"circle\" coords=\"%d,%d,%d\" href=\"%s\">\n",
- (int)(cmd->x - xx), (int)(cmd->y - yy), w, url);
- if (cmd->text) {
- w = strlen(cmd->text) * 5;
- h = map->font.height - 2;
- fprintf(fp,
- "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
- (int)(cmd->x - xx + cmd->lposx),
- (int)(cmd->y - yy - cmd->lposy),
- (int)(cmd->x - xx + cmd->lposx + w),
- (int)(cmd->y - yy - cmd->lposy + h), url);
- }
- }
-
- if (cmd->draw_rectangle) {
- w = 7;
- h = 6;
- fprintf(fp,
- "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
- (int)(cmd->x - xx), (int)(cmd->y - yy),
- (int)(cmd->x - xx + w), (int)(cmd->y - yy + h), url);
- if (cmd->text) {
- w = strlen(cmd->text) * 5;
- h = map->font.height - 2;
- fprintf(fp,
- "<area shape=\"rect\" coords=\"%d,%d,%d,%d\" href=\"%s\">\n",
- (int)(cmd->x - xx + cmd->lposx),
- (int)(cmd->y - yy - cmd->lposy),
- (int)(cmd->x - xx + cmd->lposx + w),
- (int)(cmd->y - yy - cmd->lposy + h), url);
- }
- }
- }
- }
-
- fprintf(fp, "</map>\n");
- fclose(fp);
- }
-
- return TRUE;
-}
-
-/* Writes the server uptime reliablity data file. */
-
-bool silc_map_writerel(SilcMap map, SilcMapConnection mapconn)
-{
- FILE *fp;
- int try = 0, success = 0;
- char f[256], *hostname;
-
- /* Generate data filename */
- memset(f, 0, sizeof(f));
- silc_dlist_start(mapconn->hostnames);
- hostname = silc_dlist_get(mapconn->hostnames);
- snprintf(f, sizeof(f) - 1, "%s_%d.rel", hostname, mapconn->port);
-
- /* Read the current data */
- fp = fopen(f, "r");
- if (fp) {
- fscanf(fp, "%d:%d", &try, &success);
- fclose(fp);
- }
-
- /* Update the data */
- try++;
- success = (mapconn->down == FALSE ? success + 1 : success);
-
- /* Write the data file */
- fp = fopen(f, "w+");
- if (!fp) {
- fprintf(stderr, "Could not open file '%s'\n", map->writerel.filename);
- return FALSE;
- }
- fprintf(fp, "%d:%d", try, success);
-
- fclose(fp);
- return TRUE;
-}
-
-/* Writes the servers' uptime reliability graph as HTML page. */
-
-bool silc_map_writerelhtml(SilcMap map)
-{
- SilcMapConnection mapconn;
- char *hostname, *class;
- FILE *fp, *dp;
-
- /* Open for writing */
- fp = fopen(map->writerel.filename, "w+");
- if (!fp) {
- fprintf(stderr, "Could not open file '%s'\n", map->writerel.filename);
- return FALSE;
- }
-
- /* Produce the reliability graph as HTML file. */
- class = map->writerel.text ? map->writerel.text : "silcmap";
-
- fprintf(fp, "<!-- Automatically generated by silcmap -->\n");
- fprintf(fp, "<br />\n");
- fprintf(fp, "<table cellspacing=\"0\" cellpadding=\"0\" "
- "class=\"%s\" border=\"0\">\n", class);
- fprintf(fp,
- "<tr>\n"
- "<td align=\"center\" class=\"%s_header\"><b>Server</b></td>\n"
- "<td colspan=\"2\" align=\"center\" class=\"%s_header\"><b>Reliability</b></td>\n"
- "</tr>\n", class, class);
-
- silc_dlist_start(map->conns);
- while ((mapconn = silc_dlist_get(map->conns)) != SILC_LIST_END) {
- char f[256];
- int try = 0, success = 0;
- double rel = 0;
-
- silc_dlist_start(mapconn->hostnames);
- hostname = silc_dlist_get(mapconn->hostnames);
-
- /* Get the data */
- memset(f, 0, sizeof(f));
- snprintf(f, sizeof(f) - 1, "%s_%d.rel", hostname, mapconn->port);
- dp = fopen(f, "r");
- if (dp) {
- fscanf(dp, "%d:%d", &try, &success);
- fclose(dp);
- }
-
- /* Count the reliability */
- if (try)
- rel = ((double)success / (double)try) * (double)160.0;
-
- fprintf(fp, "<tr>\n");
- if (mapconn->html_url)
- fprintf(fp,
- "<td align = \"center\" class=\"%s\"> <a href=\"%s\">%s</a></td>\n", class, mapconn->html_url, hostname);
- else
- fprintf(fp,
- "<td align = \"center\" class=\"%s\"> <a href=\"%s_%d.html\">%s</a></td>\n", class, hostname, mapconn->port, hostname);
- fprintf(fp,
- "<td class=\"%s\" width=\"160\">"
- "<table style=\"border: solid 1px black; width: 160px;\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"%s\"><tr>"
- "<td style=\"width: %fpx; height: 10px;\" bgcolor=\"gray\"></td>"
- "<td style=\"width: %fpx; height: 10px;\" bgcolor=\"white\"></td>"
- "</tr></table></td>\n"
- "<td class=\"%s\">%.2f%% - score: %d</td>\n"
- "</tr>\n",
- class, class, rel, 160 - rel, class,
- ((double)success / (double)try) * (double)100.0, success);
- }
-
- fprintf(fp, "</table><br />\n");
-
- return TRUE;
-}
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+# 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
-timestamp='2005-12-13'
+timestamp='2004-07-19'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
-
# Originally written by Per Bothner <per@bothner.com>.
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
+ echo "$timestamp" ; exit 0 ;;
--version | -v )
- echo "$version" ; exit ;;
+ echo "$version" ; exit 0 ;;
--help | --h* | -h )
- echo "$usage"; exit ;;
+ echo "$usage"; exit 0 ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
;;
,,*) CC_FOR_BUILD=$CC ;;
,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+esac ;'
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
- exit ;;
+ exit 0 ;;
+ amd64:OpenBSD:*:*)
+ echo x86_64-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ cats:OpenBSD:*:*)
+ echo arm-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ luna88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
*:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
- exit ;;
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
macppc:MirBSD:*:*)
echo powerppc-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit ;;
+ exit 0 ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
# of the specific Alpha model?
echo alpha-pc-interix
- exit ;;
+ exit 0 ;;
21064:Windows_NT:50:3)
echo alpha-dec-winnt3.5
- exit ;;
+ exit 0 ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-unknown-sysv4
- exit ;;
+ exit 0;;
*:[Aa]miga[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-amigaos
- exit ;;
+ exit 0 ;;
*:[Mm]orph[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-morphos
- exit ;;
+ exit 0 ;;
*:OS/390:*:*)
echo i370-ibm-openedition
- exit ;;
- *:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
+ exit 0 ;;
*:OS400:*:*)
echo powerpc-ibm-os400
- exit ;;
+ exit 0 ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
- exit ;;
- arm:riscos:*:*|arm:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
+ exit 0;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
echo hppa1.1-hitachi-hiuxmpp
- exit ;;
+ exit 0;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
if test "`(/bin/universe) 2>/dev/null`" = att ; then
else
echo pyramid-pyramid-bsd
fi
- exit ;;
+ exit 0 ;;
NILE*:*:*:dcosx)
echo pyramid-pyramid-svr4
- exit ;;
+ exit 0 ;;
DRS?6000:unix:4.0:6*)
echo sparc-icl-nx6
- exit ;;
- DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ exit 0 ;;
+ DRS?6000:UNIX_SV:4.2*:7*)
case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7; exit ;;
+ sparc) echo sparc-icl-nx7 && exit 0 ;;
esac ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
+ exit 0 ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
+ exit 0 ;;
i86pc:SunOS:5.*:*)
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
+ exit 0 ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
+ exit 0 ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
Series*|S4*)
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit ;;
+ exit 0 ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
echo sparc-sun-sunos${UNAME_RELEASE}
;;
esac
- exit ;;
+ exit 0 ;;
aushp:SunOS:*:*)
echo sparc-auspex-sunos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
RISC*:Mach:*:*)
echo mips-dec-mach_bsd4.3
- exit ;;
+ exit 0 ;;
RISC*:ULTRIX:*:*)
echo mips-dec-ultrix${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
VAX*:ULTRIX*:*:*)
echo vax-dec-ultrix${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
echo clipper-intergraph-clix${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
exit (-1);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c &&
- dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`$dummy $dummyarg` &&
- { echo "$SYSTEM_NAME"; exit; }
+ $CC_FOR_BUILD -o $dummy $dummy.c \
+ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && exit 0
echo mips-mips-riscos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
Motorola:PowerMAX_OS:*:*)
echo powerpc-motorola-powermax
- exit ;;
+ exit 0 ;;
Motorola:*:4.3:PL8-*)
echo powerpc-harris-powermax
- exit ;;
+ exit 0 ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
echo powerpc-harris-powermax
- exit ;;
+ exit 0 ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
- exit ;;
+ exit 0 ;;
m88k:CX/UX:7*:*)
echo m88k-harris-cxux7
- exit ;;
+ exit 0 ;;
m88k:*:4*:R4*)
echo m88k-motorola-sysv4
- exit ;;
+ exit 0 ;;
m88k:*:3*:R3*)
echo m88k-motorola-sysv3
- exit ;;
+ exit 0 ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
- exit ;;
+ exit 0 ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
- exit ;;
+ exit 0 ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
echo m88k-motorola-sysv3
- exit ;;
+ exit 0 ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
echo m88k-tektronix-sysv3
- exit ;;
+ exit 0 ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
echo m68k-tektronix-bsd
- exit ;;
+ exit 0 ;;
*:IRIX*:*:*)
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit ;;
+ exit 0 ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
- exit ;;
+ exit 0 ;;
ia64:AIX:*:*)
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
- exit ;;
+ exit 0 ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
eval $set_cc_for_build
exit(0);
}
EOF
- if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
- then
- echo "$SYSTEM_NAME"
- else
- echo rs6000-ibm-aix3.2.5
- fi
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ echo rs6000-ibm-aix3.2.5
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
else
echo rs6000-ibm-aix3.2
fi
- exit ;;
+ exit 0 ;;
*:AIX:*:[45])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit ;;
+ exit 0 ;;
*:AIX:*:*)
echo rs6000-ibm-aix
- exit ;;
+ exit 0 ;;
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
echo romp-ibm-bsd4.4
- exit ;;
+ exit 0 ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
+ exit 0 ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
- exit ;;
+ exit 0 ;;
DPX/2?00:B.O.S.:*:*)
echo m68k-bull-sysv3
- exit ;;
+ exit 0 ;;
9000/[34]??:4.3bsd:1.*:*)
echo m68k-hp-bsd
- exit ;;
+ exit 0 ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
echo m68k-hp-bsd4.4
- exit ;;
+ exit 0 ;;
9000/[34678]??:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
case "${UNAME_MACHINE}" in
esac
if [ ${HP_ARCH} = "hppa2.0w" ]
then
- eval $set_cc_for_build
-
- # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
- # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
- # generating 64-bit code. GNU and HP use different nomenclature:
- #
- # $ CC_FOR_BUILD=cc ./config.guess
- # => hppa2.0w-hp-hpux11.23
- # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
- # => hppa64-hp-hpux11.23
-
- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
- grep __LP64__ >/dev/null
+ # avoid double evaluation of $set_cc_for_build
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
then
HP_ARCH="hppa2.0w"
else
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit ;;
+ exit 0 ;;
ia64:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
echo ia64-hp-hpux${HPUX_REV}
- exit ;;
+ exit 0 ;;
3050*:HI-UX:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
exit (0);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
+ $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
echo unknown-hitachi-hiuxwe2
- exit ;;
+ exit 0 ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
echo hppa1.1-hp-bsd
- exit ;;
+ exit 0 ;;
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
- exit ;;
+ exit 0 ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
echo hppa1.0-hp-mpeix
- exit ;;
+ exit 0 ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
echo hppa1.1-hp-osf
- exit ;;
+ exit 0 ;;
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
- exit ;;
+ exit 0 ;;
i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
echo ${UNAME_MACHINE}-unknown-osf1mk
else
echo ${UNAME_MACHINE}-unknown-osf1
fi
- exit ;;
+ exit 0 ;;
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
- exit ;;
+ exit 0 ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
- exit ;;
+ exit 0 ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit ;;
+ exit 0 ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
- exit ;;
+ exit 0 ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
- exit ;;
+ exit 0 ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
- exit ;;
+ exit 0 ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ exit 0 ;;
CRAY*[A-Z]90:*:*:*)
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
-e 's/\.[^.]*$/.X/'
- exit ;;
+ exit 0 ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ exit 0 ;;
CRAY*T3E:*:*:*)
echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ exit 0 ;;
CRAY*SV1:*:*:*)
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ exit 0 ;;
*:UNICOS/mp:*:*)
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ exit 0 ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ exit 0 ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ exit 0 ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
sparc*:BSD/OS:*:*)
echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:FreeBSD:*:*)
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit ;;
+ exit 0 ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
- exit ;;
+ exit 0 ;;
i*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
- exit ;;
- i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
- exit ;;
+ exit 0 ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
- exit ;;
- x86:Interix*:[345]*)
+ exit 0 ;;
+ x86:Interix*:[34]*)
echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
- exit ;;
+ exit 0 ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
- exit ;;
+ exit 0 ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
# UNAME_MACHINE based on the output of uname instead of i386?
echo i586-pc-interix
- exit ;;
+ exit 0 ;;
i*:UWIN*:*)
echo ${UNAME_MACHINE}-pc-uwin
- exit ;;
- amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
- exit ;;
+ exit 0 ;;
p*:CYGWIN*:*)
echo powerpcle-unknown-cygwin
- exit ;;
+ exit 0 ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
+ exit 0 ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit ;;
+ exit 0 ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
- exit ;;
+ exit 0 ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
- exit ;;
+ exit 0 ;;
arm*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
cris:Linux:*:*)
echo cris-axis-linux-gnu
- exit ;;
- crisv32:Linux:*:*)
- echo crisv32-axis-linux-gnu
- exit ;;
- frv:Linux:*:*)
- echo frv-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
mips:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^CPU/{s: ::g;p;}'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
;;
mips64:Linux:*:*)
eval $set_cc_for_build
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^CPU/{s: ::g;p;}'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+ test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
;;
- or32:Linux:*:*)
- echo or32-unknown-linux-gnu
- exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
- exit ;;
+ exit 0 ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
PA8*) echo hppa2.0-unknown-linux-gnu ;;
*) echo hppa-unknown-linux-gnu ;;
esac
- exit ;;
+ exit 0 ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
- exit ;;
+ exit 0 ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-gnu
- exit ;;
+ exit 0 ;;
x86_64:Linux:*:*)
echo x86_64-unknown-linux-gnu
- exit ;;
+ exit 0 ;;
i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us. cd to the root directory to prevent
;;
a.out-i386-linux)
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit ;;
+ exit 0 ;;
coff-i386)
echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit ;;
+ exit 0 ;;
"")
# Either a pre-BFD a.out linker (linux-gnuoldld) or
# one that does not give us useful --help.
echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit ;;
+ exit 0 ;;
esac
# Determine whether the default compiler is a.out or elf
eval $set_cc_for_build
LIBC=gnulibc1
# endif
#else
- #if defined(__INTEL_COMPILER) || defined(__PGI)
+ #ifdef __INTEL_COMPILER
LIBC=gnu
#else
LIBC=gnuaout
LIBC=dietlibc
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^LIBC/{s: ::g;p;}'`"
- test x"${LIBC}" != x && {
- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
- exit
- }
- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+ test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
echo i386-sequent-sysv4
- exit ;;
+ exit 0 ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit ;;
+ exit 0 ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
echo ${UNAME_MACHINE}-pc-os2-emx
- exit ;;
+ exit 0 ;;
i*86:XTS-300:*:STOP)
echo ${UNAME_MACHINE}-unknown-stop
- exit ;;
+ exit 0 ;;
i*86:atheos:*:*)
echo ${UNAME_MACHINE}-unknown-atheos
- exit ;;
- i*86:syllable:*:*)
+ exit 0 ;;
+ i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
- exit ;;
+ exit 0 ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
i*86:*DOS:*:*)
echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit ;;
+ exit 0 ;;
i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
else
echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
fi
- exit ;;
- i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ exit 0 ;;
+ i*86:*:5:[78]*)
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
- exit ;;
+ exit 0 ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
else
echo ${UNAME_MACHINE}-pc-sysv32
fi
- exit ;;
+ exit 0 ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i386.
echo i386-pc-msdosdjgpp
- exit ;;
+ exit 0 ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
- exit ;;
+ exit 0 ;;
paragon:*:*:*)
echo i860-intel-osf1
- exit ;;
+ exit 0 ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
fi
- exit ;;
+ exit 0 ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
echo m68010-convergent-sysv
- exit ;;
+ exit 0 ;;
mc68k:UNIX:SYSTEM5:3.51m)
echo m68k-convergent-sysv
- exit ;;
+ exit 0 ;;
M680?0:D-NIX:5.3:*)
echo m68k-diab-dnix
- exit ;;
+ exit 0 ;;
M68*:*:R3V[5678]*:*)
- test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
+ && echo i486-ncr-sysv4 && exit 0 ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
- exit ;;
+ exit 0 ;;
TSUNAMI:LynxOS:2.*:*)
echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
SM[BE]S:UNIX_SV:*:*)
echo mips-dde-sysv${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
RM*:ReliantUNIX-*:*:*)
echo mips-sni-sysv4
- exit ;;
+ exit 0 ;;
RM*:SINIX-*:*:*)
echo mips-sni-sysv4
- exit ;;
+ exit 0 ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
else
echo ns32k-sni-sysv
fi
- exit ;;
+ exit 0 ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
echo i586-unisys-sysv4
- exit ;;
+ exit 0 ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
echo hppa1.1-stratus-sysv4
- exit ;;
+ exit 0 ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
echo i860-stratus-sysv4
- exit ;;
- i*86:VOS:*:*)
- # From Paul.Green@stratus.com.
- echo ${UNAME_MACHINE}-stratus-vos
- exit ;;
+ exit 0 ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
echo hppa1.1-stratus-vos
- exit ;;
+ exit 0 ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
news*:NEWS-OS:6*:*)
echo mips-sony-newsos6
- exit ;;
+ exit 0 ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
- exit ;;
+ exit 0 ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
- exit ;;
+ exit 0 ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
echo powerpc-apple-beos
- exit ;;
+ exit 0 ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
- exit ;;
+ exit 0 ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
SX-5:SUPER-UX:*:*)
echo sx5-nec-superux${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
SX-6:SUPER-UX:*:*)
echo sx6-nec-superux${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:Rhapsody:*:*)
echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- case $UNAME_PROCESSOR in
- unknown) UNAME_PROCESSOR=powerpc ;;
+ case `uname -p` in
+ *86) UNAME_PROCESSOR=i686 ;;
+ powerpc) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = "x86"; then
UNAME_MACHINE=pc
fi
echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:QNX:*:4*)
echo i386-pc-qnx
- exit ;;
- NSE-?:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
- exit ;;
+ exit 0 ;;
BS2000:POSIX*:*:*)
echo bs2000-siemens-sysv
- exit ;;
+ exit 0 ;;
DS/*:UNIX_System_V:*:*)
echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
UNAME_MACHINE="$cputype"
fi
echo ${UNAME_MACHINE}-unknown-plan9
- exit ;;
+ exit 0 ;;
*:TOPS-10:*:*)
echo pdp10-unknown-tops10
- exit ;;
+ exit 0 ;;
*:TENEX:*:*)
echo pdp10-unknown-tenex
- exit ;;
+ exit 0 ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
echo pdp10-dec-tops20
- exit ;;
+ exit 0 ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
echo pdp10-xkl-tops20
- exit ;;
+ exit 0 ;;
*:TOPS-20:*:*)
echo pdp10-unknown-tops20
- exit ;;
+ exit 0 ;;
*:ITS:*:*)
echo pdp10-unknown-its
- exit ;;
+ exit 0 ;;
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
- exit ;;
+ exit 0 ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit ;;
+ exit 0 ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
case "${UNAME_MACHINE}" in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
- esac ;;
- *:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
- i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
- exit ;;
- i*86:rdos:*:*)
- echo ${UNAME_MACHINE}-pc-rdos
- exit ;;
+ A*) echo alpha-dec-vms && exit 0 ;;
+ I*) echo ia64-dec-vms && exit 0 ;;
+ V*) echo vax-dec-vms && exit 0 ;;
+ esac
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
#endif
#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix\n"); exit (0);
+ printf ("arm-acorn-riscix"); exit (0);
#endif
#if defined (hp300) && !defined (hpux)
}
EOF
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
# Apollos put the system type in the environment.
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
# Convex versions that predate uname can use getsysinfo(1)
case `getsysinfo -f cpu_type` in
c1*)
echo c1-convex-bsd
- exit ;;
+ exit 0 ;;
c2*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit ;;
+ exit 0 ;;
c34*)
echo c34-convex-bsd
- exit ;;
+ exit 0 ;;
c38*)
echo c38-convex-bsd
- exit ;;
+ exit 0 ;;
c4*)
echo c4-convex-bsd
- exit ;;
+ exit 0 ;;
esac
fi
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
-and
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+ ftp://ftp.gnu.org/pub/gnu/config/
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+# 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
-timestamp='2005-12-11'
+timestamp='2004-06-24'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
-#
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
-
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
#
version="\
GNU config.sub ($timestamp)
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
+ echo "$timestamp" ; exit 0 ;;
--version | -v )
- echo "$version" ; exit ;;
+ echo "$version" ; exit 0 ;;
--help | --h* | -h )
- echo "$usage"; exit ;;
+ echo "$usage"; exit 0 ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
*local*)
# First pass through any local machine types.
echo $1
- exit ;;
+ exit 0;;
* )
break ;;
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
-hiux*)
os=-hiuxwe2
;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
-sco5)
os=-sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
-sco*)
os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
- | bfin \
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
| fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
- | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+ | m32r | m32rle | m68000 | m68k | m88k | mcore \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
- | mt \
| msp430 \
| ns16k | ns32k \
- | or32 \
+ | openrisc | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
- | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b \
+ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \
| strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \
| we32k \
- | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | x86 | xscale | xstormy16 | xtensa \
| z8k)
basic_machine=$basic_machine-unknown
;;
- m32c)
- basic_machine=$basic_machine-unknown
- ;;
m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
basic_machine=$basic_machine-unknown
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
- ms1)
- basic_machine=mt-unknown
- ;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* \
- | bfin-* | bs2000-* \
+ | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| ip2k-* | iq2000-* \
| m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* \
+ | m88110-* | m88k-* | mcore-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
- | mt-* \
| msp430-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| orion-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
- | sparclite-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tron-* \
| v850-* | v850e-* | vax-* \
| we32k-* \
- | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
- | xstormy16-* | xtensa-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+ | xtensa-* \
| ymp-* \
| z8k-*)
;;
- m32c-*)
- ;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
386bsd)
crds | unos)
basic_machine=m68k-crds
;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
basic_machine=m88k-motorola
os=-sysv3
;;
- djgpp)
- basic_machine=i586-pc
- os=-msdosdjgpp
- ;;
dpx20 | dpx20-*)
basic_machine=rs6000-bull
os=-bosx
basic_machine=i386-pc
os=-msdos
;;
- ms1-*)
- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
- ;;
mvs)
basic_machine=i370-ibm
os=-mvs
basic_machine=hppa1.1-oki
os=-proelf
;;
- openrisc | openrisc-*)
+ or32 | or32-*)
basic_machine=or32-unknown
+ os=-coff
;;
os400)
basic_machine=powerpc-ibm
basic_machine=i586-unknown
os=-pw32
;;
- rdos)
- basic_machine=i386-pc
- os=-rdos
- ;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
basic_machine=hppa1.1-winbond
os=-proelf
;;
- xbox)
- basic_machine=i686-pc
- os=-mingw32
- ;;
xps | xps100)
basic_machine=xps100-honeywell
;;
we32k)
basic_machine=we32k-att
;;
- sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
sparc | sparcv8 | sparcv9 | sparcv9b)
basic_machine=sparc-sun
;;
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos*)
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;;
-mac*)
-kaos*)
os=-kaos
;;
- -zvmoe)
- os=-zvmoe
- ;;
-none)
;;
*)
*-be)
os=-beos
;;
- *-haiku)
- os=-haiku
- ;;
*-ibm)
os=-aix
;;
esac
echo $basic_machine$os
-exit
+exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2000 - 2007 Pekka Riikonen
-s#
+# 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
# the Free Software Foundation; version 2 of the License.
*-*-freebsd*)
check_threads=true
;;
- *-*-netbsd*)
- check_threads=true
- ;;
*-*-*bsd*)
check_threads=false
;;
;;
esac
-# Get CPU
-cpu_i386=false
-cpu_ix86=false
-cpu_x86_64=false
-cpu_ppc=false
-cpu_ia64=false
-case "$host_cpu" in
- i386)
- AC_DEFINE([SILC_I386], [], [SILC_I386])
- AC_DEFINE([SILC_I486], [], [SILC_I486])
- cpu_i386=true
- cpu_ix86=true
- ;;
- i?86)
- AC_DEFINE([SILC_I486], [], [SILC_I486])
- cpu_ix86=true
- ;;
- x86_64)
- AC_DEFINE([SILC_X86_64], [], [SILC_X86_64])
- cpu_x86_64=true
- ;;
- powerpc*)
- AC_DEFINE([SILC_POWERPC], [], [SILC_POWERPC])
- cpu_ppc=true
- ;;
- ia64)
- AC_DEFINE([SILC_IA64], [], [SILC_IA64])
- cpu_ia64=true
- ;;
-esac
-AM_CONDITIONAL(SILC_I386, test x$cpu_i386 = xtrue)
-AM_CONDITIONAL(SILC_I486, test x$cpu_ix86 = xtrue)
-AM_CONDITIONAL(SILC_X86_64, test x$cpu_x86_64 = xtrue)
-AM_CONDITIONAL(SILC_POWERPC, test x$cpu_ppc = xtrue)
-AM_CONDITIONAL(SILC_IA64, test x$cpu_ia64 = xtrue)
-
# Control compiler optimizations
CFLAGS=`echo $CFLAGS | sed 's/-O[ 0123456789s]*//g'`
#ifndef SILC_DIST_TOOLKIT
AC_DISABLE_SHARED
#endif SILC_DIST_TOOLKIT
-#ifdef SILC_DIST_INPLACE
-AC_DISABLE_SHARED
-#endif SILC_DIST_INPLACE
AC_PROG_LIBTOOL
# Header checking
AC_SUBST(SILC_SIZEOF_CHAR, $ac_cv_sizeof_char)
AC_CHECK_SIZEOF(void *, 0)
AC_SUBST(SILC_SIZEOF_VOID_P, $ac_cv_sizeof_void_p)
-AC_CHECK_TYPES(long long)
-AC_CHECK_TYPES(long double)
-
-# Function to check if compiler flag works
-# Usage: SILC_ADD_CFLAGS(FLAGS, [ACTION-IF-FAILED])
-AC_DEFUN([SILC_ADD_CFLAGS],
-[ tmp_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $1"
- AC_MSG_CHECKING(whether $CC accepts $1 flag)
- AC_TRY_LINK([], [], [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)
- CFLAGS="$tmp_CFLAGS"
- $2])
- unset tmp_CFLAGS
-])
-
-# Function to check if compiler flag works, destination specifiable
-# Usage: SILC_ADD_CC_FLAGS(VAR, FLAGS, [ACTION-IF-FAILED])
-AC_DEFUN([SILC_ADD_CC_FLAGS],
-[ tmp_CFLAGS="$1_CFLAGS"
- $1_CFLAGS="${$1_CFLAGS} $2"
- AC_MSG_CHECKING(whether $CC accepts $2 flag)
- AC_TRY_LINK([], [], [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)
- $1_CFLAGS="$tmp_CFLAGS"
- $3])
- unset tmp_CFLAGS
-])
# Function and library checking
#
AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
)
AC_CHECK_FUNCS(gethostname gethostbyaddr getservbyname getservbyport)
-AC_CHECK_FUNCS(poll select listen bind shutdown close connect setsockopt)
-AC_CHECK_FUNCS(setrlimit time ctime utime gettimeofday getrusage)
+AC_CHECK_FUNCS(select listen bind shutdown close connect setsockopt)
+AC_CHECK_FUNCS(time ctime utime gettimeofday getrusage)
AC_CHECK_FUNCS(chmod fcntl stat fstat getenv putenv strerror)
AC_CHECK_FUNCS(getpid getgid getsid getpgid getpgrp getuid)
-AC_CHECK_FUNCS(setgroups initgroups nl_langinfo nanosleep tzset)
-AC_CHECK_FUNCS(strchr snprintf strstr strcpy strncpy memcpy memset memmove)
+AC_CHECK_FUNCS(setgroups initgroups nl_langinfo)
+AC_CHECK_FUNCS(strchr strstr strcpy strncpy memcpy memset memmove)
#ifdef SILC_DIST_SIM
# SIM support checking
[ --disable-asm do not use assembler optimizations],
[
AC_MSG_RESULT(no)
- AC_DEFINE([SILC_NO_ASM], [], [SILC_NO_ASM])
want_asm=false
],
[
AC_MSG_RESULT(yes)
want_asm=true
])
-AM_CONDITIONAL(SILC_NO_ASM, test x$want_asm = xfalse)
-
-# Check for assembler
-#
-SILC_ASSEMBLER=""
-have_assembler=false
-if test x$want_asm = xtrue; then
- AC_PATH_PROG([NASM], [nasm], [no])
- if test "x$NASM" != "xno"; then
- SILC_ASSEMBLER="$NASM -O2 -felf"
- have_assembler=true
- fi
-
- AC_PATH_PROG([YASM], [yasm], [no])
- if test "x$YASM" != "xno"; then
- SILC_ASSEMBLER="$YASM -Xgnu -felf"
- have_assembler=true
- fi
-fi
-AC_SUBST(SILC_ASSEMBLER)
##
-## va_copy checks
+## Compiler and compiler flag checks
##
-va_copy=false
-AC_MSG_CHECKING(for va_copy)
-AC_TRY_COMPILE(
- [
- #include <stdarg.h>
- #include <stdlib.h>
- ],
- [
- int t(int x, ...)
- {
- va_list va, cp;
- va_start(va, x);
- va_copy(cp, va);
- if (va_arg(cp, int) != 0xff11)
- return 1;
- va_end(va);
- va_end(cp);
- return 0;
- }
- int main()
- {
- return t(0, 0xff11);
- }
- ],
- [
- AC_DEFINE([HAVE_VA_COPY], [], [HAVE_VA_COPY])
- AC_MSG_RESULT(yes)
- va_copy=true
- ],
- [
- AC_MSG_RESULT(no)
- va_copy=false
- ]
-)
-if test x$va_copy = xfalse; then
- AC_MSG_CHECKING(for __va_copy)
- AC_TRY_COMPILE(
- [
- #include <stdarg.h>
- #include <stdlib.h>
- ],
- [
- int t(int x, ...)
- {
- va_list va, cp;
- va_start(va, x);
- __va_copy(cp, va);
- if (va_arg(cp, int) != 0xff11)
- return 1;
- va_end(va);
- va_end(cp);
- return 0;
- }
- int main()
- {
- return t(0, 0xff11);
- }
- ],
- [
- AC_DEFINE([HAVE___VA_COPY], [], [HAVE___VA_COPY])
- AC_MSG_RESULT(yes)
- va_copy=true
- ],
- [
- AC_MSG_RESULT(no)
- va_copy=false
- ]
- )
-fi
-
-if test x$va_copy = xfalse; then
- AC_RUN_IFELSE(
- [
- #include <stdarg.h>
- #include <stdlib.h>
- int t(int x, ...)
- {
- va_list va, cp;
- va_start(va, x);
- cp = va;
- if (va_arg(cp, int) != 0xff11)
- return 1;
- va_end(va);
- va_end(cp);
- return 0;
- }
- int main()
- {
- return t(0, 0xff11);
- }
- ],
- [va_copy=false],
- [
- AC_DEFINE([SILC_VA_COPY_ARRAY], [], [SILC_VA_COPY_ARRAY])
- ],
- [va=copy=false]
- )
-fi
+# Function to check if compiler flag works
+# Usage: SILC_ADD_CFLAGS(FLAGS, [ACTION-IF-FAILED])
+AC_DEFUN([SILC_ADD_CFLAGS],
+[ tmp_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ AC_MSG_CHECKING(whether $CC accepts $1 flag)
+ AC_TRY_LINK([], [], [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)
+ CFLAGS="$tmp_CFLAGS"
+ $2])
+ unset tmp_CFLAGS
+])
-##
-## Compiler and compiler flag checks
-##
+# Function to check if compiler flag works, destination specifiable
+# Usage: SILC_ADD_CC_FLAGS(VAR, FLAGS, [ACTION-IF-FAILED])
+AC_DEFUN([SILC_ADD_CC_FLAGS],
+[ tmp_CFLAGS="$1_CFLAGS"
+ $1_CFLAGS="${$1_CFLAGS} $2"
+ AC_MSG_CHECKING(whether $CC accepts $2 flag)
+ AC_TRY_LINK([], [], [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)
+ $1_CFLAGS="$tmp_CFLAGS"
+ $3])
+ unset tmp_CFLAGS
+])
if test "$GCC"; then
# GCC specific options
fi
# Check libs to link against
- f=`$EGREP __SILC_HAVE_PTHREAD $ac_silc_includes/silc.h`
+ f=`$EGREP __SILC_HAVE_PTHREAD $ac_silc_includes/silcincludes.h`
if test -n "$f"; then
LIBS="$LIBS -lpthread"
check_threads=false
has_threads=true
fi
- f=`$EGREP __SILC_HAVE_SIM $ac_silc_includes/silc.h`
+ f=`$EGREP __SILC_HAVE_SIM $ac_silc_includes/silcincludes.h`
if test -n "$f"; then
LIBS="$LIBS -ldl"
fi
#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=
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
AM_CONDITIONAL(SILC_MP_GMP, test x$mp_gmp = xtrue)
AM_CONDITIONAL(SILC_MP_SILCMATH, test x$mp_gmp = xfalse)
if test x$mp_gmp = xfalse; then
- AC_DEFINE([SILC_MP_SILCMATH], [], [SILCMATH])
+ AC_DEFINE([SILC_MP_SILCMAP], [], [SILCMATH])
AC_MSG_RESULT(Using SILC Math as a MP library.)
fi
#endif SILC_DIST_MATH
;;
esac
- # Check for threads
AC_CHECK_FUNC(pthread_create)
-
- # Check for read/write locks
- AC_CHECK_FUNC(pthread_rwlock_init,
- [
- AC_RUN_IFELSE(
- [
- #include <pthread.h>
- int main()
- {
- pthread_rwlock_t rwlock;
- pthread_rwlock_init(&rwlock, NULL);
- pthread_rwlock_destroy(&rwlock);
- return 0;
- }
- ],
- [],
- [
- # Rwlock not defined
- CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600"
- ]
- )
- ],
- [
- # Rwlock not defined
- CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600"
- ])
-
AC_DEFINE([SILC_HAVE_PTHREAD], [], [HAVE_PTHREAD])
AC_DEFINE([SILC_THREADS], [], [HAVE_THREAD])
__SILC_HAVE_PTHREAD="#define __SILC_HAVE_PTHREAD 1"
])
AM_CONDITIONAL(SILC_WIN32, test x$win32_support = xtrue)
-# Native Symbian OS support (disabled by default)
+# Native EPOC support (disabled by default)
#
-AM_CONDITIONAL(SILC_SYMBIAN, test xfalse = xtrue)
+AM_CONDITIONAL(SILC_EPOC, test xfalse = xtrue)
# Native BeOS support (disabled by default)
#
#
AM_CONDITIONAL(SILC_OS2, test xfalse = xtrue)
-#ifdef SILC_DIST_SERVER
-without_silcd=false
-#endif SILC_DIST_SERVER
+# Make enable-shared aware
+AM_CONDITIONAL(SILC_ENABLE_SHARED, test "$enable_shared" = yes)
+
+#ifdef SILC_DIST_TOOLKIT
+# --with-irssi
+#
+without_irssi=true
+AC_MSG_CHECKING(whether to compile Irssi SILC Client)
+AC_ARG_WITH(irssi,
+ [ --with-irssi compile with Irssi SILC Client],
+ [
+ AC_MSG_RESULT(yes)
+ without_irssi=false
+ ],
+ [
+ AC_MSG_RESULT(no)
+ without_irssi=true
+ ])
+AM_CONDITIONAL(with_irssi, test xwithout_irssi = xfalse)
+
+# --with-silcd
+#
+without_silcd=true
+AC_MSG_CHECKING(whether to compile SILC Server)
+AC_ARG_WITH(silcd,
+ [ --with-silcd compile with SILC Server],
+ [
+ AC_MSG_RESULT(yes)
+ without_silcd=false
+ ],
+ [
+ AC_MSG_RESULT(no)
+ without_silcd=true
+ ])
+#endif SILC_DIST_TOOLKIT
#ifdef SILC_DIST_CLIENT
AM_CONDITIONAL(with_irssi, true)
-#endif SILC_DIST_CLIENT
+#endif
#ifdef SILC_DIST_INPLACE
without_irssi=false
without_silcd=false
## Misc
##
-# Make enable-shared aware
-AM_CONDITIONAL(SILC_ENABLE_SHARED, test "$enable_shared" = yes)
-
SILC_TOP_SRCDIR=`pwd`
# Included configure scripts
Makefile.defines_int
includes/Makefile
includes/silcversion.h
-includes/silc.h
+includes/silcincludes.h
#endif SILC_DIST_COMPILER
#ifdef SILC_DIST_APPS
apps/Makefile
#endif SILC_DIST_INCLUDES
echo ""
-#ifdef SILC_DIST_CLIENT
+#ifdef SILC_DIST_TOOLKIT
if test x$without_irssi = xtrue; then
irssi="no"
fi
+if test x$without_silcd = xtrue; then
+ silcd="no"
+fi
+#endif SILC_DIST_TOOLKIT
+
+#ifdef SILC_DIST_CLIENT
echo " Compile SILC Client ...........: $irssi"
#endif SILC_DIST_CLIENT
#ifdef SILC_DIST_SERVER
-if test x$without_silcd = xtrue; then
- silcd="no"
-fi
echo " Compile SILC Server ...........: $silcd"
#endif SILC_DIST_SERVER
# Location of the make program. This must be specified in order to be
# able to create distributions.
#
-MAKE="make"
+MAKE="gmake"
define SILC_DIST_SIM
define SILC_DIST_SFTP
define SILC_DIST_COMPILER
-define SILC_DIST_IDCACHE
-define SILC_DIST_VCARD
-define SILC_DIST_CRYPTO
# Math library, define only TMA or TFM, not both.
define SILC_DIST_MATH
define SILC_DIST_TMA
#define SILC_DIST_TFM
-
-# ASN.1 library
-define SILC_DIST_ASN1
-
-# Key Repository library
-define SILC_DIST_SKR
# Default distribution for preparing raw CVS sources.
inherit common
inherit client
-#inherit server
+inherit server
inherit toolkit
define SILC_DIST_INPLACE
# in EXTRA_DIST or 'include' them in distribution.
if test -d $distdir; then
- rm -rf `find $distdir -name CVS`
- rm -rf `find $distdir -name Makefile`
+ find $distdir -name CVS -type d | xargs rm -rf
+ find $distdir -name Makefile -type f | xargs rm -f
fi
ln -fs ../../Makefile.defines.in Makefile.defines.in
ln -fs ../../Makefile.defines_int.in Makefile.defines_int.in
sh autogen.sh 2>/dev/null 1>/dev/null
-sed '/#undef PACKAGE_/d' config.h.in > config.h.in.tmp
-sed '/#undef PACKAGE/d' config.h.in.tmp > config.h.in
cd $cur
version_date=`date +%Y%m%d`
echo "/* automatically created by autogen.sh */" > $file
inherit common
define SILC_DIST_SERVER
-define SILC_DIST_SERVERLIB
-define SILC_DIST_HTTP
undef SILC_DIST_SFTP
post-process-dist-hook distdir/post-process-dist
+++ /dev/null
-name Map
-package silc-map
-bug-report silc-devel@lists.silcnet.org
-
-inherit common
-define SILC_DIST_SILCMAP
-define SILC_DIST_CLIENTLIB
-define SILC_DIST_APPS
-undef SILC_DIST_LIB
-undef SILC_DIST_DOC
-undef SILC_DIST_SIM
-undef SILC_DIST_MATH
-undef SILC_DIST_MPI
-
-include apps/silcmap/README README
-include apps/autodist/AUTHORS AUTHORS
-include apps/autodist/CHANGES CHANGES
-exclude README.* TODO CREDITS
-
-post-process-dist-hook distdir/post-process-dist
-post-dist-hook distdir/post-dist
# Inherits
inherit common
+inherit client
+inherit server
# License
license distdir/TOOLKIT
# Distdefs
define SILC_DIST_TOOLKIT
-define SILC_DIST_CLIENTLIB
-define SILC_DIST_HTTP
+# SFTP is undefined in server, so force it here
+define SILC_DIST_SFTP
# Includes
include README.CVS
include README.WIN32
include README.MACOSX
include apps/silcer
+include apps/silc
include tutorial
# Noprocess to optimize packaging and avoid re-licensing of certain files
noprocess doc/toolkit/
noprocess apps/
noprocess win32/
-noprocess symbian/
pre-hook distdir/pre-run
post-process-dist-hook distdir/post-process-dist
Generic naming
-All identifiers, whether they are defines, functions or something else, with
+All identifiers, whether they defines, functions or something else, with
exception of variables, has a common naming convention. Usually all
identifiers use `silc' prefix to indicate that the identifier is part of
SILC distribution. For example, silc_server_init(), SILC_PACKET_TYPE_ERROR,
rarely used in the SILC, instead structures are typedef'd as following
later. When structure is used as object they are defined as follows,
- typedef struct SilcDummyObject {
+ typedef struct SilcDummyStruct {
unsigned char *dummy;
unsigned int flags;
void (*callback)(void *, unsigned int);
- } SilcDummyStruct;
+ } SilcDummyObject;
-If the SilcDummyObject is not needed it may be omitted (which is very
+If the SilcDummyStruct is not needed it may be omitted (which is very
common in SILC code), leaving,
typedef struct {
unsigned char *dummy;
unsigned int flags;
void (*callback)(void *, unsigned int);
- } SilcDummyStruct;
+ } SilcDummyObject;
Finally, it is common that structures are typedef'd pointers as they
are very flexible to use,
- typedef SilcDummyStruct *SilcDummy;
-
-or,
-
- typedef struct {
- unsigned char *dummy;
- unsigned int flags;
- void (*callback)(void *, unsigned int);
- } SilcDummyStruct, *SilcDummy;
+ typedef SilcDummyObject *SilcDummy;
It is common in SILC to typedef structures instead of defining name
for the structure. In this case the structure may be used without
defining `struct' to the code, For example,
- SilcDummyStruct dummy_obj;
- SilcDummyStruct *dummy;
+ SilcDummyObject dummy_obj;
+ SilcDummyObject *dummy;
If the structure has a pointer typedef then they are defined as normal
variables but for real they are pointers, For example,
header files. Inline functions must be defined in following manner
in the header file,
-static inline void silc_dummy_inline(unsigned int flags)
+extern inline void silc_dummy_inline(unsigned int flags)
{
doing_little_dummy_things;
}
+Because the function is defined as extern they can be included into
+public header files. Do not forget to define inline function as extern.
+There are no explicit prototype definitions for inline functions.
+
Indentation
===========
too long to type, consider using dynamic abbreviation found in Emacs.
With this cool feature you only have type some part of the string and
then use the dabbrev to find the rest of the string. I guess, by
-default it is M-/ in Emacs but I have bound it into Shift-TAB so it
+default it is M-/ in Emacs but I have binded it into Shift-TAB so it
is fast to use when typing.
something_else;
}
- if (condition)
- oneline_no_braces;
-
Commenting
==========
`==', `+', etc. Also, when setting a value to variable be
sure to set spaces around `='. When writing argument list
to a function, space should follow each of the comma in the
- list. However, do not use spaces within parenthesis, for
+ list. However, do not use spaces with parenthesis, for
example, `if ( !k )' is not accepted.
o If you are not sure about how something should be done or
all source files.
In the start of the source files should include the #include's that are
-needed. All library source files must include `silc.h', this is
-a must. Client source file must include at least `silcclient.h' and
-server source file must include `silcserver.h'. Additional include's
+needed. All library source files must include `silcincludes.h', this is
+a must. Client source file must include at least `clientincludes.h' and
+server source file must include `serverincludes.h'. Additional include's
may be added as well, however, system specific includes should not be
added directly (unless it is really a special case). Go see any source
file as an example.
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2000 - 2007 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
AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
all:
- touch draft-riikonen-silc-spec-09.txt
+ touch draft-riikonen-silc-spec-08.txt
touch draft-riikonen-silc-pp-09.txt
- touch draft-riikonen-silc-ke-auth-09.txt
- touch draft-riikonen-silc-commands-07.txt
+ touch draft-riikonen-silc-ke-auth-08.txt
+ touch draft-riikonen-silc-commands-06.txt
touch draft-riikonen-silc-flags-payloads-04.txt
- touch draft-riikonen-silc-multimedia-session-00.txt
- touch draft-riikonen-presence-attrs-04.txt
+ touch draft-riikonen-presence-attrs-03.txt
#ifdef SILC_DIST_TOOLKIT
makerfc = $(SILC_TOP_SRCDIR)/scripts/makerfc
dist-hook:
$(SILC_TOP_SRCDIR)/scripts/manpages.pl
- touch draft-riikonen-silc-spec-09.txt
+ touch draft-riikonen-silc-spec-08.txt
touch draft-riikonen-silc-pp-09.txt
- touch draft-riikonen-silc-ke-auth-09.txt
- touch draft-riikonen-silc-commands-07.txt
+ touch draft-riikonen-silc-ke-auth-08.txt
+ touch draft-riikonen-silc-commands-06.txt
touch draft-riikonen-silc-flags-payloads-04.txt
- touch draft-riikonen-silc-multimedia-session-00.txt
- touch draft-riikonen-presence-attrs-04.txt
- $(makerfc) draft-riikonen-silc-spec-09.nroff \
- draft-riikonen-silc-spec-09.txt
+ touch draft-riikonen-presence-attrs-03.txt
+ $(makerfc) draft-riikonen-silc-spec-08.nroff \
+ draft-riikonen-silc-spec-08.txt
$(makerfc) draft-riikonen-silc-pp-09.nroff \
draft-riikonen-silc-pp-09.txt
- $(makerfc) draft-riikonen-silc-ke-auth-09.nroff \
- draft-riikonen-silc-ke-auth-09.txt
- $(makerfc) draft-riikonen-silc-commands-07.nroff \
- draft-riikonen-silc-commands-07.txt
+ $(makerfc) draft-riikonen-silc-ke-auth-08.nroff \
+ draft-riikonen-silc-ke-auth-08.txt
+ $(makerfc) draft-riikonen-silc-commands-06.nroff \
+ draft-riikonen-silc-commands-06.txt
$(makerfc) draft-riikonen-silc-flags-payloads-04.nroff \
draft-riikonen-silc-flags-payloads-04.txt
- $(makerfc) draft-riikonen-silc-multimedia-session-00.nroff \
- draft-riikonen-silc-multimedia-session-00.txt
- $(makerfc) draft-riikonen-presence-attrs-04.nroff \
- draft-riikonen-presence-attrs-04.txt
+ $(makerfc) draft-riikonen-presence-attrs-03.nroff \
+ draft-riikonen-presence-attrs-03.txt
#else !SILC_DIST_TOOLKIT
dist-hook:
$(SILC_TOP_SRCDIR)/scripts/manpages.pl
rm draft-riikonen*.txt
- touch draft-riikonen-silc-spec-09.txt
+ touch draft-riikonen-silc-spec-08.txt
touch draft-riikonen-silc-pp-09.txt
- touch draft-riikonen-silc-ke-auth-09.txt
- touch draft-riikonen-silc-commands-07.txt
+ touch draft-riikonen-silc-ke-auth-08.txt
+ touch draft-riikonen-silc-commands-06.txt
touch draft-riikonen-silc-flags-payloads-04.txt
- touch draft-riikonen-silc-multimedia-session-00.txt
- touch draft-riikonen-presence-attrs-04.txt
+ touch draft-riikonen-presence-attrs-03.txt
#endif SILC_DIST_TOOLKIT
doc-install:
#ifdef SILC_DIST_CLIENT
silc.1 \
#endif SILC_DIST_CLIENT
+#ifndef SILC_DIST_CLIENT
+ example_silcd.conf \
+#endif SILC_DIST_CLIENT
#ifdef SILC_DIST_SERVER
examples silcd.8 silcd.conf.5 \
#endif SILC_DIST_SERVER
CodingStyle \
#endif SILC_DIST_TOOLKIT
FAQ \
- example_silcd.conf \
silcalgs.conf \
draft-riikonen*.txt
.ds RF FORMFEED[Page %]
.ds CF
.ds LH Internet Draft
-.ds RH 15 January 2007
+.ds RH XXXXX
.ds CH
.na
.hy 0
.nf
Network Working Group P. Riikonen
Internet-Draft
-draft-riikonen-presence-attrs-04.txt 15 January 2007
-Expires: 15 July 2007
+draft-riikonen-presence-attrs-03.txt XXXx
+Expires: XXX
.in 3
<draft-riikonen-presence-attrs-04.txt>
.ti 0
-Status of this Draft
+Status of this Memo
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026. Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups. Note that other groups may also
+distribute working documents as Internet-Drafts.
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
-The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
-The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
.ti 0
2.3 Attribute Data Types ...................................... 4
2.4 Attribute Payload ......................................... 4
2.5 Attributes ................................................ 5
-3 Security Considerations ....................................... 12
+3 Security Considerations ....................................... 11
4 References .................................................... 12
5 Author's Address .............................................. 13
6 Full Copyright Statement ...................................... 13
.ti 0
1.1 Requirements Terminology
-The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
MAY, and OPTIONAL, when they appear in this document, are to be
interpreted as described in [RFC2119].
information, or with the required precision that may be desired in
some applications. It is therefore RECOMMENDED that this attribute
would be used to provide only basic and constant user information,
- such as name and contact information, but not online status
+ such as name and contact information, but not online status
information.
Length Type Value
Note that these public keys are intended for signing. Some
certificates may have a key usage restrictions and same key cannot
be used for both encryption and signing. Therefore, the name
- of the certificate type indicates if they are intended for
+ of the certificate type indicates if they are intended for
signing only.
This attribute includes a third party server or authority public
key or CA certificate and MUST be present if the attribute
ATTRIBUTE_SERVER_DIGITAL_SIGNATURE is also present. The format
- for this attribute is identical to the ATTRIBUTE_USER_PUBLIC_KEY
+ for this attribute is identical to the ATTRIBUTE_USER_PUBLIC_KEY
attribute. If there are more than one ATTRIBUTE_SERVER_PUBLIC_KEY
attributes set and ATTRIBUTE_SERVER_DIGITAL_SIGNATURE is also set,
the digital signature SHOULD be verifiable with the first set public
This attribute value includes digital signature of all Attribute
Payloads except this attribute. This signature can be provided by
- the user. This attribute SHOULD be last attribute provided in the
- reply so that it is easier for the receiver to compute the signature
+ the user. This attribute SHOULD be last attribute provided in the
+ reply so that it is easier for the receiver to compute the signature
data to be verified. The format and encoding of this attribute
depends on the public key or certificate used to produce the
signature. See the ATTRIBUTE_USER_PUBLIC_KEY for all public keys
information provided by the user. How it verifies this information
is out of scope of this document, however it may base its
information to a previous registration information and current
- online status of the user in a service. This attribute SHOULD be
+ online status of the user in a service. This attribute SHOULD be
last when provided, so that it is easier for the receiver to
compute the signature data to be verified. The format for this
attribute is identical to the ATTRIBUTE_USER_DIGITAL_SIGNATURE
.ti 0
-4 References
+4 References
[RFC2119] Bradner, S., "Key Words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
RFC 2426, September 1998.
[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
- Protocol Specification", Internet Draft, January 2007.
+ Protocol Specification", Internet Draft, May 2002.
[RFC2440] Callas, J., et al, "OpenPGP Message Format", RFC 2440,
November 1998.
-[RFC2459] Housley, R., et al, "Internet X.509 Public Key
+[RFC2459] Housley, R., et al, "Internet X.509 Public Key
Infrastructure, Certificate and CRL Profile", RFC 2459,
January 1999.
-[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
+[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
Internet Draft.
[PKCS7] Kalinski, B., "PKCS #7: Cryptographic Message Syntax,
5 Author's Address
Pekka Riikonen
-Helsinki
+Snellmaninkatu 34 A 15
+70100 Kuopio
Finland
EMail: priikone@iki.fi
.ti 0
6 Full Copyright Statement
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
<channel auth> Authentication Payload's Public Data field
MUST include an indication of the public key to be used. The
first 20 bytes of the Public Data field MUST be SHA-1 digest of
- the public key that must be used in verification. The digest
- is the SILC Public Key fingerprint. Rest of thePublic Data field
- are set as defined in [SILC1]. This way server can determine from
- the digest whether that public key exist on the channel and then
- use that key in verification. The hash function used with
- <channel auth> MUST be sha1.
+ the public key that must be used in verification. Rest of the
+ Public Data field are set as defined in [SILC1]. This way server
+ can determine from the digest whether that public key exist on the
+ channel and then use that key in verification. The hash function
+ used with <channel auth> MUST be sha1.
The server MUST check whether the user is allowed to join to
the requested channel. Various modes set to the channel affect
+++ /dev/null
-.pl 10.0i
-.po 0
-.ll 7.2i
-.lt 7.2i
-.nr LL 7.2i
-.nr LT 7.2i
-.ds LF Riikonen
-.ds RF FORMFEED[Page %]
-.ds CF
-.ds LH Internet Draft
-.ds RH 15 January 2007
-.ds CH
-.na
-.hy 0
-.in 0
-.nf
-Network Working Group P. Riikonen
-Internet-Draft
-draft-riikonen-silc-commands-07.txt 15 January 2007
-Expires: 15 July 2007
-
-.in 3
-
-.ce 2
-SILC Commands
-<draft-riikonen-silc-commands-07.txt>
-
-.ti 0
-Status of this Draft
-
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
-
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
-
-The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
-The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
-
-
-.ti 0
-Abstract
-
-This memo describes the commands used in the Secure Internet Live
-Conferencing (SILC) protocol, specified in the Secure Internet Live
-Conferencing, Protocol Specification [SILC1]. The SILC Commands are
-very important part of the SILC protocol. Usually the commands are used
-by SILC clients to manage the SILC session, but also SILC servers may
-use the commands. This memo specifies detailed command messages and
-command reply messages.
-
-
-
-
-
-
-
-
-.ti 0
-Table of Contents
-
-.nf
-1 Introduction .................................................. 2
- 1.1 Requirements Terminology .................................. 2
-2 SILC Commands ................................................. 2
- 2.1 SILC Commands Syntax ...................................... 4
- 2.2 SILC Command Argument Idioms .............................. 4
- 2.3 SILC Commands List ........................................ 5
- 2.4 SILC Command Status Payload ............................... 43
-3 SILC Status Types ............................................. 44
-4 Security Considerations ....................................... 51
-5 References .................................................... 51
-6 Author's Address .............................................. 52
-Appendix A ...................................................... 52
-Full Copyright Statement ........................................ 54
-
-
-.ti 0
-1. Introduction
-
-This document describes the commands used in the Secure Internet Live
-Conferencing (SILC) protocol, specified in the Secure Internet Live
-Conferencing, Protocol Specification [SILC1]. This document specifies
-detailed command messages and command reply messages.
-
-Commands are very important part on SILC network especially for client
-which uses commands to operate on the SILC network. Commands are used
-to set nickname, join to channel, change modes and many other things.
-
-See the [SILC1] for the requirements and the restrictions for the usage
-of the SILC commands. The [SILC2] defines the command packet type and
-the Command Payload which is actually used to deliver the commands and
-command reply messages.
-
-
-.ti 0
-1.1 Requirements Terminology
-
-The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
-MAY, and OPTIONAL, when they appear in this document, are to be
-interpreted as described in [RFC2119].
-
-
-.ti 0
-2 SILC Commands
-
-.ti 0
-2.1 SILC Commands Syntax
-
-This section briefly describes the syntax of the command notions
-in this document. Every field in command is separated from each
-other by whitespaces (` ') indicating that each field is independent
-argument and each argument MUST have own Command Argument Payload.
-The number of maximum arguments are defined with each command
-separately. The Command Argument Payload is described in [SILC2].
-
-Every command defines specific number for each argument. Currently,
-they are defined in ascending order; first argument has number one
-(1), second has number two (2) and so on. This number is set into the
-Argument Type field in the Command Argument Payload. This makes it
-possible to send the arguments in free order as the number MUST be
-used to identify the type of the argument. This makes is it also
-possible to have multiple optional arguments in commands and in
-command replies. The number of argument is marked in parentheses
-before the actual argument.
-
-
-
-.in 6
-Example: Arguments: (1) <nickname> (2) <username@host>
-.in 3
-
-
-Every command replies with Status Payload. This payload tells the
-sender of the command whether the command was completed successfully or
-whether there was an error. If error occurred the payload includes the
-error type. In the next section the Status Payload is not described
-as it is common to all commands and has been described here. Commands
-MAY reply with other arguments as well. These arguments are command
-specific and are described in the next section.
-
-Example command:
-.in 6
-
-EXAMPLE_COMMAND
-
-.in 8
-Max Arguments: 3
- Arguments: (1) <nickname>[@<server>] (2) <message>
- (3) [<count>]
-
-The command has maximum of 3 arguments. However, only first
-and second arguments are mandatory.
-
-First argument <nickname> is mandatory but may have optional
-<nickname@server> format as well. Second argument is mandatory
-<message> argument. Third argument is optional <count> argument.
-
-The numbers in parentheses are the argument specific numbers
-that specify the type of the argument in Command Argument Payload.
-The receiver always knows that, say, argument number two (2) is
-<message> argument, regardless of the ordering of the arguments in
-the Command Payload.
-
-Reply messages to the command:
-
-Max Arguments: 4
- Arguments: (1) <Status Payload> (2) [<channel list>]
- (3) <idle time> (4) [<away message>]
-
-This command may reply with maximum of 4 arguments. However,
-only the first and third arguments are mandatory. The numbers
-in the parentheses have the same meaning as in the upper
-command sending specification.
-
-Every command reply with <Status Payload>, it is mandatory
-argument for all command replies and for this reason it is not
-described in the command reply descriptions.
-
-
-
-Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_NO_SUCH_NICK
-
-Every command reply also defines set of status message that it
-may return inside the <Status Payload>. All status messages
-are defined in the section 2.3 SILC Command Status Payload
-The status messages defined with the command are recommendations.
-It is possible to return other status messages not listed with
-the command reply definition.
-.in 3
-
-
-.ti 0
-2.2 SILC Command Argument Idioms
-
-All commands that has an ID as argument (for example <Client ID>) are
-actually ID Payloads, defined in [SILC2] that includes the type of the
-ID, length of the ID and the actual ID data. This way variable length
-ID's can be sent as arguments.
-
-All passphrases that may be sent in commands as arguments MUST be
-UTF-8 [RFC3629] encoded. All strings sent as arguments in command and
-command reply are also UTF-8 encoded, unless otherwise defined. See
-the [SILC1] for general UTF-8 definition in SILC protocol.
-
-All public keys and certificates that are sent as arguments are actually
-Public Key Payloads [SILC2]. This way it is possible to send different
-kind of public keys and certificate types as arguments.
-
-
-
-
-.ti 0
-2.3 SILC Commands List
-
-This section lists all SILC commands, however, it is expected that a
-implementation and especially client implementation has many more
-commands that has only local affect. These commands are official
-SILC commands that has both client and server sides and cannot be
-characterized as local commands.
-
-List of all defined commands in SILC follows.
-
-.in 0
- 0 SILC_COMMAND_NONE
-
- None. This is reserved command and MUST NOT be sent.
-
-
- 1 SILC_COMMAND_WHOIS
-
- Max Arguments: 256
- Arguments: (1) [<nickname>[@<server>]] (2) [<count>]
- (3) [<Requested Attributes>] (4) [<Client ID>]
- (n) [...]
-
- Whois command is used to query various information about specific
- user. The user may be requested by their nickname and server name.
- The query may find multiple matching users as there are no unique
- nicknames in the SILC. The <count> option may be given to narrow
- down the number of accepted results. If this is not defined there
- are no limit of accepted results. The query may also be narrowed
- down by defining the server name of the nickname. The <count> is
- 32 bit MSB first order integer.
-
- It is also possible to search the user by Client ID. If the
- <Client ID> is provided server MUST use it as the search value
- instead of the <nickname>. It is also possible to define multiple
- Client ID's to search multiple users sending only one WHOIS
- command. In this case the Client ID's are appended as normal
- arguments.
-
- The <Requested Attributes> is defined in [ATTRS] and can be used
- to request various information about the client. See Appendix A
- for definition of using these attributes in SILC. If neither the
- <nickname> or <Client ID> arguments are present but the attributes
- are, the server MUST use the attributes to do the searching. If
- none of the arguments, <nickname>, <Client ID> and <Requested
- Attributes> are present, error MUST be retuned. Server MAY
- use the <Requested Attributes> to narrow down the search if they
- present at any time.
-
- To prevent miss-use of this command wildcards in the nickname
- or in the server name are not permitted. It is not allowed
- to request all users on some server. The WHOIS requests MUST
- be based on explicit nickname request.
-
- The WHOIS request MUST be always sent to the router by normal
- server so that all users are searched. However, the server still
- MUST search its locally connected clients. The router MUST send
- this command to the server which owns the requested client, if
- the router is unable to provide all mandatory information about
- the client. That server MUST reply to the command. Server MUST
- NOT send whois replies to the client until it has received the
- reply from its router.
-
- Reply messages to the command:
-
- Max Arguments: 11
- Arguments: (1) <Status Payload> (2) <Client ID>
- (3) <nickname>[@<server>] (4) <username@host>
- (5) <real name> (6) [<Channel Payload
- list>]
- (7) [<user mode>] (8) [<idle time>]
- (9) [<fingerprint>] (10) <channel user
- mode list>
- (11) [<Attributes>]
-
-
- This command may reply with several command reply messages to
- form a list of results. In this case the status payload will
- include STATUS_LIST_START status in the first reply and
- STATUS_LIST_END in the last reply to indicate the end of the
- list. If there are only one reply the status is set to normal
- STATUS_OK. If multiple Client IDs was requested then each found
- and unfound client MUST cause successful or error reply,
- respectively.
-
- The command replies include the Client ID of the nickname,
- nickname and server name, user name and host name and user's real
- name. Client should process these replies only after the last
- reply has been received with the STATUS_LIST_END status. If the
- <count> option were defined in the query there will be only
- <count> many replies from the server.
-
- The server returns the list of channels if the client has
- joined channels. In this case the list is list of Channel
- Payloads. The Mode Mask in the Channel Payload is the channel's
- mode. The list is encoded by adding the Channel Payloads one
- after the other. Private and secret channels MUST NOT be sent,
- except if the sender of this command is on those channels, or
- the sender is server. The <channel user mode list> MUST also
- be sent if client is joined channels. This list includes 32 bit
- MSB first order values one after the other and each indicate
- the user's mode on a channel. The order of these values MUST
- be same as the channel order in the <Channel Payload list>.
-
- The server also returns client's user mode, idle time, and the
- fingerprint of the client's public key. The <fingerprint> is the
- binary hash digest of the public key. The fingerprint MUST NOT
- be sent if the server has not verified the proof of possession of
- the corresponding private key. Server can do this during the
- SILC Key Exchange protocol. The <fingerprint> is SHA1 digest.
-
- The <Attributes> is the reply to the <Requested Attributes>.
- See the Appendix A for more information.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_LIST_START
- SILC_STATUS_LIST_END
- SILC_STATUS_ERR_NO_SUCH_NICK
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
-
-
- 2 SILC_COMMAND_WHOWAS
-
- Max Arguments: 2
- Arguments: (1) <nickname>[@<server>] (2) [<count>]
-
- Whowas. This command is used to query history information about
- specific user. The user may be requested by their nickname and
- server name. The query may find multiple matching users as there
- are no unique nicknames in the SILC. The <count> option may be
- given to narrow down the number of accepted results. If this
- is not defined there are no limit of accepted results. The query
- may also be narrowed down by defining the server name of the
- nickname. The <count> is 32 bit MSB first order integer.
-
- To prevent miss-use of this command wildcards in the nickname
- or in the server name are not permitted. The WHOWAS requests MUST
- be based on specific nickname request.
-
- The WHOWAS request MUST be always sent to the router by server
- so that all users are searched. However, the server still must
- search its locally connected clients.
-
- Reply messages to the command:
-
- Max Arguments: 5
- Arguments: (1) <Status Payload> (2) <Client ID>
- (3) <nickname>[@<server>] (4) <username@host>
- (5) [<real name>]
-
- This command may reply with several command reply messages to form
- a list of results. In this case the status payload will include
- STATUS_LIST_START status in the first reply and STATUS_LIST_END in
- the last reply to indicate the end of the list. If there are only
- one reply the status is set to normal STATUS_OK.
-
- The command replies with nickname and user name and host name.
- Every server MUST keep history for some period of time of its
- locally connected clients.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_LIST_START
- SILC_STATUS_LIST_END
- SILC_STATUS_ERR_NO_SUCH_NICK
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
-
-
- 3 SILC_COMMAND_IDENTIFY
-
- Max Arguments: 256
- Arguments: (1) [<nickname>[@<server>]] (2) [<server name>]
- (3) [<channel name>] (4) [<count>]
- (5) [<ID Payload>] (n) [...]
-
- Identify command is used to query information about an entity by
- the entity's name or ID. This command can be used to query
- information about clients, servers and channels.
-
- The query may find multiple matching entities. The <count> option
- may be given to narrow down the number of accepted results. If
- this is not defined there are no limit of accepted results. The
- <count> is 32 bit MSB first order integer.
-
- It is also possible to search the entity by its ID. If the
- <ID Payload> is provided server must use it as the search value
- instead of the entity's name. One of the arguments MUST be given.
- It is also possible to define multiple ID Payloads to search
- multiple entities sending only one IDENTIFY command. In this case
- the ID Payloads are appended as normal arguments. The type of the
- entity is defined by the type of the ID Payload.
-
- To prevent miss-use of this command wildcards in the names are
- not permitted. It is not allowed to request for example all users
- on server.
-
- Implementations may not want to give interface access to this
- command as it is hardly a command that would be used by an end
- user. However, it must be implemented as it is most likely used
- with private message sending.
-
- The IDENTIFY command MUST be always sent to the router by server
- so that all users are searched. However, server MUST still search
- its locally connected clients.
-
- Reply messages to the command:
-
- Max Arguments: 4
- Arguments: (1) <Status Payload> (2) <ID Payload>
- (3) [<entity's name>] (4) [<info>]
-
- This command may reply with several command reply messages to form
- a list of results. In this case the status payload will include
- STATUS_LIST_START status in the first reply and STATUS_LIST_END in
- the last reply to indicate the end of the list. If there are only
- one reply the status is set to normal STATUS_OK. If multiple Client
- IDs was requested then each found and unfound client must cause
- successful or error reply, respectively.
-
- When querying clients the <entity's name> must include the client's
- nickname in the following format: nickname[@server]. The
- <info> must include the client's username and host in the following
- format: username@host.
-
- When querying servers the <entity's name> must include the server's
- full name. The <info> may be omitted.
-
- When querying channels the <entity's name> must include the
- channel's name. The <info> may be omitted.
-
- If the <count> option were defined in the query there will be only
- <count> many replies from the server.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_LIST_START
- SILC_STATUS_LIST_END
- SILC_STATUS_ERR_NO_SUCH_NICK
- SILC_STATUS_ERR_NO_SUCH_SERVER
- SILC_STATUS_ERR_NO_SUCH_CHANNEL
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
-
-
- 4 SILC_COMMAND_NICK
-
- Max Arguments: 1
- Arguments: (1) <nickname>
-
- Set/change nickname. This command is used to set nickname for
- user. See [SILC1] for definition of correctly formatted
- nickname.
-
- When nickname is changed new Client ID is generated. Server MUST
- distribute SILC_NOTIFY_TYPE_NICK_CHANGE to local clients on the
- channels (if any) the client is joined on. Then it MUST send
- SILC_NOTIFY_TYPE_NICK_CHANGE notify to its primary route to
- notify about nickname and Client ID change.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <New ID Payload>
- (3) <nickname>
-
- This command replies always with <New ID Payload> that is
- generated by the server every time user changes their nickname.
- Client receiving this payload MUST start using the received
- Client ID as its current valid Client ID. The New ID Payload
- is described in [SILC2]. The <nickname> is the user's new
- nickname.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NICKNAME_IN_USE
- SILC_STATUS_ERR_BAD_NICKNAME
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
-
-
- 5 SILC_COMMAND_LIST
-
- Max Arguments: 1
- Arguments: (1) [<Channel ID>]
-
- The list command is used to list channels and their topics on the
- current server. If the <Channel ID> parameter is used, only the
- status of that channel is displayed. Secret channels are not
- listed at all. Private channels are listed with status indicating
- that the channel is private. Router MAY reply with all channels
- it knows about.
-
- Reply messages to the command:
-
- Max Arguments: 5
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) <channel> (4) [<topic>]
- (5) [<user count>]
-
- This command may reply with several command reply messages to form
- a list of results. In this case the status payload will include
- STATUS_LIST_START status in the first reply and STATUS_LIST_END in
- the last reply to indicate the end of the list. If there are only
- one reply the status is set to normal STATUS_OK.
-
- This command replies with Channel ID, name and the topic of the
- channel. If the channel is private channel the <topic> SHOULD
- include the "*private*" string.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_LIST_START
- SILC_STATUS_LIST_END
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_NO_SUCH_SERVER
-
-
- 6 SILC_COMMAND_TOPIC
-
- Max Arguments: 2
- Arguments: (1) <Channel ID> (2) [<topic>]
-
- This command is used to change or view the topic of a channel.
- The topic for channel <Channel ID> is returned if there is no
- <topic> given. If the <topic> parameter is present, the topic
- for that channel will be changed, if the channel modes permit
- this action.
-
- After setting the topic the server MUST send the notify type
- SILC_NOTIFY_TYPE_TOPIC_SET to its primary router and then to
- the channel which topic was changed.
-
- Reply messages to the command:
-
- Max Arguments: 2
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) [<topic>]
-
- The command may reply with the topic of the channel if it is
- set.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ON_CHANNEL
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CHANNEL
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_BAD_CHANNEL_ID
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_CHANNEL_PRIV
-
-
- 7 SILC_COMMAND_INVITE
-
- Max Arguments: 4
- Arguments: (1) <Channel ID> (2) [<Client ID>]
- (3) [<add | del>] (4) [<invite list>]
-
- This command can be used to invite other clients to join to a
- channel, and to manage the channel's invite list. The <Client
- ID> argument is the target client's ID that is being invited.
- The <Channel ID> is the Channel ID of the requested channel.
- The sender of this command MUST be on the channel. The server
- MUST also send the notify type SILC_NOTIFY_TYPE_INVITE to its
- primary router and then to the client indicated by the <Client
- ID>.
-
- The <add | del> is an argument of size of 1 byte where 0x00 means
- adding a client to invite list, and 0x01 means deleting a client
- from invite list. The <invite list>, if present, indicates
- the information to be added to or removed from the invite list.
- It may include a string for matching clients, public key of a
- client (Public Key Payload) or Client ID of a client. The
- <invite list> is an Argument List Payload.
-
- The following Argument Types has been defined for invite list
- Argument Payloads:
-
- 0x01 - Argument is an invite string of following format:
-
- [<nickname>[@<server>]!][<username>]@[<hostname or IP/MASK>]
-
- The <hostname> may also be in format of IP/MASK to indicate
- a network, for example 10.2.1.0/255.255.0.0.
-
- 0x02 - Argument is the public key of a client
- 0x03 - Argument is the Client ID of a client
-
- If unknown type value is received or there is invalid amount of
- Argument Payloads present in the list, the command MUST be
- discarded. When argument that is to be deleted from the invite
- list does not exist in the list the argument is ignored.
-
- When adding to or removing from the invite list the server MUST
- send the notify type SILC_NOTIFY_TYPE_INVITE to its primary router.
- When the SILC_CHANNEL_MODE_INVITE is set the client which executes
- this command MUST have at least channel operator privileges to be
- able to add to or remove from the invite list. If this channel
- mode is not set the list manipulation is allowed for all clients.
- Wildcards MAY be used with this command. When this command is
- used to invite explicit client with <Client ID> the ID MUST be
- added to the invite list by the server.
-
- When this command is given with only <Channel ID> argument then
- the command merely returns the invite list of the channel. This
- command MUST fail if the requested channel does not exist, the
- requested <Client ID> is already on the channel or if the channel
- is invite only channel and the caller of this command does not
- have at least channel operator privileges on the channel.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) [<invite list>]
-
- This command replies with the invite list of the channel if it
- exists.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_NO_CLIENT_ID
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_NOT_ON_CHANNEL
- SILC_STATUS_ERR_USER_ON_CHANNEL
- SILC_STATUS_ERR_NO_CHANNEL_PRIV
- SILC_STATUS_ERR_RESOURCE_LIMIT
-
-
- 8 SILC_COMMAND_QUIT
-
- Max Arguments: 1
- Arguments: (1) [<quit message>]
-
- This command is used by client to end SILC session. The server
- must close the connection to a client which sends this command.
- if <quit message> is given it will be sent to other clients on
- channel if the client is on channel when quitting.
-
- Reply messages to the command:
-
- This command does not reply anything.
-
-
- 9 SILC_COMMAND_KILL
-
- Max Arguments: 3
- Arguments: (1) <Client ID> (2) [<comment>]
- (3) [<auth payload>]
-
- This command can be used by SILC operators to remove a client from
- SILC network. It also can be used by a normal client to remove
- its own client from network by providing correct authentication
- data.
-
- Router operator killing a client:
-
- The removing has temporary effects and client may reconnect to
- SILC network. The <Client ID> is the client to be removed from SILC.
- The <comment> argument may be provided to give to the removed client
- some information why it was removed from the network. The killer
- MUST have SILC operator privileges.
-
- When killing a client the router MUST first send notify type
- SILC_NOTIFY_TYPE_KILLED to all channels the client has joined.
- The packet MUST NOT be sent to the killed client on the channels.
- Then, the router MUST send the same notify type to its primary
- router. Finally, the router MUST send the same notify type
- destined directly to the client which was killed. The killed
- client MUST also be removed from the invite lists of joined
- channels if it is explicitly added in the invite lists.
-
- Normal client killing by authentication:
-
- When normal client executes this command the <Client ID> is the
- destination client to be removed from the network. The client
- MUST provide the <auth payload> which includes a digital signature
- that MUST be verified with the public key of the client indicated
- by <Client ID>. The <Client ID> MUST be local client to the server.
- If the signature verification is successful the server sends
- SILC_NOTIFY_TYPE_SIGNOFF to network and to the destination client.
- The SILC_NOTIFY_TYPE_KILLED MUST NOT be used in this case. If the
- verification fails the destination client remains in network.
- The hash function used in <auth payload> computing is selected
- by user or SHA1 otherwise.
-
- Reply messages to the command:
-
- Max Arguments: 2
- Arguments: (1) <Status Payload> (2) <Client ID>
-
- This command returns with the requested Client ID.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_NO_CLIENT_ID
- SILC_STATUS_ERR_NO_ROUTER_PRIV
-
-
- 10 SILC_COMMAND_INFO
-
- Max Arguments: 2
- Arguments: (1) [<server>] (2) [<Server ID>]
-
- This command is used to fetch various information about a server.
- If <server> argument is specified the command MUST be sent to
- the requested server.
-
- If the <Server ID> is specified the server information if fetched
- by the provided Server ID. One of the arguments MUST always be
- present.
-
- Reply messages to the command:
-
- Max Arguments: 4
- Arguments: (1) <Status Payload> (2) <Server ID>
- (3) <server name> (4) <string>
-
- This command replies with the Server ID of the server and a
- string which tells the information about the server.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_SERVER
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID
- SILC_STATUS_ERR_NO_SERVER_ID
-
-
- 11 SILC_COMMAND_STATS
-
- Max Arguments: 1
- Arguments: (1) <Server ID>
-
- This command is used to fetch various statistical information
- from the server indicated by <Server ID>, which is the ID of
- server where sender is connected to. Server receiving this
- command MAY also send this further to its router for fetching
- other cell and network wide statistics to accompany the reply.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <Server ID>
- (3) [<statistics structure>]
-
- This command replies with the Server ID of the server and
- optional statistics structure which includes 32 bit MSB first
- ordered integer values to represent various statistical
- information. The structure is as follows:
-
- starttime - time when server was started
- uptime - uptime of the server
- my clients - number of locally connected clients
- my channels - number of locally created channels
- my server ops - number of local server operators
- my router ops - number of local router operators
- cell clients - number of clients in local cell
- cell channels - number of channels in local cell
- cell servers - number of servers in local cell
- clients - number of client in SILC network
- channels - number of channels in SILC network
- servers - number of servers in SILC network
- routers - number of routers in SILC network
- server ops - number of server operators in SILC network
- router ops - number of router operators in SILC network
-
- If some value is unknown it is set to zero (0) value. The
- "starttime" is the start time of the server, and is seconds
- since Epoch (POSIX.1). The "uptime" is time difference of
- current time and "starttime" in the server, and is seconds
- in value.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID
- SILC_STATUS_ERR_NO_SUCH_SERVER
- SILC_STATUS_ERR_NO_SERVER_ID
-
-
- 12 SILC_COMMAND_PING
-
- Max Arguments: 1
- Arguments: (1) <Server ID>
-
- This command is used by client and server to test the communication
- channel to its server if one suspects that the communication is not
- working correctly. The <Server ID> is the ID of the server the
- sender is connected to.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with Status Payload. Server returns
- SILC_STATUS_OK in Status Payload if pinging was successful.
-
-
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SERVER_ID
- SILC_STATUS_ERR_NO_SUCH_SERVER
- SILC_STATUS_ERR_NOT_REGISTERED
-
-
- 13 SILC_COMMAND_OPER
-
- Max Arguments: 2
- Arguments: (1) <username> (2) <authentication payload>
-
- This command is used by normal client to obtain server operator
- privileges on some server or router. Note that router operator
- has router privileges that supersedes the server operator
- privileges and this does not obtain those privileges. Client
- MUST use SILCOPER command to obtain router level privileges.
-
- The <username> is the username set in the server configurations
- as operator. The <authentication payload> is the data that the
- client is authenticated against. It may be passphrase prompted
- for user on client's screen or it may be public key authentication
- based on digital signatures. The public key used to verify the
- signature should be locally saved in the server, and server should
- not use public key received during the SKE to verify this signature.
-
- After changing the mode the server MUST send the notify type
- SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with Status Payload.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_AUTH_FAILED
-
-
- 14 SILC_COMMAND_JOIN
-
- Max Arguments: 7
- Arguments: (1) <channel> (2) <Client ID>
- (3) [<passphrase>] (4) [<cipher>]
- (5) [<hmac>] (6) [<founder auth>]
- (7) [<channel auth>]
-
- Join to channel/create new channel. This command is used to
- join to a channel. If the channel does not exist the channel is
- created. If server is normal server this command MUST be sent
- to router which will create the channel. The channel MAY be
- protected with passphrase. If this is the case the passphrase
- MUST be sent along the join command. See the [SILC1] for
- definition of correctly formatted channel name, <channel>.
-
- The second argument <Client ID> is the Client ID of the client
- which is joining to the client. When client sends this command
- to the server the <Client ID> MUST be the client's own ID.
-
- Cipher to be used to secure the traffic on the channel MAY be
- requested by sending the name of the requested <cipher>. This
- is used only if the channel does not exist and is created. If
- the channel already exists the cipher set previously for the
- channel will be used to secure the traffic. The computed MACs
- of the channel message are produced by the default HMAC or by
- the <hmac> provided for the command.
-
- The <founder auth> is Authentication Payload providing the
- authentication for gaining founder privileges on the channel
- when joining the channel. The client may provide this if it
- knows that it is the founder of the channel and that the
- SILC_CMODE_FOUNDER_AUTH mode is set on the channel. The server
- MUST verify whether the client is able to gain the founder
- privileges the same way as the client had given the
- SILC_COMMAND_CUMODE command to gain founder privileges. The
- client is still able to join the channel even if the founder
- privileges could not be gained. The hash function used with
- the <founder payload> is selected by user or SHA1 otherwise.
-
- If the <channel auth> is present and the channel mode
- SILC_CMODE_CHANNEL_AUTH is set the server MUST verify the
- <channel auth> with channel public key(s). If public key that
- can verify <channel auth> does not exist on the channel public
- key list the client MUST NOT be allowed to join the channel.
- Because more than one public key may be set on channel the
- <channel auth> Authentication Payload's Public Data field
- MUST include an indication of the public key to be used. The
- first 20 bytes of the Public Data field MUST be SHA-1 digest of
- the public key that must be used in verification. The digest
- is the SILC Public Key fingerprint. Rest of thePublic Data field
- are set as defined in [SILC1]. This way server can determine from
- the digest whether that public key exist on the channel and then
- use that key in verification. The hash function used with
- <channel auth> is selected by user or SHA1 otherwise.
-
- The server MUST check whether the user is allowed to join to
- the requested channel. Various modes set to the channel affect
- the ability of the user to join the channel. These conditions
- are:
-
- o The user MUST be invited to the channel if the channel
- is invite-only channel.
-
- o The Client ID/nickname/username/host name/public key
- MUST NOT match any active bans.
-
- o The correct passphrase MUST be provided if passphrase
- is set to the channel, and/or digital signature verification
- with channel public key MUST be successful if public keys
- has been set to the channel.
-
- o The user count limit, if set, MUST NOT be reached.
-
- If the client provided correct <founder auth> payload it can
- override these conditions, except the condition for the passphrase.
- The correct passphrase MUST be provided even if <founder auth>
- payload is provided.
-
- Reply messages to the command:
-
- Max Arguments: 17
- Arguments: (1) <Status Payload> (2) <channel>
- (3) <Channel ID> (4) <Client ID>
- (5) <channel mode mask> (6) <created>
- (7) [<Channel Key Payload>] (8) [<ban list>]
- (9) [<invite list>] (10) [<topic>]
- (11) [<hmac>] (12) <list count>
- (13) <Client ID list> (14) <client mode list>
- (15) [<founder pubkey>] (16) [<channel pubkeys>]
- (17) [<user limit>]
-
- This command replies with the channel name requested by the
- client, channel ID of the channel and topic of the channel
- if it exists. The <Client ID> is the Client ID which was joined
- to the channel. It also replies with the channel mode mask
- which tells all the modes set on the channel. If the channel
- is created the mode mask is zero (0) and <created> is 0x01.
- If ban mask and/or invite list is set they are sent as well.
- The <user limit> is the user limit on the channel, if one is set.
-
- The <list count>, <Client ID list> and <client mode list> are
- the clients currently on the channel and their modes on the
- channel. The <Client ID list> is formed by adding the ID Payloads
- one after the other. The <client mode list> is formed by adding
- 32 bit MSB first order values one after the other. The <founder
- pubkey> is the public key (or certificate) of the channel founder.
- The <channel pubkeys> is Argument List Payload containing the
- channel public keys that has been set for the channel.
-
- Client receives the channel key in the reply message as well
- inside <Channel Key Payload>.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_BAD_PASSWORD
- SILC_STATUS_ERR_CHANNEL_IS_FULL
- SILC_STATUS_ERR_NOT_INVITED
- SILC_STATUS_ERR_BANNED_FROM_CHANNEL
- SILC_STATUS_ERR_BAD_CHANNEL
- SILC_STATUS_ERR_USER_ON_CHANNEL
-
-
- 15 SILC_COMMAND_MOTD
-
- Max Arguments: 1
- Arguments: (1) <server>
-
- This command is used to query the Message of the Day of the server.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <Server ID>
- (3) [<motd>]
-
- This command replies with the motd message if it exists.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NO_SUCH_SERVER
-
-
- 16 SILC_COMMAND_UMODE
-
- Max Arguments: 2
- Arguments: (1) <Client ID> (2) [<client mode mask>]
-
- This command is used by client to set/unset modes for itself.
- However, there are some modes that the client MUST NOT set itself,
- but they will be set by server. However, client MAY unset any
- mode. Modes may be masked together ORing them thus having
- several modes set. Client MUST keep its client mode mask
- locally so that the mode setting/unsetting would work without
- problems. Client may change only its own modes.
-
- After changing the mode server MUST send the notify type
- SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
-
- The following client modes are defined:
-
- 0x00000000 SILC_UMODE_NONE
-
- No specific mode for client. This is the initial
- setting when new client is created. The client is
- normal client and is present in the network.
-
-
- 0x00000001 SILC_UMODE_SERVER_OPERATOR
-
- Marks the user as server operator. Client MUST NOT
- set this mode itself. Server sets this mode to the
- client when client attains the server operator
- privileges by SILC_COMMAND_OPER command. Client
- MAY unset the mode itself.
-
-
- 0x00000002 SILC_UMODE_ROUTER_OPERATOR
-
- Marks the user as router (SILC) operator. Client
- MUST NOT set this mode itself. Router sets this mode
- to the client when client attains the router operator
- privileges by SILC_COMMAND_SILCOPER command. Client
- MAY unset the mode itself.
-
-
- 0x00000004 SILC_UMODE_GONE
-
- Marks that the user is not currently present in the
- SILC Network. Client MAY set and unset this mode.
-
-
- 0x00000008 SILC_UMODE_INDISPOSED
-
- Marks that the user is currently indisposed and may
- not be able to receive any messages, and that user may
- not be present in the network. Client MAY set and
- unset this mode.
-
-
- 0x00000010 SILC_UMODE_BUSY
-
- Marks that the user is currently busy and may not
- want to receive any messages, and that user may not
- be present in the network. Client MAY set and unset
- this mode.
-
-
- 0x00000020 SILC_UMODE_PAGE
-
- User is not currently present or is unable to receive
- messages, and prefers to be paged in some mechanism
- if the user needs to be reached. Client MAY set and
- unset this mode.
-
-
- 0x00000040 SILC_UMODE_HYPER
-
- Marks that the user is hyper active and is eager to
- receive and send messages. Client MAY set and unset
- this mode.
-
-
- 0x00000080 SILC_UMODE_ROBOT
-
- Marks that the client is actually a robot program.
- Client MAY set and unset this mode.
-
-
- 0x00000100 SILC_UMODE_ANONYMOUS
-
- Marks that the client is anonymous client. Server
- that specifically is designed for anonymous services
- can set and unset this mode. Client MUST NOT set or
- unset this mode itself. A client with this mode set
- would have the username and the hostname information
- scrambled by the server which set this mode.
-
-
- 0x00000200 SILC_UMODE_BLOCK_PRIVMSG
-
- Marks that the client wishes to block private
- messages sent to the client, unless the Private
- Message Key flag is set in the SILC packet header.
- If this mode is set server MUST NOT deliver private
- messages to the client without the Private Message
- Key flag being set. The Private Message Key flag set
- indicates that the private message is protected with
- a key shared between the sender and the recipient.
-
- A separate service could provide additional filtering
- features for accepting private messages from certain
- sender. However, this document does not specify such
- service.
-
- The client MAY set and unset this mode.
-
-
- 0x00000400 SILC_UMODE_DETACHED
-
- Marks that the client is detached from the SILC network.
- This means that the actual network connection to the
- client is lost but the client entry is still valid. The
- detached client can be resumed at a later time. This
- mode MUST NOT be set by client. It can only be set when
- client has issued command SILC_COMMAND_DETACH. The server
- sets this mode. This mode cannot be unset with this
- command. It is unset when the client is resuming back to
- the network and SILC_PACKET_RESUME_CLIENT packet is
- received.
-
- This flag MUST NOT be used to determine whether a packet
- can be sent to the client or not. Only the server that
- had the original client connection can make the decision
- by knowing that the network connection is not active.
- In this case the default case is to discard the packet.
-
-
- 0x00000800 SILC_UMODE_REJECT_WATCHING
-
- Marks that the client rejects that it could be watched
- by someone else. If this mode is set notifications about
- this client is not send, even if someone is watching the
- same nickname this client has. Client MAY set and unset
- this mode. Any changes for this client MUST NOT be
- notified to any watcher when this mode is set.
-
- A separate service could provide additional filtering
- features for rejecting and accepting the watching from
- certain users. However, this document does not specify
- such service.
-
-
- 0x00001000 SILC_UMODE_BLOCK_INVITE
-
- Marks that the client wishes to block incoming invite
- notifications. Client MAY set and unset this mode.
- When set server does not deliver invite notifications
- to the client. Note that this mode may make it harder
- to join invite-only channels.
-
- If the <client mode mask> was not provided this command merely
- returns the mode mask to the client.
-
-
- Reply messages to the command:
-
- Max Arguments: 2
- Arguments: (1) <Status Payload> (2) <client mode mask>
-
- This command replies with the changed client mode mask that
- the client MUST to keep locally.
-
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_BAD_CLIENT_ID
- SILC_STATUS_ERR_NOT_YOU
- SILC_STATUS_ERR_PERM_DENIED
- SILC_STATUS_ERR_UNKNOWN_MODE
- SILC_STATUS_ERR_NO_CLIENT_ID
-
-
- 17 SILC_COMMAND_CMODE
-
- Max Arguments: 9
- Arguments: (1) <Channel ID> (2) [<channel mode mask>]
- (3) [<user limit>] (4) [<passphrase>]
- (5) [<cipher>] (6) [<hmac>]
- (7) [<auth payload>] (8) [<founder pubkey>]
- (9) [<channel pubkey>]
-
- This command is used by client to set or change channel flags on
- a channel. Channel has several modes that set various properties
- of a channel. Modes may be masked together by ORing them thus
- having several modes set. The <Channel ID> is the ID of the
- target channel. The client changing channel mode MUST be on
- the same channel and posses sufficient privileges to be able to
- change the mode.
-
- When the mode is changed SILC_NOTIFY_TYPE_CMODE_CHANGE notify
- type MUST be distributed to the channel.
-
- The following channel modes are defined:
-
- 0x00000000 SILC_CMODE_NONE
-
- No specific mode on channel. This is the default when
- channel is created. This means that channel is just plain
- normal channel.
-
-
- 0x00000001 SILC_CMODE_PRIVATE
-
- Channel is private channel. Private channels are shown
- in the channel list listed with SILC_COMMAND_LIST command
- with indication that the channel is private. Also,
- client on private channel will no be detected to be on
- the channel as the channel is not shown in the client's
- currently joined channel list. Channel founder and
- channel operator MAY set/unset this mode.
-
-
- 0x00000002 SILC_CMODE_SECRET
-
- Channel is secret channel. Secret channels are not shown
- in the list listed with SILC_COMMAND_LIST command. Secret
- channels can be considered to be invisible channels.
- Channel founder and channel operator MAY set/unset this
- mode.
-
-
- 0x00000004 SILC_CMODE_PRIVKEY
-
- Channel uses private channel key to protect the traffic
- on the channel. When this mode is set the client will be
- responsible to set the key it wants to use to encrypt and
- decrypt the traffic on channel. Server generated channel
- keys are not used at all. This mode provides additional
- security as clients on channel may agree to use private
- channel key that even servers do not know. Naturally,
- this requires that every client on the channel knows
- the key before hand (it is considered to be pre-shared-
- key). The key material SHOULD be processed as stated
- in the [SILC3] in the section Processing the Key Material.
-
- As it is local setting it is possible to have several
- private channel keys on one channel. In this case several
- clients can talk on same channel but only those clients
- that share the key with the message sender will be able
- to hear the talking. Client SHOULD NOT display those
- message for the end user that it is not able to decrypt
- when this mode is set.
-
- Only channel founder MAY set/unset this mode. If this
- mode is unset the server will distribute new channel
- key to all clients on the channel which will be used
- thereafter.
-
-
- 0x00000008 SILC_CMODE_INVITE
-
- Channel is invite only channel. Client may join to this
- channel only if it is invited to the channel. Channel
- founder and channel operator MAY set/unset this mode.
-
-
- 0x00000010 SILC_CMODE_TOPIC
-
- The topic of the channel may only be set by client that
- is channel founder or channel operator. Normal clients
- on channel will not be able to set topic when this mode
- is set. Channel founder and channel operator MAY set/
- unset this mode.
-
-
- 0x00000020 SILC_CMODE_ULIMIT
-
- User limit has been set to the channel. New clients
- may not join to the channel when the limit set is
- reached. Channel founder and channel operator MAY set/
- unset the limit. The <user limit> argument is the
- number of limited users.
-
-
- 0x00000040 SILC_CMODE_PASSPHRASE
-
- Passphrase has been set to the channel. Client may
- join to the channel only if it is able to provide the
- correct passphrase. Setting passphrases to channel
- is entirely safe as all commands are protected in the
- SILC network. Only channel founder MAY set/unset
- the passphrase. The <passphrase> argument is the
- set passphrase.
-
-
- 0x00000080 SILC_CMODE_CIPHER
-
- Sets specific cipher to be used to protect channel
- traffic. The <cipher> argument is the requested cipher.
- When set or unset the server must re-generate new
- channel key. Only channel founder MAY set the cipher of
- the channel. When unset the new key is generated using
- default cipher for the channel.
-
-
- 0x00000100 SILC_CMODE_HMAC
-
- Sets specific hmac to be used to compute the MACs of the
- channel message. The <hmac> argument is the requested hmac.
- Only channel founder may set the hmac of the channel.
-
-
- 0x00000200 SILC_CMODE_FOUNDER_AUTH
-
- Channel founder may set this mode to be able to regain
- channel founder rights even if the client leaves the
- channel. The <auth payload> is the Authentication Payload
- consisting of the public key authentication method and the
- digital signature for that method. The passphrase or NONE
- authentication methods MUST NOT be accepted.
-
- The server does not save <auth payload> but MUST verify it.
- The public key used to verify the payload is the <founder
- pubkey> if present, or the public key of the client sending
- this command. If <founder pubkey> is present also that
- public key MUST be saved as founder's public key. This
- mode may be set only if the <auth payload> was verified
- successfully. The hash function used with the <auth
- payload> is selected by user or SHA1 otherwise.
-
- The public key of the founder is sent in the
- SILC_NOTIFY_TYPE_CMODE_CHANGE notify type so that other
- routers and servers in the network may save the public key.
- This way the founder can reclaim the founder rights back
- to the channel from any server in the network. The founder
- rights can be regained by the SILC_CUMODE_FOUNDER channel
- user mode, or during joining procedure with the command
- SILC_COMMAND_JOIN.
-
- If this mode is already set but the <founder pubkey> is
- different the new key will replace the old founder key and
- the new key is distributed in the network with the
- SILC_NOTIFY_TYPE_CMODE_CHANGE notify. Only the original
- founder may set this mode multiple times and the client
- MUST have SILC_CUMODE_FOUNDER mode on the channel.
-
- When this channel mode is set the channel also becomes
- permanent. If all clients leave the channel while this
- mode is set the channel MUST NOT be destroyed. The founder
- can reclaim the founder mode back on these empty channels
- at any time. Implementations MAY limit the number of how
- many channels a user can own and how long they remain
- persistent.
-
-
- 0x00000400 SILC_CMODE_SILENCE_USERS
-
- Channel founder may set this mode to silence normal users
- on the channel. Users with operator privileges are not
- affected by this mode. Messages sent by normal users
- are dropped by servers when this mode is set. This mode
- can be used to moderate the channel. Only channel founder
- may set/unset this mode.
-
-
- 0x00000800 SILC_CMODE_SILENCE_OPERS
-
- Channel founder may set this mode to silence operators
- on the channel. When used with SILC_CMODE_SILENCE_USERS
- mode this can be used to set the channel in state where only
- the founder of the channel may send messages to the channel.
- Messages sent by operators are dropped by servers when this
- mode is set. Only channel founder may set/unset this mode.
-
-
- 0x00001000 SILC_CMODE_CHANNEL_AUTH
-
- When this mode is set the channel has one or more public keys
- or certificates set, and ability to join the channel requires
- a client to provide digital signature that can be successfully
- verified with one of the channel public keys. This mode is
- equivalent to the SILC_MODE_PASSPHRASE except that digital
- signatures are used to gain access to the channel. Both
- modes MAY be set at the same time. Channel founder may set
- and unset this mode.
-
- The <channel pubkey> argument is an Argument List Payload
- where each argument is Public Key Payload including public
- key to be added or removed from the channel public key list.
- To add a public key to channel this mode is set and the
- argument type is 0x00, and the argument is the public key.
- To remove a public key from channel public key list the
- argument type is 0x01, and the argument is the public key
- to be removed from the list. To remove all public keys at
- once this mode is unset. An implementation MAY limit the
- number of public keys that can be set for the channel.
- This mode MUST NOT be set if <channel pubkey> is not present
- when the mode is set for the first time. Implementation MAY
- add and remove multiple public keys at the same time by
- including multiple arguments to the <channel pubkey>
- Argument List Payload.
-
-
- To make the mode system work, client MUST keep the channel mode
- mask locally so that the mode setting and unsetting would work
- without problems. The client receives the initial channel mode
- mask when it joins to the channel. When the mode changes on
- channel the server MUST distribute the changed channel mode mask
- to all clients on the channel by sending the notify type
- SILC_NOTIFY_TYPE_CMODE_CHANGE. The notify type MUST also be sent
- to the server's primary router. If the <channel mode mask> was
- not provided this command returns the mode mask, founder key,
- channel public key list and the current user limit to the client.
-
- Reply messages to the command:
-
- Max Arguments: 6
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) <channel mode mask> (4) [<founder pubkey>]
- (5) [<channel pubkeys>] (6) [<user limit>]
-
- This command replies with the changed channel mode mask that
- client MUST keep locally. It may also return the channel
- founder's public key if it is set. It may also return list of
- channel public keys when the list was altered. The <channel
- pubkeys> is Argument List Payload and each argument includes
- one public key. The <user limit> is the current user limit
- on the channel, if one is set.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ON_CHANNEL
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_BAD_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_PRIV
- SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
- SILC_STATUS_ERR_UNKNOWN_MODE
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_AUTH_FAILED
-
-
- 18 SILC_COMMAND_CUMODE
-
- Max Arguments: 4
- Arguments: (1) <Channel ID> (2) <mode mask>
- (3) <Client ID> (4) [<auth payload>]
-
- This command is used by client to change channel user modes on
- channel. Users on channel may have some special modes and this
- command is used by channel operators to set or change these modes.
- The <Channel ID> is the ID of the target channel. The <mode mask>
- is OR'ed mask of modes. The <Client ID> is the target client.
- The client changing channel user modes MUST be on the same channel
- as the target client and posses sufficient privileges to be able to
- change the mode.
-
- When the mode is changed SILC_NOTIFY_TYPE_CUMODE_CHANGE notify
- type is distributed to the channel.
-
- The following channel modes are defined:
-
- 0x00000000 SILC_CUMODE_NONE
-
- No specific mode. This is the normal situation for client.
- Also, this is the mode set when removing all modes from
- the target client.
-
-
- 0x00000001 SILC_CUMODE_FOUNDER
-
- The client is channel founder of the channel. Usually this
- mode is set only by the server when the channel was created.
- However, if the SILC_CMODE_FOUNDER_AUTH channel mode has
- been set, the client can claim channel founder privileges
- by providing the <auth payload> that the server will use
- to authenticate the client. The public key that server will
- use to verify the <auth payload> MUST be the same public key
- that was saved when the SILC_CMODE_FOUNDER_AUTH channel
- mode was set. The client MAY remove this mode at any time.
-
-
- 0x00000002 SILC_CUMODE_OPERATOR
-
- Sets channel operator privileges on the channel for a
- client on the channel. Channel founder and channel operator
- MAY set/unset this mode. The client MAY remove this mode
- at any time.
-
-
- 0x00000004 SILC_CUMODE_BLOCK_MESSAGES
-
- Marks that the client wishes not to receive any channel
- messages sent for the channel. Client MAY set and unset
- this mode to itself. Client MUST NOT set it to anyone else.
- When this mode is set server MUST NOT deliver channel
- messages to this client. Other packets such as channel
- key packets are still sent to the client.
-
- A separate service could provide additional filtering
- features for accepting channel messages from certain
- sender. However, this document does not specify such
- service.
-
-
- 0x00000008 SILC_CUMODE_BLOCK_MESSAGES_USERS
-
- Marks that the client wishes not to receive any channel
- messages sent from normal users. Only messages sent by
- channel founder or channel operator is accepted. Client
- MAY set and unset this mode to itself. Client MUST NOT
- set it to anyone else. When this mode is set server MUST
- NOT deliver channel messages that are sent by normal users
- to this client.
-
- A separate service could provide additional filtering
- features for accepting channel messages from certain
- sender. However, this document does not specify such
- service.
-
-
- 0x00000010 SILC_CUMODE_BLOCK_MESSAGES_ROBOTS
-
- Marks that the client wishes not to receive any channel
- messages sent from robots. Messages sent by users with
- the SILC_UMODE_ROBOT user mode set are not delivered.
- Client MAY set and unset this mode to itself. Client MUST
- NOT set it to anyone else. When this mode is set server
- MUST NOT deliver channel messages that are sent by robots
- to this client.
-
-
- 0x00000020 SILC_CUMODE_QUIET
-
- Marks that the client cannot talk on the channel. This
- mode can be set by channel operator or channel founder to
- some other user that is not operator or founder. The
- target client MUST NOT unset this mode. When this mode
- is set the server MUST drop messages sent by this client
- to the channel.
-
-
- Reply messages to the command:
-
- Max Arguments: 4
- Arguments: (1) <Status Payload> (2) <channel user mode mask>
- (3) <Channel ID> (4) <Client ID>
-
- This command replies with the changed channel user mode mask that
- client MUST keep locally. The <Channel ID> is the specified
- channel. The <Client ID> is the target client.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ON_CHANNEL
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_BAD_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_PRIV
- SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
- SILC_STATUS_ERR_UNKNOWN_MODE
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_AUTH_FAILED
-
-
- 19 SILC_COMMAND_KICK
-
- Max Arguments: 3
- Arguments: (1) <Channel ID> (2) <Client ID>
- (3) [<comment>]
-
- This command is used by channel operators to remove a client from
- channel. The <channel> argument is the channel the client to be
- removed is on currently. Note that the "kicker" must be on the same
- channel. If <comment> is provided it will be sent to the removed
- client.
-
- After kicking the client the server MUST send the notify type
- SILC_NOTIFY_TYPE_KICKED to the channel and to its primary router.
- The client is removed from the channel after sending this notify.
- The kicked client MUST be removed from the invite list of the
- channel if it is explicitly added in the list. The channel key
- MUST also be re-generated after kicking, unless the
- SILC_CMODE_PRIVKEY mode is set.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) <Client ID>
-
- This command returns the Channel ID and Client ID that was kicked
- from the channel.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NO_SUCH_CHANNEL
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_NO_CHANNEL_PRIV
- SILC_STATUS_ERR_NO_CLIENT_ID
-
-
-
- 20 SILC_COMMAND_BAN
-
- Max Arguments: 3
- Arguments: (1) <Channel ID> (2) [<add | del>]
- (3) [<ban list>]
-
- This command is used to manage the ban list of the channel
- indicated by the <Channel ID>. A client that is banned from
- channel is no longer able to join the channel. The client which
- is executing this command MUST have at least channel operator
- privileges on the channel.
-
- The <add | del> is an argument of size of 1 byte where 0x00 means
- adding a client to ban list, and 0x01 means deleting a client
- from ban list. The <ban list>, if present, indicates the
- information to be added to or removed from the ban list. It
- may include a string for matching clients, public key of a
- client (Public Key Payload) or Client ID of a client. The
- <ban list> is an Argument List Payload.
-
- The following Argument Types has been defined for ban list
- Argument Payloads:
-
- 0x01 - Argument is an ban string of following format:
-
- [<nickname>[@<server>]!][<username>]@[<hostname or IP/MASK>]
-
- The <hostname> may also be in format of IP/MASK to indicate
- a network.
-
- 0x02 - Argument is the public key of a client
- 0x03 - Argument is the Client ID of a client
-
- If unknown type value is received or there is invalid amount of
- Argument Payloads present in the list, the command MUST be
- discarded. When argument that is to be deleted from the ban
- list does not exist in the list the argument is ignored.
-
- The server MUST send the notify type SILC_NOTIFY_TYPE_BAN to its
- primary router after adding to or removing from the ban list.
- The wildcards MAY be used with this command. If this command
- is executed without the ban arguments the command merely replies
- with the current ban list.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) [<ban list>]
-
- This command replies with the <Channel ID> of the channel and
- the current <ban list> of the channel if it exists.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_NOT_ON_CHANNEL
- SILC_STATUS_ERR_NO_CHANNEL_PRIV
- SILC_STATUS_ERR_RESOURCE_LIMIT
-
-
-
-
- 21 SILC_COMMAND_DETACH
-
- Max Arguments: 0
- Arguments:
-
- This command is used to detach from the network. Client can
- send this command to its server to indicate that it will be
- detached. By detaching the client remains in the network but
- the actual network connection to the server is closed. The
- client may then later resume the old session back.
-
- When this command is received the server MUST check that the
- client is locally connected client, and set the user mode
- SILC_UMODE_DETACHED flag. The SILC_NOTIFY_TYPE_UMODE_CHANGE
- MUST be also sent to routers. The server then sends command
- reply to this command and closes the network connection.
- The server MUST NOT remove the client from its lists, or send
- any signoff notifications for this client. See the [SILC1]
- for detailed information about detaching.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with the status indication.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
-
-
-
- 22 SILC_COMMAND_WATCH
-
- Max Arguments: 4
- Arguments: (1) <Client ID> (2) [<add nickname>]
- (3) [<del nickname>] (4) [<public key>]
-
- This command is used to set up a watch for <add nickname>
- nickname. When a user in the network appears with the
- nickname, or signoffs the network or user's mode is changed
- the client which set up the watch will be notified about
- this change. This can be used to watch for certain nicknames
- in the network and receive notifications when for example a
- friend appears in the network or leaves the network.
-
- The <del nickname> is a nickname that has been previously
- added to watch list and is now removed from it. Notifications
- for that nickname will not be delivered anymore. The nickname
- set to watch MUST NOT include any wildcards. Note also that a
- nickname may match several users since nicknames are not unique.
- Implementations MAY set limits for how many nicknames client
- can watch.
-
- OPTIONALLY this command may also be set to watch clients' actions
- in the network using their public key or certificate. The
- <public key> MAY be present, and it is an Argument List Payload
- where each argument is a Public Key Payload including public key
- to be added or removed from the watch list. To To add a public
- key to watch list the argument type is 0x00, and the argument is
- the public key. To remove a public key from watch list list the
- argument type is 0x01, and the argument is the public key to be
- removed from the list. An implementation MAY limit the number of
- public keys that can be set on the watch list. Implementation MAY
- add and remove multiple public keys at the same time by including
- multiple arguments to the <public key> Argument List Payload.
-
- The <Client ID> is the Client ID of the sender of this command.
-
- When normal server receives this command from client it
- MUST send it to its router. Router will process the command
- and actually keeps the watch list.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with the status indication.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_BAD_NICKNAME
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_RESOURCE_LIMIT
- SILC_STATUS_ERR_NO_SUCH_NICK
- SILC_STATUS_ERR_NICKNAME_IN_USE
-
-
- 23 SILC_COMMAND_SILCOPER
-
- Max Arguments: 2
- Arguments: (1) <username> (2) <authentication payload>
-
- This command is used by normal client to obtain router operator
- privileges (also known as SILC operator) on the router. Note
- that router operator has privileges that supersedes the server
- operator privileges.
-
- The <username> is the username set in the server configurations
- as operator. The <authentication payload> is the data that the
- client is authenticated against. It may be passphrase prompted
- for user on client's screen or it may be public key or certificate
- authentication data (data signed with private key). The public
- key that router will use to verify the signature found in the
- payload should be verified. It is recommended that the public
- key is saved locally in the router and router would not use
- any public keys received during the SKE.
-
- Difference between router operator and server operator is that
- router operator is able to handle cell level properties while
- server operator (even on router server) is able to handle only
- local properties, such as, local connections and normal server
- administration. The router operator is also able to use the
- SILC_COMMAND_KILL command.
-
- After changing the mode server MUST send the notify type
- SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with Status Payload.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_AUTH_FAILED
-
-
-
-
- 24 SILC_COMMAND_LEAVE
-
- Max Arguments: 1
- Arguments: (1) <Channel ID>
-
- This command is used by client to leave a channel the client is
- joined to.
-
- When leaving channel the server MUST send the notify type
- SILC_NOTIFY_TYPE_LEAVE to its primary router and to the channel.
- The channel key MUST also be re-generated when leaving the channel
- and distribute it to all clients still currently on the channel.
- The key MUST NOT be re-generated if the SILC_CMODE_PRIVKEY mode
- is set.
-
- Reply messages to the command:
-
- Max Arguments: 2
- Arguments: (1) <Status Payload> (2) <Channel ID>
-
- The <Channel ID> is the ID of left channel.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_BAD_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
-
-
- 25 SILC_COMMAND_USERS
-
- Max Arguments: 2
- Arguments: (1) [<Channel ID>] (2) [<channel name>]
-
- This command is used to list user names currently on the requested
- channel; either the argument <Channel ID> or the <channel name>.
- One of these arguments must be present. The server MUST resolve
- the joined clients and reply with a lists of users on the channel
- and with list of user modes on the channel.
-
- If the requested channel is a private or secret channel, this
- command MUST NOT send the list of users, except if the sender is
- on the channel, or the sender is a server. Otherwise, error is
- returned to the sender.
-
- Reply messages to the command:
-
- Max Arguments: 5
- Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) <list count> (4) <Client ID list>
- (5) <client mode list>
-
- This command replies with the Channel ID of the requested channel
- Client ID list of the users on the channel and list of their modes.
- The Client ID list has Client ID's of all users in the list. The
- <Client ID list> is formed by adding Client ID's one after another.
- The <client mode list> is formed by adding client's user modes on
- the channel one after another (4 bytes (32 bits) each). The <list
- count> of length of 4 bytes (32 bits), tells the number of entries
- in the lists. Both lists MUST have equal number of entries.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
- SILC_STATUS_ERR_BAD_CHANNEL_ID
- SILC_STATUS_ERR_NO_CHANNEL_ID
- SILC_STATUS_ERR_NOT_ON_CHANNEL
-
-
- 26 SILC_COMMAND_GETKEY
-
- Max Arguments: 1
- Arguments: (1) <ID Payload>
-
- This command is used to fetch the public key of the client or
- server indicated by the <ID Payload>. The public key is fetched
- from the server where to the client is connected.
-
- Reply messages to the command:
-
- Max Arguments: 3
- Arguments: (1) <Status Payload> (2) <ID Payload>
- (3) [<Public Key Payload>]
-
- This command replies with the client's or server's ID and with
- the <Public Key Payload>.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID
-
-
- 27 SILC_COMMAND_SERVICE
-
- Max Arguments: 256
- Arguments: (1) [<service name>] (2) [<auth payload>]
- (n) [...]
-
- This command is used to negotiate a service agreement with a
- remote server. If this command is given without arguments it
- MAY return the service list, if it is publicly available. The
- <service name> is a service specific identifier, and the
- <auth payload> MAY be used to authenticate the requester to the
- remote service. The authentication to a service may be based
- on previous agreement with the requester and the service
- provider. The command MAY also take additional service
- specific arguments.
-
- This document does not specify any services. How the services
- are configured and put available in a server is also out of
- scope of this document.
-
- This command MAY be used by client to start using some service
- in a server, but it also MAY be used by server to negotiate
- to start using a service in some other server or router.
-
- After the negotiation is done both of the parties need to know
- from the service identifier how the service can be used. The
- service can be considered to be a protocol which both of the
- parties need to support.
-
- Reply messages to the command:
-
- Max Arguments: 256
- Arguments: (1) <Status Payload> (2) [<service list>]
- (3) [<service name>] (n) [...]
-
-
- This command MAY reply with the <service list> when command is
- given without arguments, and the list is a comma separated list
- of service identifiers. The <service name> is the service that
- the sender requested and this is provided when the server has
- accepted the sender to use the <service name>. The command
- reply MAY also have additional service specific arguments.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_SERVICE
- SILC_STATUS_ERR_AUTH_FAILED
- SILC_STATUS_ERR_PERM_DENIED
-
-
-
- 28 - 199
-
- Currently undefined commands.
-
-
- 200 - 254
-
- These commands are reserved for private use and will not be defined
- in this document.
-
-
- 255 SILC_COMMAND_MAX
-
- Reserved command. This must not be sent.
-.in 3
-
-
-.ti 0
-2.4 SILC Command Status Payload
-
-Command Status Payload is sent in command reply messages to indicate
-the status of the command. The payload is one of argument in the
-command thus this is the data area in Command Argument Payload described
-in [SILC2]. The payload is only 2 bytes in length. The following
-diagram represents the Command Status Payload (fields are always in
-MSB first order).
-
-
-.in 21
-.nf
- 1
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Status | Error |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 6: SILC Command Status Payload
-
-
-.in 6
-o Status (1 byte) - Indicates the status message type,
- error, start of list, entry of list or end of list.
-
-o Error (1 byte) - Indicates the error if the Status
- field is some list status, which means there are list
- of errors.
-.in 3
-
-The values in Status and Error fields are set according
-the following rules:
-
-.in 6
-o If there is single reply and error has not occurred
- then Status field includes value SILC_STATUS_OK, and
- the Error field MUST be ignored (and set to zero
- value).
-
-o If there is single error, then Status field includes
- one of the error values, and the Error field MUST be
- ignored (and set to zero value).
-
-o If there will be multiple successful command replies
- then Status field includes SILC_STATUS_LIST_START,
- SILC_STATUS_LIST_ITEM or SILC_STATUS_LIST_END value,
- and Error field is set to SILC_STATUS_OK.
-
-o If there are multiple error replies then Status field
- includes SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM
- or SILC_STATUS_LIST_END value, and the Error field
- includes the error value.
-.in 3
-
-This way it is possible to send single successful or
-single error reply, but also multiple successful and
-multiple error replies. Note that it is possible to
-send both list of successful replies and list of error
-replies at the same time, however in this case the
-list of error replies MUST be sent after the successful
-replies. This way the recipient may ignore the multiple
-errors if it wishes to do so. Also note that in this
-case the successful and error replies belong to the
-same list.
-
-All Status messages are described in the next section.
-
-
-.ti 0
-3 SILC Status Types
-
-Status messages are returned in SILC protocol in command reply
-packet and in notify packet. The SILC_PACKET_COMMAND_REPLY is
-the command reply packet and status types are sent inside the
-Status Payload as one of command reply argument, as defined in
-previous sections. For SILC_PACKET_NOTIFY packet they can be sent
-as defined in [SILC2] for SILC_NOTIFY_TYPE_ERROR type. The same
-types defined in this section are used in both cases.
-
-When returning status messages in the command reply message they
-indicate whether the command was executed without errors. If error
-occurred the status indicates which error occurred. If error
-occurred the arguments to the command replies are dictated by the
-error type. If arguments are to be sent, they are defined below
-with the error status types.
-
-When sending status messages in SILC_NOTIFY_TYPE_ERROR notify type
-they always send some error status. Usually they are sent to
-indicate that error occurred while processing some SILC packet.
-Please see the [SILC1] and [SILC2] for more information sending
-status types in SILC_NOTIFY_TYPE_ERROR notify.
-
-The Status Types are only numeric values and the receiver must
-convert the numeric values into human readable messages if this
-is desired in the application.
-
-List of all defined status types:
-
-.in 0
- Generic status messages:
-
- 0 SILC_STATUS_OK
-
- Ok status. Everything went Ok. The status payload maybe
- safely ignored in this case.
-
- 1 SILC_STATUS_LIST_START
-
- Start of the list. There will be several command replies and
- this reply is the start of the list.
-
- 2 SILC_STATUS_LIST_ITEM
-
- Item in the list. This is one of the item in the list but not the
- first or last one.
-
- 3 SILC_STATUS_LIST_END
-
- End of the list. There were several command replies and this
- reply is the last of the list. There won't be other replies
- belonging to this list after this one.
-
- 4 - 9
-
- Currently undefined and has been reserved for the future.
-
-
- Error status message:
-
-
-
- 10 SILC_STATUS_ERR_NO_SUCH_NICK
-
- "No such nickname". Requested nickname does not exist.
- The next argument MUST be the requested nickname.
-
- 11 SILC_STATUS_ERR_NO_SUCH_CHANNEL
-
- "No such channel". Requested channel name does not exist.
- The next argument MUST be the requested channel name.
-
- 12 SILC_STATUS_ERR_NO_SUCH_SERVER
-
- "No such server". Requested server name does not exist.
- The next argument MUST be the requested server name.
-
- 13 SILC_STATUS_ERR_INCOMPLETE_INFORMATION
-
- "Incomplete registration information". Information remote
- sent was incomplete.
-
- 14 SILC_STATUS_ERR_NO_RECIPIENT
-
- "No recipient given". Command required recipient which was
- not provided.
-
- 15 SILC_STATUS_ERR_UNKNOWN_COMMAND
-
- "Unknown command". Command sent to server is unknown by the
- server.
-
- 16 SILC_STATUS_ERR_WILDCARDS
-
- "Wildcards cannot be used". Wildcards were provided but they
- weren't permitted.
-
- 17 SILC_STATUS_ERR_NO_CLIENT_ID
-
- "No Client ID given". Client ID were expected as command
- parameter but were not found.
-
- 18 SILC_STATUS_ERR_NO_CHANNEL_ID
-
- "No Channel ID given". Channel ID were expected as command
- parameter but were not found.
-
- 19 SILC_STATUS_ERR_NO_SERVER_ID
-
- "No Serve ID given". Server ID were expected as command
- parameter but were not found.
-
- 20 SILC_STATUS_ERR_BAD_CLIENT_ID
-
- "Bad Client ID". Client ID provided were erroneous.
- The next argument MUST be the provided ID.
-
- 21 SILC_STATUS_ERR_BAD_CHANNEL_ID
-
- "Bad Channel ID". Channel ID provided were erroneous.
- The next argument MUST be the provided ID.
-
- 22 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
-
- "No such Client ID". Client ID provided does not exist.
- The unknown Client ID MUST be provided as next argument
- in the reply.
-
- 23 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
-
- "No such Channel ID". Channel ID provided does not exist.
- The unknown Channel ID MUST be provided as next argument
- in the reply.
-
- 24 SILC_STATUS_ERR_NICKNAME_IN_USE
-
- "Nickname already exists". Nickname created could not be
- registered because number of same nicknames were already set to
- maximum. This is not expected to happen in real life but is
- possible to occur.
-
- 25 SILC_STATUS_ERR_NOT_ON_CHANNEL
-
- "You are not on that channel". The command were specified for
- channel user is not currently on. The next argument MUST be the
- Channel ID.
-
- 26 SILC_STATUS_ERR_USER_NOT_ON_CHANNEL
-
- "They are not on channel". The requested target client is not
- on requested channel. The next two arguments, in this order,
- MUST be the requested Client ID and Channel ID.
-
- 27 SILC_STATUS_ERR_USER_ON_CHANNEL
-
- "User already on channel". User were invited on channel they
- already are on. The next two arguments, in this order, MUST be
- the requested Client ID and Channel ID.
-
- 28 SILC_STATUS_ERR_NOT_REGISTERED
-
- "You have not registered". User executed command that requires
- the client to be registered on the server before it may be
- executed.
-
- 29 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
-
- "Not enough parameters". Command requires more parameters
- than provided.
-
- 30 SILC_STATUS_ERR_TOO_MANY_PARAMS
-
- "Too many parameters". Too many parameters were provided
- for the command.
-
- 31 SILC_STATUS_ERR_PERM_DENIED
-
- "Permission denied". Generic permission denied error status
- to indicate disallowed access.
-
- 32 SILC_STATUS_ERR_BANNED_FROM_SERVER
-
- "You are banned from this server". The client tried to register
- on server that has explicitly denied this host to connect.
-
- 33 SILC_STATUS_ERR_BAD_PASSWORD
-
- "Cannot join channel. Incorrect password". Password provided for
- channel were not accepted. The next argument MUST be the
- Channel ID.
-
- 34 SILC_STATUS_ERR_CHANNEL_IS_FULL
-
- "Cannot join channel. Channel is full". The channel is full
- and client cannot be joined to it. The next argument MUST be
- the Channel ID.
-
- 35 SILC_STATUS_ERR_NOT_INVITED
-
- "Cannot join channel. You have not been invited". The channel
- is invite only channel and client has not been invited. The next
- argument MUST be the Channel ID.
-
- 36 SILC_STATUS_ERR_BANNED_FROM_CHANNEL
-
- "Cannot join channel. You have been banned". The client has
- been banned from the channel. The next argument MUST be the
- Channel ID.
-
- 37 SILC_STATUS_ERR_UNKNOWN_MODE
-
- "Unknown mode". Mode provided by the client were unknown to
- the server.
-
- 38 SILC_STATUS_ERR_NOT_YOU
-
- "Cannot change mode for other users". User tried to change
- someone else's mode.
-
- 39 SILC_STATUS_ERR_NO_CHANNEL_PRIV
-
- "Permission denied. You are not channel operator". Command may
- be executed only by channel operator. The next argument MUST be
- the Channel ID.
-
- 40 SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
-
- "Permission denied. You are not channel founder". Command may
- be executed only by channel operator. The next argument MUST be
- the Channel ID.
-
- 41 SILC_STATUS_ERR_NO_SERVER_PRIV
-
- "Permission denied. You are not server operator". Command may
- be executed only by server operator.
-
- 42 SILC_STATUS_ERR_NO_ROUTER_PRIV
-
- "Permission denied. You are not SILC operator". Command may be
- executed only by router (SILC) operator.
-
- 43 SILC_STATUS_ERR_BAD_NICKNAME
-
- "Bad nickname". Nickname requested contained illegal characters
- or were malformed.
-
- 44 SILC_STATUS_ERR_BAD_CHANNEL
-
- "Bad channel name". Channel requested contained illegal characters
- or were malformed.
-
- 45 SILC_STATUS_ERR_AUTH_FAILED
-
- "Authentication failed". The authentication data sent as
- argument were wrong and thus authentication failed.
-
- 46 SILC_STATUS_ERR_UNKOWN_ALGORITHM
-
- "The algorithm was not supported." The server does not support the
- requested algorithm. The next argument MUST be the algorithm name
- string.
-
- 47 SILC_STATUS_ERR_NO_SUCH_SERVER_ID
-
- "No such Server ID". Server ID provided does not exist.
- The unknown Server ID MUST be provided as next argument
- in the reply.
-
- 48 SILC_STATUS_ERR_RESOURCE_LIMIT
-
- "No more resources available". This can mean that server cannot
- or will not accept something due to resource limitations.
-
- 49 SILC_STATUS_ERR_NO_SUCH_SERVICE
-
- "Service does not exist". Requested service identifier is
- unknown. The next argument MUST be the service identifier.
-
- 50 SILC_STATUS_ERR_NOT_AUTHENTICATED
-
- "You have not been authenticated". Remote connection is not
- authenticated even though it is supposed to be.
-
- 51 SILC_STATUS_ERR_BAD_SERVER_ID
-
- "Server ID is not valid". Provided server ID is not valid.
- The next argument MUST be the provided ID.
-
- 52 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED
-
- "Key exchange failed". Key Exchange protocol failed.
-
- 53 SILC_STATUS_ERR_BAD_VERSION
-
- "Bad version". Protocol or software version mismatch.
-
- 54 SILC_STATUS_ERR_TIMEDOUT
-
- "Operation timed out". Operation or service request timed
- out, and thus was not processed.
-
- 55 SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY
-
- "Unsupported public key type". The public key or certificate
- type is not supported in this implementation.
-
- 56 SILC_STATUS_ERR_OPERATION_ALLOWED
-
- "Operation is not allowed". A operation, for example a command,
- is not allowed or it's execution is not allowed.
-
-.in 3
-
-
-
-.ti 0
-4 Security Considerations
-
-Security is central to the design of this protocol, and these security
-considerations permeate the specification. Common security considerations
-such as keeping private keys truly private and using adequate lengths for
-symmetric and asymmetric keys must be followed in order to maintain the
-security of this protocol.
-
-
-.ti 0
-5 References
-
-[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
- Protocol Specification", Internet Draft, January 2007.
-
-[SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft,
- January 2007.
-
-[SILC3] Riikonen, P., "SILC Key Exchange and Authentication
- Protocols", Internet Draft, January 2007.
-
-[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
- RFC 1459, May 1993.
-
-[IRC-ARCH] Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
- April 2000.
-
-[IRC-CHAN] Kalt, C., "Internet Relay Chat: Channel Management", RFC
- 2811, April 2000.
-
-[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
- 2812, April 2000.
-
-[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
- 2813, April 2000.
-
-[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
- Internet Draft.
-
-[PGP] Callas, J., et al, "OpenPGP Message Format", RFC 2440,
- November 1998.
-
-[SPKI] Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
- September 1999.
-
-[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
- Infrastructure, Certificate and CRL Profile", RFC 2459,
- January 1999.
-
-[Schneier] Schneier, B., "Applied Cryptography Second Edition",
- John Wiley & Sons, New York, NY, 1996.
-
-[Menezes] Menezes, A., et al, "Handbook of Applied Cryptography",
- CRC Press 1997.
-
-[OAKLEY] Orman, H., "The OAKLEY Key Determination Protocol",
- RFC 2412, November 1998.
-
-[ISAKMP] Maughan D., et al, "Internet Security Association and
- Key Management Protocol (ISAKMP)", RFC 2408, November
- 1998.
-
-[IKE] Harkins D., and Carrel D., "The Internet Key Exchange
- (IKE)", RFC 2409, November 1998.
-
-[HMAC] Krawczyk, H., "HMAC: Keyed-Hashing for Message
- Authentication", RFC 2104, February 1997.
-
-[PKCS1] Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
- Specifications, Version 2.0", RFC 2437, October 1998.
-
-[RFC2119] Bradner, S., "Key Words for use in RFCs to Indicate
- Requirement Levels", BCP 14, RFC 2119, March 1997.
-
-[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
- 10646", RFC 3629, November 2003.
-
-[ATTRS] Riikonen, P., "User Online Presence and Information
- Attributes", Internet Draft, May 2002.
-
-
-.ti 0
-6 Author's Address
-
-.nf
-Pekka Riikonen
-Helsinki
-Finland
-
-EMail: priikone@iki.fi
-
-
-.ti 0
-Appendix A
-
-This appendix defines the usage of the <Requested Attributes> argument in
-the SILC_COMMAND_WHOIS command. The attributes are defined in [ATTRS],
-and may be used to request additional information about the user. Since
-the information that may be requested using the attributes is something
-that server cannot deliver to the sender, it is possible to send the WHOIS
-command directly to the destination client whom will then provide the
-requested attributes. This requires the servers to relay the WHOIS
-command to the client, and it requires capability for handling the WHOIS
-command in the client end.
-
-The <Requested Attributes> MAY include several attributes that are
-requested. The format and encoding of the <Requested Attributes> is as
-defined in [ATTRS]. When <Requested Attributes> argument is set the
-server MAY process the attributes to see whether it can narrow down
-the WHOIS search, for example when searching with a nickname. The
-normal servers MUST process the WHOIS command as normal WHOIS command,
-that is to send the command directly to the router. The router MAY
-process the attributes, but it MUST send the command to the server
-that owns the requested client.
-
-The server that owns the client and receives the command MUST check
-whether the client is detached from the network. If it is detached,
-that is the user mode has the SILC_UMODE_DETACHED mode set, it SHOULD
-process the attributes and provide as many of the requested attributes
-as possible and then send reply back to the sender. If the client is
-active in the network it MUST send the command to the client for
-processing.
-
-The client receiving WHOIS command SHOULD check whether the
-<Requested Attributes> argument is set. If it is not set then the
-WHOIS command SHOULD be discarded. The client processes the requested
-attributes and SHOULD reply to each of the requested attribute with
-either valid value, or with an indication that the requested attribute
-is not known or supported. This is to be done as defined in [ATTRS].
-The client always MUST send a reply to the command when some attributes
-were requested. The client MAY also add additional attributes to the
-reply even if they were not requested. The client MAY also digitally
-sign the attributes with ATTRIBUTE_USER_DIGITAL_SIGNATURE as defined
-in [ATTRS]. Then the client sends the reply back to the sender of
-the command. The command reply that client assembles does not need
-to include any other argument but the <Status Payload> (1), and the
-<Attributes> (11). The server receiving reply from client MUST allow
-this sort of command reply for WHOIS command.
-
-The information received from the client MAY be cached in the
-server's end. The caching may be desired for example if the client
-can be detached from the network. This way the server is then able
-to provide at least partial information for a requester. The
-server MAY also process the command reply and verify whether the
-attributes provided in the reply are actually valid. If it can do
-this, and verify that they indeed are valid values it MAY append
-a digital signature at the end of the attributes with the
-ATTRIBUTE_SERVER_DIGITAL_SIGNATURE as defined in [ATTRS]. The
-server then MUST provide valid WHOIS command reply to the sender
-of the command. Other servers and routers that receive the command
-reply en route to the original sender MAY also cache the information.
-
-The client which receives the command reply to the WHOIS command
-SHOULD verify the ATTRIBUTE_USER_DIGITAL_SIGNATURE and the
-ATTRIBUTE_SERVER_DIGITAL_SIGNATURE if they are provided.
-
-
-.ti 0
-Full Copyright Statement
-
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
-
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
<draft-riikonen-flags-payloads-04.txt>
.ti 0
-Status of this Draft
+Status of this Memo
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026. Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups. Note that other groups may also
+distribute working documents as Internet-Drafts.
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
+http://www.ietf.org/ietf/1id-abstracts.txt
+
The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
.ti 0
.ti 0
7 Full Copyright Statement
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
-
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+++ /dev/null
-.pl 10.0i
-.po 0
-.ll 7.2i
-.lt 7.2i
-.nr LL 7.2i
-.nr LT 7.2i
-.ds LF Riikonen
-.ds RF FORMFEED[Page %]
-.ds CF
-.ds LH Internet-Draft
-.ds RH 15 January 2007
-.ds CH
-.na
-.hy 0
-.in 0
-.nf
-Network Working Group P. Riikonen
-Internet-Draft
-draft-riikonen-silc-ke-auth-09.txt 15 January 2007
-Expires: 15 July 2007
-
-.in 3
-
-.ce 2
-SILC Key Exchange and Authentication Protocols
-<draft-riikonen-silc-ke-auth-09.txt>
-
-.ti 0
-Status of this Draft
-
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
-
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
-
-The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
-The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
-
-
-.ti 0
-Abstract
-
-This memo describes two protocols used in the Secure Internet Live
-Conferencing (SILC) protocol, specified in the Secure Internet Live
-Conferencing, Protocol Specification [SILC1]. The SILC Key Exchange
-(SKE) protocol provides secure key exchange between two parties
-resulting into shared secret key material. The protocol is based
-on Diffie-Hellman key exchange algorithm and its functionality is
-derived from several key exchange protocols.
-
-The second protocol, SILC Connection Authentication protocol provides
-user level authentication used when creating connections in SILC
-network. The protocol supports passphrase (pre-shared secret)
-authentication and public key (and certificate) authentication based
-on digital signatures.
-
-
-
-.ti 0
-Table of Contents
-
-.nf
-1 Introduction .................................................. 2
- 1.1 Requirements Terminology .................................. 3
-2 SILC Key Exchange Protocol .................................... 3
- 2.1 Key Exchange Payloads ..................................... 4
- 2.1.1 Key Exchange Start Payload .......................... 4
- 2.1.2 Key Exchange Payload ................................ 9
- 2.2 Key Exchange Procedure .................................... 11
- 2.3 Processing the Key Material ............................... 13
- 2.4 SILC Key Exchange Groups .................................. 15
- 2.4.1 diffie-hellman-group1 ............................... 15
- 2.4.2 diffie-hellman-group2 ............................... 15
- 2.4.3 diffie-hellman-group3 ............................... 16
- 2.5 Key Exchange Status Types ................................. 16
-3 SILC Connection Authentication Protocol ....................... 18
- 3.1 Connection Auth Payload ................................... 19
- 3.2 Connection Authentication Types ........................... 20
- 3.2.1 Passphrase Authentication ........................... 20
- 3.2.2 Public Key Authentication ........................... 21
- 3.3 Connection Authentication Status Types .................... 21
-4 Security Considerations ....................................... 22
-5 References .................................................... 22
-6 Author's Address .............................................. 23
-7 Full Copyright Statement ...................................... 24
-
-
-.ti 0
-List of Figures
-
-.nf
-Figure 1: Key Exchange Start Payload
-Figure 2: Key Exchange Payload
-Figure 3: Connection Auth Payload
-
-
-.ti 0
-1 Introduction
-
-This memo describes two protocols used in the Secure Internet Live
-Conferencing (SILC) protocol specified in the Secure Internet Live
-Conferencing, Protocol Specification [SILC1]. The SILC Key Exchange
-(SKE) protocol provides secure key exchange between two parties
-resulting into shared secret key material. The protocol is based on
-Diffie-Hellman key exchange algorithm and its functionality is derived
-from several key exchange protocols, such as SSH2 Key Exchange protocol,
-Station-To-Station (STS) protocol and the OAKLEY Key Determination
-protocol [OAKLEY].
-
-The second protocol, SILC Connection Authentication protocol provides
-user level authentication used when creating connections in SILC
-network. The protocol supports passphrase (pre-shared secret)
-authentication and public key (and certificate) authentication based
-on digital signatures.
-
-The basis of secure SILC session requires strong and secure key exchange
-protocol and authentication. The authentication protocol is secured and
-no authentication data is ever sent in the network without encrypting
-and authenticating it first. Thus, authentication protocol may be used
-only after the key exchange protocol has been successfully completed.
-
-This document constantly refers to other SILC protocol specifications
-that should be read to be able to fully understand the functionality
-and purpose of these protocols. The most important references are
-the Secure Internet Live Conferencing, Protocol Specification [SILC1]
-and the SILC Packet Protocol [SILC2].
-
-The protocol is intended to be used with the SILC protocol thus it
-does not define own framework that could be used. The framework is
-provided by the SILC protocol.
-
-
-.ti 0
-1.1 Requirements Terminology
-
-The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
-MAY, and OPTIONAL, when they appear in this document, are to be
-interpreted as described in [RFC2119].
-
-
-.ti 0
-2 SILC Key Exchange Protocol
-
-SILC Key Exchange Protocol (SKE) is used to exchange shared secret
-material used to secure the communication channel. The protocol use
-Diffie-Hellman key exchange algorithm and its functionality is derived
-from several key exchange protocols, such as SSH2 Key Exchange protocol,
-Station-To-Station (STS) protocol and the OAKLEY Key Determination
-protocol [OAKLEY]. The protocol does not claim any conformance
-to any of these protocols, they were only used as a reference when
-designing this protocol. The protocol can mutually authenticate the
-negotiating parties during the key exchange.
-
-The purpose of SILC Key Exchange protocol is to create session keys to
-be used in current SILC session. The keys are valid only for some period
-of time (usually an hour) or at most until the session ends. These keys
-are used to protect packets traveling between the two entities.
-Usually all traffic is secured with the key material derived from this
-protocol.
-
-The Diffie-Hellman implementation used in the SILC SHOULD be compliant
-to the PKCS #3.
-
-
-.ti 0
-2.1 Key Exchange Payloads
-
-During the key exchange procedure public data is sent between initiator
-and responder. This data is later used in the key exchange procedure.
-There are several payloads used in the key exchange. As for all SILC
-packets, SILC Packet Header, described in [SILC2], is at the beginning
-of all packets sent in during this protocol. All the fields in the
-following payloads are in MSB (most significant byte first) order.
-
-
-.ti 0
-2.1.1 Key Exchange Start Payload
-
-The key exchange between two entities MUST be started by sending the
-SILC_PACKET_KEY_EXCHANGE packet containing Key Exchange Start Payload.
-Initiator sends the Key Exchange Start Payload to the responder filled
-with all security properties it supports. The responder then checks
-whether it supports the security properties.
-
-It then sends a Key Exchange Start Payload to the initiator filled with
-security properties it selected from the original payload. The payload
-sent by responder MUST include only one chosen property per list. The
-character encoding for the security property values as defined in [SILC1]
-SHOULD be UTF-8 [RFC2279] in Key Exchange Start Payload.
-
-The Key Exchange Start Payload is used to tell connecting entities what
-security properties and algorithms should be used in the communication.
-The Key Exchange Start Payload is sent only once per session. Even if
-the PFS (Perfect Forward Secrecy) flag is set the Key Exchange Start
-Payload is not re-sent. When PFS is desired the Key Exchange Payloads
-are sent to negotiate new key material. The procedure is equivalent to
-the very first negotiation except that the Key Exchange Start Payload
-is not sent.
-
-As this payload is used only with the very first key exchange the payload
-is never encrypted, as there are no keys to encrypt it with.
-
-A cookie is also sent in this payload. A cookie is used to randomize the
-payload so that none of the key exchange parties can determine this
-payload before the key exchange procedure starts. The cookie MUST be
-returned to the original sender unmodified by the responder.
-
-Following diagram represents the Key Exchange Start Payload. The lists
-mentioned below are always comma (`,') separated and the list MUST NOT
-include white spaces (` ').
-
-
-.in 5
-.nf
- 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| RESERVED | Flags | Payload Length |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| |
-+ +
-| |
-+ Cookie +
-| |
-+ +
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Version String Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Version String ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Key Exchange Grp Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Key Exchange Groups ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| PKCS Alg Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ PKCS Algorithms ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Encryption Alg Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Encryption Algorithms ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Hash Alg Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Hash Algorithms ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| HMAC Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ HMACs ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Compression Alg Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Compression Algorithms ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 1: Key Exchange Start Payload
-
-
-.in 6
-o RESERVED (1 byte) - Reserved field. Sender fills this with
- zero (0) value.
-
-o Flags (1 byte) - Indicates flags to be used in the key
- exchange. Several flags can be set at once by ORing the
- flags together. The following flags are reserved for this
- field:
-
- No flags 0x00
-
- In this case the field is ignored.
-
- IV Included 0x01
-
- This flag is used to indicate that Initialization
- Vector (IV) in encryption will be included in the
- ciphertext which the recipient must use in decryption.
- At the beginning of the SILC packet, before the SILC
- Packet header an 8-bit Security ID (SID) MUST be
- placed. After the SID, the IV MUST be placed. After
- the IV, a 32-bit MSB first ordered packet sequence
- number MUST be placed. The SID and IV MUST NOT be
- encrypted, but the sequence number MUST be included
- in encryption. The recipient MUST use the sequence
- number during MAC verification [SILC2]. All fields
- however are authenticated with MAC.
-
- The Security ID is set to value 0 when the key
- exchange is performed for the first time. It is
- monotonically increased after each re-key, wrapping
- eventually. The SID in combination with the current
- session can be used to identify which key has been
- used to encrypt an incoming packet. This is especially
- important after rekey when using UDP/IP protocol,
- where packets may be lost or reordered. A packet with
- unknown SID will result into discarding the packet as
- it cannot be decrypted. After rekey, implementation
- should understand that it may still receive packets
- with old SID and be prepared to decrypt them with the
- old key.
-
- With this flag it is possible to use SILC protocol on
- unreliable transport such as UDP/IP which may cause
- packet reordering and packet losses. By default,
- this flag is not set and thus IV is not included
- in the ciphertext. Setting this flag increases the
- packet length by one ciphertext block plus 1 byte for
- the Security ID and 32 bits for the sequence number.
- Responder MAY override this flag for the initiator,
- however without this flag UDP connection cannot be
- used. The flag MAY also be used in TCP connection.
-
- When using with UDP/IP implementations SHOULD use
- anti-replay methods where an anti-replay window
- defines what packets are replays. An example of
- anti-window protocol is in [RFC2406] Section 3.4.2
- with example source code in [RFC2401] Appendix C.
- While [RFC2401] and [RFC2406] does not relate to SILC,
- the anti-replay method used is applicable in SILC.
-
- PFS 0x02
-
- Perfect Forward Secrecy (PFS) to be used in the
- key exchange protocol. If not set, re-keying
- is performed using the old key. See the [SILC1]
- for more information on this issue. When PFS is
- used, re-keying and creating new keys for any
- particular purpose MUST cause new key exchange with
- new Diffie-Hellman exponent values. In this key
- exchange only the Key Exchange Payload is sent and
- the Key Exchange Start Payload MUST NOT be sent.
- When doing PFS the Key Exchange Payloads are
- encrypted with the old keys.
-
- Mutual Authentication 0x04
-
- Both of the parties will perform authentication
- by providing signed data for the other party to
- verify. By default, only responder will provide
- the signature data. If this is set then the
- initiator must also provide it. Initiator MAY
- set this but also responder MAY set this even if
- initiator did not set it.
-
- Rest of the flags are reserved for the future and
- MUST NOT be set.
-
-o Payload Length (2 bytes) - Length of the entire Key Exchange
- Start payload, not including any other field.
-
-o Cookie (16 bytes) - Cookie that randomize this payload so
- that each of the party cannot determine the payload before
- hand. This field MUST be present.
-
-o Version String Length (2 bytes) - The length of the Version
- String field, not including any other field.
-
-o Version String (variable length) - Indicates the version of
- the sender of this payload. Initiator sets this when sending
- the payload and responder sets this when it replies by sending
- this payload. See [SILC1] for definition for the version
- string format. This field MUST be present and include valid
- version string.
-
-o Key Exchange Grp Length (2 bytes) - The length of the
- key exchange group list, not including any other field.
-
-o Key Exchange Group (variable length) - The list of
- key exchange groups. See the section 2.4 SILC Key Exchange
- Groups for definitions of these groups. This field MUST
- be present.
-
-o PKCS Alg Length (2 bytes) - The length of the PKCS algorithms
- list, not including any other field.
-
-o PKCS Algorithms (variable length) - The list of PKCS
- algorithms. This field MUST be present.
-
-o Encryption Alg Length (2 bytes) - The length of the encryption
- algorithms list, not including any other field.
-
-o Encryption Algorithms (variable length) - The list of
- encryption algorithms. This field MUST be present.
-
-o Hash Alg Length (2 bytes) - The length of the Hash algorithm
- list, not including any other field.
-
-o Hash Algorithms (variable length) - The list of Hash
- algorithms. The hash algorithms are mainly used in the
- SKE protocol. This field MUST be present.
-
-o HMAC Length (2 bytes) - The length of the HMAC list, not
- including any other field.
-
-o HMACs (variable length) - The list of HMACs. The HMAC's
- are used to compute the Message Authentication Code (MAC)
- of the SILC packets. This field MUST be present.
-
-o Compression Alg Length (2 bytes) - The length of the
- compression algorithms list, not including any other field.
-
-o Compression Algorithms (variable length) - The list of
- compression algorithms. This field MAY be omitted.
-.in 3
-
-
-.ti 0
-2.1.2 Key Exchange Payload
-
-Key Exchange payload is used to deliver the public key (or certificate),
-the computed Diffie-Hellman public value and possibly signature data
-from one party to the other. When initiator is using this payload
-and the Mutual Authentication flag is not set then the initiator MUST
-NOT provide the signature data. If the flag is set then the initiator
-MUST provide the signature data so that the responder can verify it.
-
-The Mutual Authentication flag is usually used when a separate
-authentication protocol will not be executed for the initiator of the
-protocol. This is case for example when the SKE is performed between
-two SILC clients. In normal case, where client is connecting to a
-server, or server is connecting to a router the Mutual Authentication
-flag MAY be omitted. However, if the connection authentication protocol
-for the connecting entity is not based on digital signatures (it is
-based on pre-shared key or there is no authentication) then the Mutual
-Authentication flag SHOULD be enabled. This way the connecting entity
-has to provide proof of possession of the private key for the public key
-it will provide in this protocol.
-
-When performing re-key with PFS selected this is the only payload that
-is sent in the SKE protocol. The Key Exchange Start Payload MUST NOT
-be sent at all. However, this payload does not have all the fields
-present. In the re-key with PFS the public key and a possible signature
-data SHOULD NOT be present. If they are present they MUST be ignored.
-The only field that is present is the Public Data that is used to create
-the new key material. In the re-key the Mutual Authentication flag, that
-may be set in the initial negotiation, MUST also be ignored.
-
-This payload is sent inside SILC_PACKET_KEY_EXCHANGE_1 and inside
-SILC_PACKET_KEY_EXCHANGE_2 packet types. The initiator uses the
-SILC_PACKET_KEY_EXCHANGE_1 and the responder the latter.
-
-The following diagram represent the Key Exchange Payload.
-
-
-.in 5
-.nf
- 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Public Key Length | Public Key Type |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| |
-~ Public Key of the party (or certificate) ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Public Data Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Public Data ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Signature Length | |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
-| |
-~ Signature Data ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 2: Key Exchange Payload
-
-
-.in 6
-o Public Key Length (2 bytes) - The length of the Public Key
- (or certificate) field, not including any other field.
-
-o Public Key Type (2 bytes) - The public key (or certificate)
- type. This field indicates the type of the public key in
- the packet. Following types are defined:
-
- 1 SILC style public key (mandatory)
- 2 SSH2 style public key (optional)
- 3 X.509 Version 3 certificate (optional)
- 4 OpenPGP certificate (optional)
- 5 SPKI certificate (optional)
-
- The only required type to support is type number 1. See
- [SILC1] for the SILC public key specification. See
- SSH2 public key specification in [SSH-TRANS]. See X.509v3
- certificate specification in [PKIX-Part1]. See OpenPGP
- certificate specification in [PGP]. See SPKI certificate
- specification in [SPKI]. If this field includes zero (0)
- or unsupported type number the protocol MUST be aborted
- sending SILC_PACKET_FAILURE message and the connection SHOULD
- be closed immediately.
-
-o Public Key (or certificate) (variable length) - The
- public key or certificate of the party. This public key
- may be used to verify the digital signature. The public key
- or certificate in this field is encoded in the manner as
- defined in their respective definitions; see previous field.
-
-o Public Data Length (2 bytes) - The length of the Public Data
- field, not including any other field.
-
-o Public Data (variable length) - The public data to be
- sent to the receiver (computed Diffie-Hellman public values).
- See section 2.2 Key Exchange Procedure for detailed description
- how this field is computed. This field is MP integer and is
- encoded as defined in [SILC1].
-
-o Signature Length (2 bytes) - The length of the signature,
- not including any other field.
-
-o Signature Data (variable length) - The signature signed
- by the sender. The receiver of this signature MUST
- verify it. The verification is done using the sender's
- public key. See section 2.2 Key Exchange Procedure for
- detailed description how to produce the signature. If
- the Mutual Authentication flag is not set then initiator
- MUST NOT provide this field and the Signature Length field
- MUST be set to zero (0) value. If the flag is set then
- also the initiator MUST provide this field. The responder
- always MUST provide this field. The encoding for signature
- is defined in [SILC1].
-.in 3
-
-
-
-.ti 0
-2.2 Key Exchange Procedure
-
-The key exchange begins by sending SILC_PACKET_KEY_EXCHANGE packet with
-Key Exchange Start Payload to select the security properties to be used
-in the key exchange and later in the communication.
-
-After Key Exchange Start Payload has been processed by both of the
-parties the protocol proceeds as follows:
-
-
-Setup: p is a large and public safe prime. This is one of the
- Diffie Hellman groups. q is order of subgroup (largest
- prime factor of p). g is a generator and is defined
- along with the Diffie Hellman group.
-
- 1. Initiator generates a random number x, where 1 < x < q,
- and computes e = g ^ x mod p. The result e is then
- encoded into Key Exchange Payload, with the public key
- (or certificate) and sent to the responder.
-
- If the Mutual Authentication flag is set then initiator
- MUST also produce signature data SIGN_i which the responder
- will verify. The initiator MUST compute a hash value
- HASH_i = hash(Initiator's Key Exchange Start Payload |
- public key (or certificate) | e). The '|' stands for
- concatenation. It then signs the HASH_i value with its
- private key resulting a signature SIGN_i.
-
- 2. Responder generates a random number y, where 1 < y < q,
- and computes f = g ^ y mod p. It then computes the
- shared secret KEY = e ^ y mod p, and, a hash value
- HASH = hash(Initiator's Key Exchange Start Payload |
- public key (or certificate) | Initiator's public key
- (or certificate) | e | f | KEY). It then signs
- the HASH value with its private key resulting a signature
- SIGN.
-
- It then encodes its public key (or certificate), f and
- SIGN into Key Exchange Payload and sends it to the
- initiator.
-
- If the Mutual Authentication flag is set then the responder
- SHOULD verify that the public key provided in the payload
- is authentic, or if certificates are used it verifies the
- certificate. The responder MAY accept the public key without
- verifying it, however, doing so may result to insecure key
- exchange (accepting the public key without verifying may be
- desirable for practical reasons on many environments. For
- long term use this is never desirable, in which case
- certificates would be the preferred method to use). It then
- computes the HASH_i value the same way initiator did in the
- phase 1. It then verifies the signature SIGN_i from the
- payload with the hash value HASH_i using the received public
- key.
-
- 3. Initiator verifies that the public key provided in
- the payload is authentic, or if certificates are used
- it verifies the certificate. The initiator MAY accept
- the public key without verifying it, however, doing
- so may result to insecure key exchange (accepting the
- public key without verifying may be desirable for
- practical reasons on many environments. For long term
- use this is never desirable, in which case certificates
- would be the preferred method to use).
-
- Initiator then computes the shared secret KEY =
- f ^ x mod p, and, a hash value HASH in the same way as
- responder did in phase 2. It then verifies the
- signature SIGN from the payload with the hash value
- HASH using the received public key.
-
-
-If any of these phases is to fail the SILC_PACKET_FAILURE MUST be sent
-to indicate that the key exchange protocol has failed, and the connection
-SHOULD be closed immediately. Any other packets MUST NOT be sent or
-accepted during the key exchange except the SILC_PACKET_KEY_EXCHANGE_*,
-SILC_PACKET_FAILURE and SILC_PACKET_SUCCESS packets.
-
-The result of this protocol is a shared secret key material KEY and
-a hash value HASH. The key material itself is not fit to be used as
-a key, it needs to be processed further to derive the actual keys to be
-used. The key material is also used to produce other security parameters
-later used in the communication. See section 2.3 Processing the Key
-Material for detailed description how to process the key material.
-
-If the Mutual Authentication flag was set the protocol produces also
-a hash value HASH_i. This value, however, must be discarded.
-
-After the keys are processed the protocol is ended by sending the
-SILC_PACKET_SUCCESS packet. Both entities send this packet to
-each other. After this both parties MUST start using the new keys.
-
-
-.ti 0
-2.3 Processing the Key Material
-
-Key Exchange protocol produces secret shared key material KEY. This
-key material is used to derive the actual keys used in the encryption
-of the communication channel. The key material is also used to derive
-other security parameters used in the communication. Key Exchange
-protocol produces a hash value HASH as well.
-
-The keys MUST be derived from the key material as follows:
-
-.in 6
-Sending Initial Vector (IV) = hash(0x0 | KEY | HASH)
-Receiving Initial Vector (IV) = hash(0x1 | KEY | HASH)
-Sending Encryption Key = hash(0x2 | KEY | HASH)
-Receiving Encryption Key = hash(0x3 | KEY | HASH)
-Sending HMAC Key = hash(0x4 | KEY | HASH)
-Receiving HMAC Key = hash(0x5 | KEY | HASH)
-.in 3
-
-
-The Initial Vector (IV) is used in the encryption when doing for
-example CBC mode. As many bytes as needed are taken from the start of
-the hash output for IV. Sending IV is for sending key and receiving IV
-is for receiving key. For receiving party, the receiving IV is actually
-sender's sending IV, and, the sending IV is actually sender's receiving
-IV. Initiator uses IV's as they are (sending IV for sending and
-receiving IV for receiving).
-
-The Encryption Keys are derived as well from the hash(). If the hash()
-output is too short for the encryption algorithm more key material MUST
-be produced in the following manner:
-
-.in 6
-K1 = hash(0x2 | KEY | HASH)
-K2 = hash(KEY | HASH | K1)
-K3 = hash(KEY | HASH | K1 | K2) ...
-
-Sending Encryption Key = K1 | K2 | K3 ...
-
-
-K1 = hash(0x3 | KEY | HASH)
-K2 = hash(KEY | HASH | K1)
-K3 = hash(KEY | HASH | K1 | K2) ...
-
-Receiving Encryption Key = K1 | K2 | K3 ...
-.in 3
-
-
-The key is distributed by hashing the previous hash with the original
-key material. The final key is a concatenation of the hash values.
-For Receiving Encryption Key the procedure is equivalent. Sending key
-is used only for encrypting data to be sent. The receiving key is used
-only to decrypt received data. For receiving party, the receive key is
-actually sender's sending key, and, the sending key is actually sender's
-receiving key. Initiator uses generated keys as they are (sending key
-for sending and receiving key for receiving).
-
-The HMAC keys are used to create MAC values to packets in the
-communication channel. As many bytes as needed are taken from the start
-of the hash output to generate the MAC keys.
-
-These procedures are performed by all parties of the key exchange
-protocol. This MUST be done before the protocol has been ended by
-sending the SILC_PACKET_SUCCESS packet, to assure that parties can
-successfully process the key material.
-
-This same key processing procedure MAY be used in the SILC in some
-other circumstances as well. Any changes to this procedure is defined
-separately when this procedure is needed. See the [SILC1] and the
-[SILC2] for these circumstances.
-
-
-.ti 0
-2.4 SILC Key Exchange Groups
-
-The Following groups may be used in the SILC Key Exchange protocol.
-The first group diffie-hellman-group1 is REQUIRED, other groups MAY be
-negotiated to be used in the connection with Key Exchange Start Payload
-and SILC_PACKET_KEY_EXCHANGE packet. However, the first group MUST be
-proposed in the Key Exchange Start Payload regardless of any other
-requested group (however, it does not have to be the first in the list).
-
-
-.ti 0
-2.4.1 diffie-hellman-group1
-
-The length of this group is 1024 bits. This is REQUIRED group.
-The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
-
-Its hexadecimal value is
-
-.in 6
-FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
-29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
-EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
-E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
-EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
-FFFFFFFF FFFFFFFF
-.in 3
-
-
-The generator used with this prime is g = 2. The group order q is
-(p - 1) / 2.
-
-This group was taken from RFC 2412.
-
-
-.ti 0
-2.4.2 diffie-hellman-group2
-
-The length of this group is 1536 bits. This is OPTIONAL group.
-The prime is 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }.
-
-Its hexadecimal value is
-
-.in 6
-FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
-29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
-EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
-E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
-EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
-C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
-83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
-670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
-.in 3
-
-The generator used with this prime is g = 2. The group order q is
-(p - 1) / 2.
-
-This group was taken from RFC 3526.
-
-
-.ti 0
-2.4.3 diffie-hellman-group3
-
-The length of this group is 2048 bits. This is OPTIONAL group.
-This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }.
-
-Its hexadecimal value is
-
-.in 6
-FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
-29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
-EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
-E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
-EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
-C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
-83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
-670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
-E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
-DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
-15728E5A 8AACAA68 FFFFFFFF FFFFFFFF
-.in 3
-
-The generator used with this prime is g = 2. The group order q is
-(p - 1) / 2.
-
-This group was taken from RFC 3526.
-
-Additional larger groups are defined in RFC 3526 and may be used in SKE
-by defining name for them using the above name format.
-
-
-.ti 0
-2.5 Key Exchange Status Types
-
-This section defines all key exchange protocol status types that may
-be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
-to indicate the status of the protocol. Implementations may map the
-status types to human readable error message. All types except the
-SILC_SKE_STATUS_OK type MUST be sent in SILC_PACKET_FAILURE packet.
-The length of status is 32 bits (4 bytes). The following status types
-are defined:
-
-.in 6
-0 SILC_SKE_STATUS_OK
-
- Protocol were executed successfully.
-
-
-1 SILC_SKE_STATUS_ERROR
-
- Unknown error occurred. No specific error type is defined.
-
-
-2 SILC_SKE_STATUS_BAD_PAYLOAD
-
- Provided KE payload were malformed or included bad fields.
-
-
-3 SILC_SKE_STATUS_UNSUPPORTED_GROUP
-
- None of the provided groups were supported.
-
-
-4 SILC_SKE_STATUS_UNSUPPORTED_CIPHER
-
- None of the provided ciphers were supported.
-
-
-5 SILC_SKE_STATUS_UNSUPPORTED_PKCS
-
- None of the provided public key algorithms were supported.
-
-
-6 SILC_SKE_STATUS_UNSUPPORTED_HASH_FUNCTION
-
- None of the provided hash functions were supported.
-
-
-7 SILC_SKE_STATUS_UNSUPPORTED_HMAC
-
- None of the provided HMACs were supported.
-
-
-8 SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY
-
- Provided public key type is not supported.
-
-
-9 SILC_SKE_STATUS_INCORRECT_SIGNATURE
-
- Provided signature was incorrect.
-
-
-10 SILC_SKE_STATUS_BAD_VERSION
-
- Provided version string was not acceptable.
-
-
-11 SILC_SKE_STATUS_INVALID_COOKIE
-
- The cookie in the Key Exchange Start Payload was malformed,
- because responder modified the cookie.
-.in 3
-
-
-.ti 0
-3 SILC Connection Authentication Protocol
-
-Purpose of Connection Authentication protocol is to authenticate the
-connecting party with server. Usually connecting party is client but
-server may connect to router server as well. Its other purpose is to
-provide information for the server about which type of entity the
-connection is. The type defines whether the connection is client,
-server or router connection. Server use this information to create the
-ID for the connection.
-
-Server MUST verify the authentication data received and if it is to fail
-the authentication MUST be failed by sending SILC_PACKET_FAILURE packet.
-If authentication is successful the protocol is ended by server by sending
-SILC_PACKET_SUCCESS packet.
-
-The protocol is executed after the SILC Key Exchange protocol. It MUST
-NOT be executed in any other time. As it is performed after key exchange
-protocol all traffic in the connection authentication protocol is
-encrypted with the exchanged keys.
-
-The protocol MUST be started by the connecting party by sending the
-SILC_PACKET_CONNECTION_AUTH packet with Connection Auth Payload,
-described in the next section. This payload MUST include the
-authentication data. The authentication data is set according
-authentication method that MUST be known by both parties. If connecting
-party does not know what is the mandatory authentication method it MAY
-request it from the server by sending SILC_PACKET_CONNECTION_AUTH_REQUEST
-packet. This packet is not part of this protocol and is described in
-section Connection Auth Request Payload in [SILC2]. However, if
-connecting party already knows the mandatory authentication method
-sending the request is not necessary.
-
-See [SILC1] and section Connection Auth Request Payload in [SILC2] also
-for the list of different authentication methods. Authentication method
-MAY also be NONE, in which case the server does not require
-authentication. However, in this case the protocol still MUST be
-executed; the authentication data is empty indicating no authentication
-is required.
-
-If authentication method is passphrase the authentication data is
-plaintext passphrase. As the payload is encrypted it is safe to have
-plaintext passphrase. It is also provided as plaintext passphrase
-because the receiver may need to pass the entire passphrase into a
-passphrase verifier, and a message digest of the passphrase would
-prevent this. See the section 3.2.1 Passphrase Authentication for
-more information.
-
-If authentication method is public key authentication the authentication
-data is a digital signature of the hash value of hash HASH and Key
-Exchange Start Payload, established by the SILC Key Exchange protocol.
-This signature MUST then be verified by the server. See the section
-3.2.2 Public Key Authentication for more information.
-
-See the section 4 SILC Procedures in [SILC1] for more information about
-client creating connection to server, and server creating connection
-to router, and how to register the session in the SILC Network after
-successful Connection Authentication protocol.
-
-
-.ti 0
-3.1 Connection Auth Payload
-
-Client sends this payload to authenticate itself to the server. Server
-connecting to another server also sends this payload. Server receiving
-this payload MUST verify all the data in it and if something is to fail
-the authentication MUST be failed by sending SILC_PACKET_FAILURE packet.
-
-The payload may only be sent with SILC_PACKET_CONNECTION_AUTH packet.
-It MUST NOT be sent in any other packet type. The following diagram
-represent the Connection Auth Payload.
-
-
-
-
-
-
-
-.in 5
-.nf
- 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Payload Length | Connection Type |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| |
-~ Authentication Data ~
-| |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 3: Connection Auth Payload
-
-
-.in 6
-o Payload Length (2 bytes) - Length of the entire Connection
- Auth Payload.
-
-o Connection Type (2 bytes) - Indicates the type of the
- connection. See section Connection Auth Request Payload
- in [SILC2] for the list of connection types. This field MUST
- include valid connection type or the packet MUST be discarded
- and authentication MUST be failed.
-
-o Authentication Data (variable length) - The actual
- authentication data. Contents of this depends on the
- authentication method known by both parties. If no
- authentication is required this field does not exist.
-.in 3
-
-
-.ti 0
-3.2 Connection Authentication Types
-
-SILC supports two authentication types to be used in the connection
-authentication protocol; passphrase authentication or public key
-authentication based on digital signatures. The following sections
-defines the authentication methods. See [SILC2] for defined numerical
-authentication method types.
-
-
-.ti 0
-3.2.1 Passphrase Authentication
-
-Passphrase authentication or pre-shared key based authentication is
-simply an authentication where the party that wants to authenticate
-itself to the other end sends the passphrase that is required by
-the other end, for example server. The plaintext passphrase is put
-to the payload, that is then encrypted. The plaintext passphrase
-MUST be in UTF-8 [RFC2279] encoding. If the passphrase is in the
-sender's system in some other encoding it MUST be UTF-8 encoded
-before transmitted. The receiver MAY change the encoding of the
-passphrase to its system's default character encoding before verifying
-the passphrase.
-
-If the passphrase matches with the one in the server's end the
-authentication is successful. Otherwise SILC_PACKET_FAILURE MUST be
-sent to the sender and the protocol execution fails.
-
-This is REQUIRED authentication method to be supported by all SILC
-implementations.
-
-When password authentication is used it is RECOMMENDED that maximum
-amount of padding is applied to the SILC packet. This way it is not
-possible to approximate the length of the password from the encrypted
-packet.
-
-
-
-.ti 0
-3.2.2 Public Key Authentication
-
-Public key authentication may be used if passphrase based authentication
-is not desired. The public key authentication works by sending a
-digital signature as authentication data to the other end, say, server.
-The server MUST then verify the signature by the public key of the sender,
-which the server has received earlier in SKE protocol, or which the
-server has cached locally at some previous time.
-
-The signature is computed using the private key of the sender by signing
-the HASH value provided by the SKE protocol previously, and the Key
-Exchange Start Payload from SKE protocol that was sent to the server.
-These are concatenated and hash function is used to compute a hash value
-which is then signed.
-
- auth_hash = hash(HASH | Key Exchange Start Payload);
- signature = sign(auth_hash);
-
-The hash() function used to compute the value is the hash function
-negotiated in the SKE protocol. The server MUST verify the data, thus
-it must keep the HASH and the Key Exchange Start Payload saved during
-SKE and authentication protocols. These values can be discarded after
-Connection Authentication protocol is completed.
-
-If the verified signature matches the sent signature, the authentication
-were successful and SILC_PACKET_SUCCESS is sent. If it failed the
-protocol execution is stopped and SILC_PACKET_FAILURE is sent.
-
-This is REQUIRED authentication method to be supported by all SILC
-implementations.
-
-
-
-.ti 0
-3.3 Connection Authentication Status Types
-
-This section defines all connection authentication status types that
-may be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
-to indicate the status of the protocol. Implementations may map the
-status types to human readable error message. All types except the
-SILC_AUTH_STATUS_OK type MUST be sent in SILC_PACKET_FAILURE packet.
-The length of status is 32 bits (4 bytes). The following status types
-are defined:
-
-0 SILC_AUTH_OK
-
- Protocol was executed successfully.
-
-
-1 SILC_AUTH_FAILED
-
- Authentication failed.
-
-
-.ti 0
-4 Security Considerations
-
-Security is central to the design of this protocol, and these security
-considerations permeate the specification. Common security considerations
-such as keeping private keys truly private and using adequate lengths for
-symmetric and asymmetric keys must be followed in order to maintain the
-security of this protocol.
-
-
-.ti 0
-5 References
-
-[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
- Protocol Specification", Internet Draft, January 2007.
-
-[SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft,
- January 2007.
-
-[SILC4] Riikonen, P., "SILC Commands", Internet Draft, January 2007.
-
-[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
- RFC 1459, May 1993.
-
-[IRC-ARCH] Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
- April 2000.
-
-[IRC-CHAN] Kalt, C., "Internet Relay Chat: Channel Management", RFC
- 2811, April 2000.
-
-[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
- 2812, April 2000.
-
-[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
- 2813, April 2000.
-
-[SSH-TRANS] Ylonen, T., et al, "SSH Transport Layer Protocol",
- Internet Draft.
-
-[PGP] Callas, J., et al, "OpenPGP Message Format", RFC 2440,
- November 1998.
-
-[SPKI] Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
- September 1999.
-
-[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
- Infrastructure, Certificate and CRL Profile", RFC 2459,
- January 1999.
-
-[Schneier] Schneier, B., "Applied Cryptography Second Edition",
- John Wiley & Sons, New York, NY, 1996.
-
-[Menezes] Menezes, A., et al, "Handbook of Applied Cryptography",
- CRC Press 1997.
-
-[OAKLEY] Orman, H., "The OAKLEY Key Determination Protocol",
- RFC 2412, November 1998.
-
-[ISAKMP] Maughan D., et al, "Internet Security Association and
- Key Management Protocol (ISAKMP)", RFC 2408, November
- 1998.
-
-[IKE] Harkins D., and Carrel D., "The Internet Key Exchange
- (IKE)", RFC 2409, November 1998.
-
-[HMAC] Krawczyk, H., "HMAC: Keyed-Hashing for Message
- Authentication", RFC 2104, February 1997.
-
-[PKCS1] Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
- Specifications, Version 2.0", RFC 2437, October 1998.
-
-[RFC2119] Bradner, S., "Key Words for use in RFCs to Indicate
- Requirement Levels", BCP 14, RFC 2119, March 1997.
-
-[RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO
- 10646", RFC 2279, January 1998.
-
-[RFC2401] Kent, S., et al, "Security Architecture for the Internet
- Protocol", RFC 2401, November 1998.
-
-[RFC2406] Kent, S., et al, "Security Architecture for the Internet
- Protocol", RFC 2406, November 1998.
-
-
-.ti 0
-6 Author's Address
-
-.nf
-Pekka Riikonen
-Helsinki
-Finland
-
-EMail: priikone@iki.fi
-
-
-.ti 0
-7 Full Copyright Statement
-
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
-
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+++ /dev/null
-.pl 10.0i
-.po 0
-.ll 7.2i
-.lt 7.2i
-.nr LL 7.2i
-.nr LT 7.2i
-.ds LF Riikonen
-.ds RF FORMFEED[Page %]
-.ds CF
-.ds LH Internet-Draft
-.ds RH 15 January 2007
-.ds CH
-.na
-.hy 0
-.in 0
-.nf
-Network Working Group P. Riikonen
-Internet-Draft
-draft-riikonen-silc-multimedia-session-00.txt 15 January 2007
-Expires: 15 July 2007
-
-.in 3
-
-.ce 2
-Multimedia Sessions in SILC protocol
-<draft-riikonen-silc-multimedia-session-00.txt>
-
-.ti 0
-Status of this Draft
-
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
-
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
-
-The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
-The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
-
-
-.ti 0
-Abstract
-
-This document defines the use of multimedia protocols and the set up
-of multimedia sessions in the Secure Internet Live Conferencing (SILC)
-protocol [SILC1].
-
-
-.ti 0
-Table of Contents
-
-.nf
-1 Introduction .................................................. 2
- 1.1 Requirements Terminology .................................. 2
-2 Recommended Protocol .......................................... 2
-3 Session Description Protocol (SDP) ............................ 2
- 3.1 SDP field usage in SILC ................................... 3
- 3.2 SDP Examples .............................................. 5
-4 Session Initiation Protocol (SIP) ............................. 6
-5 Other Protocols ............................................... 6
-6 Security Considerations ....................................... 7
-7 References .................................................... 7
-8 Author's Address .............................................. 7
-9 Full Copyright Statement ...................................... 7
-
-
-.ti 0
-1 Introduction
-
-This document defines the use of multimedia protocols and the set up
-of multimedia sessions in the Secure Internet Live Conferencing (SILC)
-protocol [SILC1]. The SILC protocol supports multimedia messages
-with the Message Payload [SILC2] and SILC_MESSAGE_FLAG_DATA which
-has the ability to define what type of content is delievered within
-the payload. The Message Payload is used to encapsulate the multimedia
-session set up procedure and the actual multimedia session data. We
-define the recommended multimedia session protocol for SILC and also
-consider some other protocols in the scope of SILC.
-
-
-.ti 0
-1.1 Requirements Terminology
-
-The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
-MAY, and OPTIONAL, when they appear in this document, are to be
-interpreted as described in [RFC2119].
-
-
-.ti 0
-2 Recommended Protocol
-
-Since SILC protocol can encapsulate practically any protocol for setting
-up a multimedia session we have selected the Session Description Protocol
-(SDP) as RECOMMENDED protocol. It was chosen for its maturity, simplicity
-and versatility. If multimedia features are implemented in SILC
-application it is recommended that at least support for SDP is added.
-
-
-.ti 0
-3 Session Description Protocol (SDP)
-
-The SDP [SDP] protocol defines a general purpose multimedia session
-description protocol. SDP is one of the simplest protocols to negotiate
-multimedia sessions and is suited perfectly for SILC protocol. Since SDP
-does not itself define how it is used to set up the session, we define it
-here for SILC. The definition is based on the [RFC3264] and [RFC4145].
-
-In SILC the SDP messages are sent as data messages (MIME message). They
-can be destined directly to a client for direct conferencing, or to a
-channel for group conferencing. It is also possible to send the message
-directly to client to invite them to group conferencing before they have
-joined the channel. The MIME type used is application/sdp.
-
-To set up a multimedia session a client sends SILC message with
-SILC_MESSAGE_FLAG_DATA and SILC_MESSAGE_FLAG_REQUEST flags set and with
-MIME SDP message in the message payload. If the receiver wants to
-participate in the multimedia session it sends MIME SDP message back with
-SILC_MESSAGE_FLAG_DATA and SILC_MESSAGE_FLAG_REPLY flags set to the
-sender. If reply is not received after an application defined period of
-time the message may be retransmitted or the session set up may be
-terminated.
-
-After reply has been received the multimedia session is started according
-to the SDP and all multimedia data is sent using SILC data messages. When
-performing peer-to-peer connection the SDP defines which party initiates
-the connection. After initiation the SILC Key Exchange protocol MUST be
-performed. The resulted key material will be used to protect the multimedia
-session. Multimedia data transmission may start after the key exchange
-has been performed. When performing group conferencing all parties
-independently connect to the SILC server specified in the SDP. In other
-cases when performing the multimedia session inside the SILC network, any
-party may start transmitting the multimedia data after the SDPs have been
-exchanged.
-
-To terminate the session, or to reject incoming request, an MD5 digest
-MUST be computed from the original SDP data, and the digest is sent back
-with the SILC_MESSAGE_FLAG_DATA and SILC_MESSAGE_FLAG_STOP flags set.
-The receiver of such message should verify the MD5 digest and terminate
-the session if it matches any active session. The session may also be
-terminated by closing network connection. In group sessions simply by
-leaving the channel terminates the session. The original sender of the
-SDP message may send the terminating message to notify all clients on the
-channel to terminate the session. If the original sender on channel
-receives the terminating message it takes no action on it.
-
-.ti 0
-3.1 SDP field usage in SILC
-
-The Encryption Keys (k=) field describes encryption key to protect the
-multimedia session. As SILC protocol transport and the multimedia session
-is secured by default this field SHOULD NOT be used.
-
-
-The Origin (o=) field describes from where the session originates. The
-<username> sub-field is the sender's SILC nickname. Examples:
-
- o=foobar 2890844521 2890842804 IN IP4 10.2.1.7
-
-
-The Connection Data (c=) field describes the connection information for
-the multimedia session. When performing peer-to-peer multimedia session
-the <network type> is 'IN', indicating Internet connection. When
-performing multimedia session inside SILC network it is 'SILC'. When
-the 'SILC' network type is used the <address type> and <connection address>
-sub-fields are omitted. Examples:
-
- c=SILC
- c=IN IP4 10.2.1.7
-
-
-The Media Announcements (m=) field describes the media information for the
-multimedia session. If the network type in c= field is 'SILC' the <port>
-sub-field MUST be set to 9 (discard). The <transport> for RTP over UDP
-is 'RTP/AVP', for RTP over TCP it is 'TCP/RTP/AVP', and for non-RTP protocol
-over UDP it is 'udp' and over TCP it is 'tcp'. The <fmt> sub-field
-includes the RTP media payload number when using RTP. When using non-RTP
-protocol it includes MIME subtype. Examples:
-
- c=SILC
- m=audio 9 TCP/RTP/AVP 3
- a=rtpmap:3 GSM/8000
-
- c=SILC
- m=audio 9 tcp mpeg
-
-
-The Attributes (a=) field can be used to set various session and media
-specific attributes. For SILC we define attribute "silc".
-
- a=silc:<session type> <parameters>
-
-The <session type> is either "direct" or "group". When it is "direct"
-and the c= field defines a connection point the connection will be
-peer-to-peer connection to the remote client. If it is "group" and the
-the c= field defines a connection point the connection will be to a remote
-SILC server for group conferencing. If c= field includes "SILC" network
-type, then "direct" is for direct session with a client in SILC network
-and "group" is for group conferencing in SILC network. If the "silc"
-attribute is omitted the session type is expected to be "direct". The
-following parameters are defined for attribute "silc".
-
- channel The name of the channel for group conferencing.
- Can be used only with "group" session type.
- More than one channel parameters may be defined.
-
-
-The [RFC4145] specifies a "setup" attribute that defines which party of the
-session will initiate the connection when performing peer-to-peer session.
-Its use in SILC is as specified in [RFC4145] and MUST be present in SDP
-when the c= field includes an actual connection point and when the "silc"
-attribute session type is "direct", or if the attribute is not present at
-all. When performing group conferencing each party always need to create
-the connection to the server and the "setup" attribute need not be present
-in SDP.
-
-.ti 0
-3.2 SDP Examples
-
- v=0
- o=foobar 2890844521 2890842804 IN IP4 10.2.1.100
- s=peer-to-peer example
- t=0 0
- m=audio 5000 TCP/RTP/AVP 3
- c=IN IP4 10.2.1.100
- a=rtpmap:3 GSM/8000
- a=silc:direct
- a=setup:active
-
-This example sets up a peer-to-peer session to remote client at
-10.2.1.100 at port 5000.
-
- v=0
- o=foobar 2890844521 2890842804 IN IP4 10.2.1.32
- s=Group conferencing example
- c=IN IP4 10.2.1.7
- t=0 0
- a=silc:group channel=foobar
- m=audio 706 TCP/RTP/AVP 3
- a=rtpmap:3 GSM/8000
-
-This example sets up a session to a remote SILC server 10.2.1.7 at port
-706. Once connected the channel "foobar" will be joined for group
-conferencing.
-
- v=0
- o=foobar 2890844521 2890842804 IN IP4 10.2.1.32
- s=SILC network chat example
- c=SILC
- t=0 0
- m=audio 9 TCP/RTP/AVP 3
- a=rtpmap:3 GSM/8000
-
-This example sets up a session inside SILC network with the remote user
-"foobar".
-
- v=0
- o=foobar 2890844521 2890842804 IN IP4 10.2.1.32
- s=SILC network group conferencing example
- t=0 0
- m=audio 9 TCP/RTP/AVP 3
- c=SILC
- a=rtpmap:3 GSM/8000
- a=silc:group channel=group-chat
-
-This example sets up a group conferencing session inside SILC network on
-channel "group-chat".
-
-
-.ti 0
-4 Session Initiation Protocol (SIP)
-
-The SIP [SIP] protocol is a general purpose protocol for setting up,
-modifying and terminating different kinds of sessions, including
-multimedia sessions. The SIP protocol use the SDP to describe the
-multimedia session.
-
-In SILC the SIP messages are sent as data messages (MIME message). They
-can be destined directly to a client for direct conferencing, or to a
-channel for group conferencing. It is also possible to send the message
-directly to client to invite them to group conferencing before they have
-joined the channel. The MIME type used is application/sip. The
-SILC_MESSAGE_FLAG_DATA flag must be set in each message and the message
-payload includes a MIME SIP message. The actual SIP session set up and
-termination is described in the SIP protocol specification, and SILC
-protocol merely provides a secure transport for the session. After the
-session is set up all multimedia data is sent using SILC data messages.
-The MIME type for the multimedia data messages is defined during the SIP
-session set up.
-
-The rules for SDP fields described in previous section also applies for
-SDP with SIP in the context of SILC.
-
-Proxy and redirection servers usually would not be used in the context of
-SILC, unless the sessions are redirected to outside SILC network. This
-may compromise the security of the session.
-
-The S/MIME need not be used when using SIP in SILC protocol. The SILC
-protocol transport and the created multimedia session is secured by
-default.
-
-
-.ti 0
-5 Other Protocols
-
-There are other open and proprietary protocols for setting up multimedia
-sessions. One important is H.323 using the H.225 to set up the session.
-This document should later define the use of H.323 with SILC.
-Practically any protocol to set up multimedia sessions may be used with
-SILC by using SILC as a secure transport to set up the session, and to use
-SILC data messages (MIME messages) to secure and deliver the actual
-multimedia data once the session has been established.
-
-
-.ti 0
-6 Security Considerations
-
-Security is central to the design of this protocol, and these security
-considerations permeate the specification. Common security considerations
-such as keeping private keys truly private and using adequate lengths for
-symmetric and asymmetric keys must be followed in order to maintain the
-security of this protocol.
-
-
-.ti 0
-7 References
-
-[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
- Protocol Specification", Internet Draft, June 2003.
-
-[SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft,
- June 2003.
-
-[RFC3264] Rosenberg, J., et. al., "An Offer/Answer Model with the
- Session Description Protocol (SDP)", RFC 3264, June 2002.
-
-[RFC4145] Yon, D., et. al., "TCP-Based Media Transport in the
- Session Description Protocol (SDP)", RFC 4145, September
- 2005.
-
-[SIP] Rosenberg, J., et. al., "SIP: Session Initiation Protocol",
- RFC 3261, June 2002.
-
-
-
-.ti 0
-8 Author's Address
-
-.nf
-Pekka Riikonen
-Helsinki
-Finland
-
-EMail: priikone@iki.fi
-
-
-.ti 0
-9 Full Copyright Statement
-
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
-
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
.ds RF FORMFEED[Page %]
.ds CF
.ds LH Internet Draft
-.ds RH 15 January 2007
+.ds RH XXX
.ds CH
.na
.hy 0
.nf
Network Working Group P. Riikonen
Internet-Draft
-draft-riikonen-silc-pp-09.txt 15 January 2007
-Expires: 15 July 2007
+draft-riikonen-silc-pp-08.txt XXX
+Expires: XXX
.in 3
<draft-riikonen-silc-pp-09.txt>
.ti 0
-Status of this Draft
+Status of this Memo
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026. Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups. Note that other groups may also
+distribute working documents as Internet-Drafts.
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
+http://www.ietf.org/ietf/1id-abstracts.txt
+
The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
+http://www.ietf.org/shadow.html
+The distribution of this memo is unlimited.
.ti 0
2 SILC Packet Protocol .......................................... 4
2.1 SILC Packet ............................................... 4
2.2 SILC Packet Header ........................................ 5
- 2.3 SILC Packet Types ......................................... 8
+ 2.3 SILC Packet Types ......................................... 7
2.3.1 SILC Packet Payloads ................................ 15
- 2.3.2 Generic payloads .................................... 16
- 2.3.2.1 ID Payload .................................. 16
- 2.3.2.2 Argument Payload ............................ 17
+ 2.3.2 Generic payloads .................................... 15
+ 2.3.2.1 ID Payload .................................. 15
+ 2.3.2.2 Argument Payload ............................ 16
2.3.2.3 Argument List Payload ....................... 17
2.3.2.4 Channel Payload ............................. 18
2.3.2.5 Public Key Payload .......................... 19
- 2.3.2.6 Message Payload ............................. 20
+ 2.3.2.6 Message Payload ............................. 19
2.3.3 Disconnect Payload .................................. 23
- 2.3.4 Success Payload ..................................... 24
- 2.3.5 Failure Payload ..................................... 25
+ 2.3.4 Success Payload ..................................... 23
+ 2.3.5 Failure Payload ..................................... 24
2.3.6 Reject Payload ...................................... 25
- 2.3.7 Notify Payload ...................................... 26
- 2.3.8 Error Payload ....................................... 35
+ 2.3.7 Notify Payload ...................................... 25
+ 2.3.8 Error Payload ....................................... 34
2.3.9 Channel Message Payload ............................. 35
- 2.3.10 Channel Key Payload ................................ 36
- 2.3.11 Private Message Payload ............................ 38
- 2.3.12 Private Message Key Payload ........................ 38
- 2.3.13 Command Payload .................................... 40
- 2.3.14 Command Reply Payload .............................. 41
- 2.3.15 Connection Auth Request Payload .................... 41
+ 2.3.10 Channel Key Payload ................................ 35
+ 2.3.11 Private Message Payload ............................ 37
+ 2.3.12 Private Message Key Payload ........................ 37
+ 2.3.13 Command Payload .................................... 39
+ 2.3.14 Command Reply Payload .............................. 40
+ 2.3.15 Connection Auth Request Payload .................... 40
2.3.16 New ID Payload ..................................... 42
- 2.3.17 New Client Payload ................................. 43
- 2.3.18 New Server Payload ................................. 44
- 2.3.19 New Channel Payload ................................ 45
+ 2.3.17 New Client Payload ................................. 42
+ 2.3.18 New Server Payload ................................. 43
+ 2.3.19 New Channel Payload ................................ 44
2.3.20 Key Agreement Payload .............................. 45
- 2.3.21 Resume Router Payload .............................. 47
+ 2.3.21 Resume Router Payload .............................. 46
2.3.22 File Transfer Payload .............................. 47
2.3.23 Resume Client Payload .............................. 48
- 2.3.24 Acknowledgement Payload ............................ 50
- 2.4 SILC ID Types ............................................. 50
- 2.5 Packet Encryption And Decryption .......................... 51
- 2.5.1 Normal Packet Encryption And Decryption ............. 51
- 2.5.2 Channel Message Encryption And Decryption ........... 52
- 2.5.3 Private Message Encryption And Decryption ........... 53
- 2.6 Packet MAC Generation ..................................... 53
- 2.7 Packet Padding Generation ................................. 54
- 2.8 Packet Compression ........................................ 54
- 2.9 Packet Sending ............................................ 55
- 2.10 Packet Reception ......................................... 55
- 2.11 Packet Routing ........................................... 55
- 2.12 Packet Broadcasting ...................................... 57
-3 Security Considerations ....................................... 57
-4 References .................................................... 57
-5 Author's Address .............................................. 59
-6 Full Copyright Statement ...................................... 59
+ 2.4 SILC ID Types ............................................. 49
+ 2.5 Packet Encryption And Decryption .......................... 49
+ 2.5.1 Normal Packet Encryption And Decryption ............. 50
+ 2.5.2 Channel Message Encryption And Decryption ........... 50
+ 2.5.3 Private Message Encryption And Decryption ........... 51
+ 2.6 Packet MAC Generation ..................................... 52
+ 2.7 Packet Padding Generation ................................. 53
+ 2.8 Packet Compression ........................................ 53
+ 2.9 Packet Sending ............................................ 54
+ 2.10 Packet Reception ......................................... 54
+ 2.11 Packet Routing ........................................... 54
+ 2.12 Packet Broadcasting ...................................... 56
+3 Security Considerations ....................................... 56
+4 References .................................................... 56
+5 Author's Address .............................................. 58
+6 Full Copyright Statement ...................................... 58
.ti 0
List of Figures
Indicates that the packet data MUST include private
message that is encrypted using private key set by
client. Servers does not know this key and cannot
- decrypt the payload, but simply passes it along. See
- section 2.5.3 Private Message Encryption And Decryption
- for more information.
+ handle the packet, but passes it along. See section
+ 2.5.3 Private Message Encryption And Decryption for
+ more information.
List 0x02
See section 2.8 Packet Compression for description of
packet compressing.
-
- Acknowledgement 0x10
-
- Marks that the packet needs to be acknowledged by the
- recipient. The ACK packet MUST NOT have this flag set.
- The acknowledgement packet is SILC_PACKET_ACK packet.
- If the packet is not acknowledged the packet may be
- retransmitted. This flag is especially useful when
- using UDP/IP and SHOULD NOT be used with TCP/IP. The
- flag MUST NOT be used with message packets. The
- SILC_MESSAGE_FLAG_ACK can be used instead. Broadcast
- packets MUST NOT set this flag. Retransmission
- may use for example exponential backoff algorithm.
-
.in 3
o Packet Type (1 byte) - Indicates the type of the packet.
Payload of the packet: See section 2.3.23 Resume Client Payload
- 29 SILC_PACKET_ACK
-
- This packet is used to acknowledge a packet that had the
- Acknowledgement packet flag set.
-
- Payload of the packet: See section 2.3.24 Acknowledgement
- Payload
-
-
- 30 - 199
+ 29 - 199
Currently undefined commands.
The IV SHOULD be random data for each channel message.
When encrypting private messages with session keys this
- field MUST NOT be present. For private messages this field
- is present only when encrypting with a static private
- message key (pre-shared key). If randomly generated key
- material is used this field MUST NOT be present. Also,
- If Key Agreement (SKE) was used to negotiate fresh key
- material for private message key this field MUST NOT be
- present. See the section 4.6 in [SILC1] for more
- information about IVs when encrypting private messages.
+ field MUST NOT be present. For private messages this
+ field is present only when encrypting with a static
+ private message key (pre-shared key). If randomly
+ generated key material is used this field MUST NOT be
+ present. Also, If Key Agreement (SKE) was used to
+ negotiate fresh key material for private message key
+ this field MUST NOT be present. See the section 4.6
+ in [SILC1] for more information about IVs when
+ encrypting private messages.
This field includes the initialization vector used in message
encryption. It need to be used in the packet decryption
and receiver can use the MAC to verify which of the keys
must be used in decryption. This field is not present
when encrypting private messages with session key. This
- field is not encrypted. This field is authenticated by
+ field is not encrypted. This field is authenticated by
the SILC packet MAC.
.in 3
then send it to its primary router. The router or server
receiving the packet distributes this type to the local clients
on the channel and broadcast it to the network. This notify
- MUST NOT be sent to the quitting client. The Destination ID
- in the packet may be any ID depending to who it is destined.
+ MUST NOT be sent to the quitting client.
Max Arguments: 2
Arguments: (1) <Client ID> (2) <message>
are not server generated. For this reason server cannot send this
packet as it does not know the key.
-The destination ID in the packet SHOULD be the entity to whom the
-packet is sent. Using Channel ID as destination ID is not
-necessary as the Channel ID is included in the Channel Key Payload.
-
The payload may only be sent with SILC_PACKET_CHANNEL_KEY packet.
It MUST NOT be sent in any other packet type. The following diagram
represents the Channel Key Payload.
field.
o Channel Key (variable length) - The actual channel key
- material. See [SILC1] on how to start using the key.
+ material.
.in 3
The message can be protected by the session key established by the
SILC Key Exchange Protocol. However, it is also possible to agree
-to use a private message key to protect just the private messages.
-It is for example possible to perform Key Agreement between two
-clients. See section 2.3.20 Key Agreement Payload how to perform
-key agreement. It is also possible to use static or pre-shared keys
+to use a private key to protect just the private messages. It is
+for example possible to perform Key Agreement between two clients.
+See section 2.3.20 Key Agreement Payload how to perform key
+agreement. It is also possible to use static or pre-shared keys
to protect private messages. See the 2.3.12 Private Message Key
Payload and [SILC1] section 4.6 for detailed description for private
message key generation.
~ Hostname ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Protocol | Port |
+| Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.in 3
MAY fill this field when sending the payload. If the receiver
sends this payload as reply to the request it MUST fill this field.
-o Protocol (2 bytes) - The internet protocol used for the key
- agreement connection. Possible values are 0 for TCP and 1 for
- UDP. Other values are unsupported. This is a 16 bit MSB first
- order value. If Hostname field is not present, the value in
- this field is ignored.
-
-o Port (2 bytes) - The port where the SKE protocol is bound.
+o Port (4 bytes) - The port where the SKE protocol is bound.
The sender MAY fill this field when sending the payload. If
the receiver sends this payload as reply to the request it
- MUST fill this field. This is a 16 bit MSB first order value.
+ MUST fill this field. This is a 32 bit MSB first order value.
.in 3
detailed description how the detaching and resuming procedure is
performed.
-The payload may only be sent with SILC_PACKET_RESUME_CLIENT packet. It
+The payload may only be sent with SILC_PACKET_RESUME CLIENT packet. It
MUST NOT be sent in any other packet type. The following diagram
represents the Resume Client Payload.
.in 3
-.ti 0
-2.3.24 Acknowledgement Payload
-
-This payload is used to acknowledge a packet that had the Acknowledgement
-packet flag set. The payload includes the sequence number of the packet
-that had the flag set, which the recipient can use to identify that the
-packet was acknowledged.
-
-The payload may only be sent with SILC_PACKET_ACK packet. It
-MUST NOT be sent in any other packet type. The following diagram
-represents the Acknowledgement Payload.
-
-.in 5
-.nf
- 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Packet Sequence Number |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 24: Resume Client Payload
-
-
-.in 6
-o Packet Sequence Number (4 bytes) - The packet sequence number
- of the packet that had the Acknowledgement flag set.
-.in 3
-
.ti 0
2.4 SILC ID Types
2.11 Packet Routing
Routers are the primary entities in the SILC network that takes care
-of packet routing. Normal servers performs packet forwarding, for
-example, when they are forwarding channel message to the local clients.
+of packet routing. However, normal servers routes packets as well, for
+example, when they are routing channel message to the local clients.
Routing is quite simple as every packet tells the true origin and the
true destination of the packet.
When routing for example private messages they should be routed to the
shortest route always to reach the destination client as fast as possible.
-For server which receives a packet to be forwarded to an entity that is
+For server which receives a packet to be routed to an entity that is
indirectly connected to the sender, the server MUST check whether that
-particular packet type is allowed to be sent to that destination. Not
+particular packet type is allowed to be routed to that destination. Not
all packets may be sent by some odd entity to for example a local client,
or to some remote server or router, that is indirectly connected to the
sender. See section 2.3 SILC Packet Types and paragraph about indirectly
4 References
[SILC1] Riikonen, P., "Secure Internet Live Conferencing (SILC),
- Protocol Specification", Internet Draft, January 2007.
+ Protocol Specification", Internet Draft, May 2002.
[SILC3] Riikonen, P., "SILC Key Exchange and Authentication
- Protocols", Internet Draft, January 2007.
+ Protocols", Internet Draft, May 2002.
-[SILC4] Riikonen, P., "SILC Commands", Internet Draft, January 2007.
+[SILC4] Riikonen, P., "SILC Commands", Internet Draft, May 2002.
[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
RFC 1459, May 1993.
.nf
Pekka Riikonen
-Helsinki
+Snellmaninkatu 34 A 15
+70100 Kuopio
Finland
EMail: priikone@iki.fi
.ti 0
6 Full Copyright Statement
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
-
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
.ds RF FORMFEED[Page %]
.ds CF
.ds LH Internet Draft
-.ds RH 15 January 2007
+.ds RH 11 February 2004
.ds CH
.na
.hy 0
.nf
Network Working Group P. Riikonen
Internet-Draft
-draft-riikonen-silc-spec-09.txt 15 January 2007
-Expires: 15 July 2007
+draft-riikonen-silc-spec-09.txt XX
+Expires: XXX
.in 3
<draft-riikonen-silc-spec-09.txt>
.ti 0
-Status of this Draft
+Status of this Memo
-By submitting this Internet-Draft, each author represents that any
-applicable patent or other IPR claims of which he or she is aware
-have been or will be disclosed, and any of which he or she becomes
-aware will be disclosed, in accordance with Section 6 of BCP 79.
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026. Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups. Note that other groups may also
+distribute working documents as Internet-Drafts.
-Internet-Drafts are working documents of the Internet Engineering
-Task Force (IETF), its areas, and its working groups. Note that
-other groups may also distribute working documents as Internet-
-Drafts. Internet-Drafts are draft documents valid for a maximum of
-six months and may be updated, replaced, or obsoleted by other
-documents at any time. It is inappropriate to use Internet-Drafts as
-reference material or to cite them other than as "work in progress".
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
The list of current Internet-Drafts can be accessed at
-http://www.ietf.org/1id-abstracts.html
+http://www.ietf.org/ietf/1id-abstracts.txt
+
The list of Internet-Draft Shadow Directories can be accessed at
-http://www.ietf.org/shadow.html.
+http://www.ietf.org/shadow.html
+The distribution of this memo is unlimited.
.ti 0
2.5 Router Connections ........................................ 8
3 SILC Specification ............................................ 9
3.1 Client .................................................... 9
- 3.1.1 Client ID ........................................... 10
- 3.2 Server .................................................... 11
+ 3.1.1 Client ID ........................................... 9
+ 3.2 Server .................................................... 10
3.2.1 Server's Local ID List .............................. 11
3.2.2 Server ID ........................................... 12
3.2.3 SILC Server Ports ................................... 12
3.3 Router .................................................... 13
3.3.1 Router's Local ID List .............................. 13
3.3.2 Router's Global ID List ............................. 14
- 3.3.3 Router's Server ID .................................. 15
+ 3.3.3 Router's Server ID .................................. 14
3.4 Channels .................................................. 15
3.4.1 Channel ID .......................................... 16
- 3.5 Operators ................................................. 17
+ 3.5 Operators ................................................. 16
3.6 SILC Commands ............................................. 17
3.7 SILC Packets .............................................. 17
- 3.8 Packet Encryption ......................................... 18
+ 3.8 Packet Encryption ......................................... 17
3.8.1 Determination of the Source and the Destination ..... 18
3.8.2 Client To Client .................................... 19
3.8.3 Client To Channel ................................... 20
3.8.4 Server To Server .................................... 21
3.9 Key Exchange And Authentication ........................... 21
- 3.9.1 Authentication Payload .............................. 22
- 3.10 Algorithms ............................................... 24
- 3.10.1 Ciphers ............................................ 24
+ 3.9.1 Authentication Payload .............................. 21
+ 3.10 Algorithms ............................................... 23
+ 3.10.1 Ciphers ............................................ 23
3.10.1.1 CBC Mode .................................. 24
- 3.10.1.2 CTR Mode .................................. 25
- 3.10.1.3 Randomized CBC Mode ....................... 27
- 3.10.2 Public Key Algorithms .............................. 27
- 3.10.2.1 Multi-Precision Integers .................. 28
- 3.10.3 Hash Functions ..................................... 28
- 3.10.4 MAC Algorithms ..................................... 28
- 3.10.5 Compression Algorithms ............................. 29
- 3.11 SILC Public Key .......................................... 29
- 3.12 SILC Version Detection ................................... 32
- 3.13 UTF-8 Strings in SILC .................................... 33
- 3.13.1 UTF-8 Identifier Strings ........................... 33
- 3.14 Backup Routers ........................................... 34
- 3.14.1 Switching to Backup Router ......................... 36
- 3.14.2 Resuming Primary Router ............................ 37
-4 SILC Procedures ............................................... 39
- 4.1 Creating Client Connection ................................ 39
- 4.2 Creating Server Connection ................................ 41
- 4.2.1 Announcing Clients, Channels and Servers ............ 42
- 4.3 Joining to a Channel ...................................... 43
- 4.4 Channel Key Generation .................................... 44
- 4.5 Private Message Sending and Reception ..................... 45
- 4.6 Private Message Key Generation ............................ 46
- 4.7 Channel Message Sending and Reception ..................... 47
- 4.8 Session Key Regeneration .................................. 47
- 4.9 Command Sending and Reception ............................. 48
- 4.10 Closing Connection ....................................... 49
- 4.11 Detaching and Resuming a Session ......................... 49
- 4.12 UDP/IP Connections ...................................... 51
-5 Security Considerations ....................................... 52
-6 References .................................................... 53
-7 Author's Address .............................................. 55
-Appendix A ...................................................... 55
-Appendix B ...................................................... 56
-Appendix C ...................................................... 57
-Appendix D ...................................................... 57
-Full Copyright Statement ........................................ 58
+ 3.10.1.2 CTR Mode .................................. 24
+ 3.10.1.3 Randomized CBC Mode ....................... 26
+ 3.10.2 Public Key Algorithms .............................. 26
+ 3.10.2.1 Multi-Precision Integers .................. 27
+ 3.10.3 Hash Functions ..................................... 27
+ 3.10.4 MAC Algorithms ..................................... 27
+ 3.10.5 Compression Algorithms ............................. 28
+ 3.11 SILC Public Key .......................................... 28
+ 3.12 SILC Version Detection ................................... 31
+ 3.13 UTF-8 Strings in SILC .................................... 31
+ 3.13.1 UTF-8 Identifier Strings ........................... 32
+ 3.14 Backup Routers ........................................... 33
+ 3.14.1 Switching to Backup Router ......................... 35
+ 3.14.2 Resuming Primary Router ............................ 36
+4 SILC Procedures ............................................... 38
+ 4.1 Creating Client Connection ................................ 38
+ 4.2 Creating Server Connection ................................ 40
+ 4.2.1 Announcing Clients, Channels and Servers ............ 40
+ 4.3 Joining to a Channel ...................................... 42
+ 4.4 Channel Key Generation .................................... 43
+ 4.5 Private Message Sending and Reception ..................... 44
+ 4.6 Private Message Key Generation ............................ 44
+ 4.7 Channel Message Sending and Reception ..................... 45
+ 4.8 Session Key Regeneration .................................. 46
+ 4.9 Command Sending and Reception ............................. 46
+ 4.10 Closing Connection ....................................... 47
+ 4.11 Detaching and Resuming a Session ......................... 48
+5 Security Considerations ....................................... 49
+6 References .................................................... 50
+7 Author's Address .............................................. 52
+Appendix A ...................................................... 52
+Appendix B ...................................................... 54
+Appendix C ...................................................... XXX
+Appendix D ...................................................... XXX
+Full Copyright Statement ........................................ XXX
.ti 0
List of Figures
Figure 4: Router Connections
Figure 5: SILC Public Key
Figure 6: Counter Block
-Figure 7: CTR Mode Initialization Vector
.ti 0
in [SILC3] along with connection authentication protocol and should
be read to fully comprehend this document and protocol.
-The SILC protocol has been developed to work on both TCP/IP and UDP/IP
-network protocols. However, typical implementation would use only TCP/IP
-with SILC protocol. Typical implementation would be made in client-server
-model.
+The SILC protocol has been developed to work on TCP/IP network
+protocol, although it could be made to work on other network protocols
+with only minor changes. However, it is recommended that TCP/IP
+protocol is used under SILC protocol. Typical implementation would
+be made in client-server model.
.ti 0
This section describes various SILC protocol concepts that forms the
actual protocol, and in the end, the actual SILC network. The mission
of the protocol is to deliver messages from clients to other clients
-through servers and routers in secure manner. The messages may also
+through routers and servers in secure manner. The messages may also
be delivered from one client to many clients forming a group, also
known as a channel.
A difference between normal server and router server is that routers
knows all global information and keep the global network state up to date.
They also do the actual routing of the messages to the correct receiver
-within the cell and between other cells. Normal servers knows only local
-information and receive global information only when it is needed. They do
-not need to keep the global network state up to date. This makes the
-network faster and scalable as there are less servers that needs to
-maintain global network state.
+between other cells. Normal servers knows only local information and
+receive global information only when it is needed. They do not need to
+keep the global network state up to date. This makes the network faster
+and scalable as there are less servers that needs to maintain global
+network state.
This, on the other hand, leads into a cellular like network, where
routers are in the center of the cell and servers are connected to the
on the other hand may connect to other routers to form the actual SILC
network, as seen in above figure. However, router is also able to act
as normal SILC server; clients may connect to it the same way as to
-normal SILC server. This, however is not a requirement and if needed
-router servers may be hidden from users by not allowing direct client
-connections. Normal server also cannot have active connections to more
-than one router. Normal server cannot be connected to two different
-cells. Router servers, on the other hand, may have as many router to
-router connections as needed. Other direct routes between other routers
-is also possible in addition of the mandatory ring connections. This
-leads into a hybrid ring-mesh network topology.
+normal SILC server. Normal server also cannot have active connections
+to more than one router. Normal server cannot be connected to two
+different cells. Router servers, on the other hand, may have as many
+router to router connections as needed. Other direct routes between
+other routers is also possible in addition of the mandatory ring
+connections. This leads into a hybrid ring-mesh network topology.
There are many issues in this network topology that needs to be careful
about. Issues like routing, the size of the cells, the number of the
are delivered from one router to the other.
-
-
.ti 0
2.4 Channel Communication
Example: Network with three routers. Router 1. uses Router 2. as its
primary router. Router 2. uses Router 3. as its primary router,
- and Router 3. uses Router 1. as its primary router. When there
- are four or more routers in th enetwork, there may be other
- direct connections between the routers but they must not be used
- as primary routes.
+ and Router 3. uses Router 1. as its primary router. There may
+ be other direct connections between the routers but they must
+ not be used as primary routes.
The above example is applicable to any amount of routers in the network
except for two routers. If there are only two routers in the network both
for two different nicknames. However, this is not expected to happen
nor cause any serious problems if it would occur. Nicknames are usually
logical and it is unlikely to have two distinct logical nicknames
-produce same truncated hash value. Use of MD5 in nickname hash is not
-a security feature.
+produce same truncated hash value.
.ti 0
Router server in SILC network is responsible for keeping the cell together
and routing messages to other servers and to other routers. Router server
-may also act as normal server when clients may connect to it. This is not
-requirement and router servers may be hidden from clients.
+is also a normal server thus clients may connect to it as it would be
+just normal SILC server.
-However, router servers have a lot of important tasks that normal servers
+However, router servers has a lot of important tasks that normal servers
do not have. Router server knows everything and keeps the global state.
They know all clients currently on SILC, all servers and routers and all
channels in SILC. Routers are the only servers in SILC that care about
-
-
.ti 0
3.3.3 Router's Server ID
o Router's Server ID IP address - Indicates the IP address of
the router of the cell where this channel is created. This is
- taken from the router's Server ID. This way SILC routers know
+ taken from the router's Server ID. This way SILC router knows
where this channel resides in the SILC network.
o Router's Server ID port - Indicates the port of the channel on
.in 3
-
.ti 0
3.5 Operators
is available in the SILC Packet Header which is included in all packets
sent in SILC network. The SILC Packet Header is described in [SILC2].
-The header MUST be encrypted with the session key of who is the next
+The header MUST be encrypted with the session key of whom is the next
receiver of the packet along the route. The receiver of the packet, for
example a router along the route, is able to determine the sender and the
destination of the packet by decrypting the SILC Packet Header and
Note that the packet and the packet header may be encrypted with
different keys. For example, packets to channels are encrypted with
the channel key, however, the header is encrypted with the session key
-as described above. Most other packets have both header and packet
-payload encrypted with the same key, such as command packets.
+as described above. However, the header and the packet may be encrypted
+with same key. This is the case, for example, with command packets.
.ti 0
o Client 1 sends encrypted packet to its server. The packet header
is encrypted with the session key shared between the client and
- server, and the private message payload is encrypted with the
- private message delivery key shared between clients.
+ server, and the private message is encrypted with the private
+ message delivery key shared between clients.
o Server determines the destination of the packet and sends the
packet to the router. Header is encrypted with the session key.
REQUIRED to use authentication protocol when connecting. The
authentication may be based on passphrase (pre-shared secret) or public
key based on digital signatures. All passphrases sent in SILC protocol
-MUST be UTF-8 [RFC3629] encoded. The connection authentication protocol
+MUST be UTF-8 [RFC3629] encoded. The connection authentication protocol
is described in detail in [SILC3].
in the payload, the ID associated to the connection and the public key
(or certificate) received in the SKE protocol. After computing the
receiver MUST verify the signature. Also in case of public key
-authentication this payload is always encrypted. This payload is
-always sent as part of some other payload.
+authentication this payload is encrypted.
.ti 0
Algorithm "none" does not perform any encryption process at all and
thus is not recommended to be used. It is recommended that no client
-or server implementation would accept "none" algorithm except in special
+or server implementation would accept none algorithm except in special
debugging mode.
.ti 0
3.10.1.1 CBC Mode
-The "cbc" encryption mode is the standard cipher-block chaining mode.
-The very first IV is derived from the SILC Key Exchange protocol.
-Subsequent IVs for encryption is the previous ciphertext block. The very
-first IV MUST be random and is generated as described in [SILC3].
+The "cbc" encryption mode is CBC mode with inter-packet chaining. This
+means that the Initialization Vector (IV) for the next encryption block
+is the previous ciphertext block. The very first IV MUST be random and
+is generated as described in [SILC3].
.ti 0
decryption operation is not needed since both encryption and decryption
process is simple XOR with the plaintext block and the key stream block.
-The counter block is used to create the key for the CTR mode. The format
-of the 128 bit counter block is as follows:
+The counter block is used to create the key for the CTR mode. When
+SILC specifications refer to Initialization Vector (IV) in general cases,
+in case of CTR mode it refers to the counter block. The format of the
+128 bit counter block is as follows:
.in 5
.nf
| Truncated HASH from SKE |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sending/Receiving IV from SKE |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Packet Counter |
+| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Block Counter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
protocol. This acts as session identifier and each rekey MUST
produce a new HASH value.
-o Sending/Receiving IV from SKE (4 bytes) - If the CTR mode is fully
- stateful this field MUST include the first 4 bytes from the Sending
- IV or Receiving IV generated in SKE protocol. When this mode is
- used to encrypt sending traffic the Sending IV is used, when used
- to decrypt receiving traffic the Receiving IV is used. This assures
- that two parties of the protocol use different IV for sending
- traffic. Each rekey MUST produce a new value.
-
- If the IV Included flag is negotiated in SKE or CTR mode is used
- where the IV is included in the data payload, this field is the
- Nonce field from the IV received in the packet, defined below.
-
-o Packet Counter (4 bytes) - This is MSB first ordered monotonically
- increasing packet counter. It is set value 1 for first packet and
- increases for subsequent packets. After rekey the counter MUST
- restart from 1.
-
- If the IV Included flag is negotiated in SKE or CTR mode is used
- where the IV is included in the data payload, this field is the
- Packet Counter field from the IV received in the packet, defined
- below.
-
-o Block Counter (4 bytes) - This is an MSB first ordered block
- counter starting from 1 for first block and increasing for
- subsequent blocks. The counter is always set to value 1 for
- a new packet.
+o Sending/Receiving IV from SKE (8 bytes) - This value is the
+ first 8 bytes from the Sending IV or Receiving IV generated in
+ the SKE protocol. When this mode is used to encrypt sending
+ traffic the Sending IV is used, when used to decrypt receiving
+ traffic the Receiving IV is used. This assures that two parties
+ of the protocol use different IV for sending traffic. Each rekey
+ MUST produce a new value.
+
+o Block Counter (4 bytes) - This is the counter value for the
+ counter block and is MSB ordered number starting from one (1)
+ value for first block and incrementing for subsequent blocks.
+ The same value MUST NOT be used twice. The rekey MUST be
+ performed before this counter value wraps.
.in 3
CTR mode MUST NOT be used with "none" MAC. Implementations also MUST
assure that the same counter block is not used to encrypt more than
-one block. None of the counters must be allowed to wrap without rekey.
-Also, the key material used with CTR mode MUST be fresh key material.
-Static keys (pre-shared keys) MUST NOT be used with CTR mode. For this
-reason using CTR mode to encrypt for example channel messages or private
-messages with a pre-shared key is inappropriate. For private messages,
-the Key Agreement [SILC2] could be performed to produce fresh key material.
+one block. Also, the key material used with CTR mode MUST be fresh
+key material. Static keys (pre-shared keys) MUST NOT be used with
+CTR mode. For this reason using CTR mode to encrypt for example
+channel messages or private messages with a pre-shared key is
+inappropriate. For private messages, the Key Agreement could be
+performed to produce fresh key material.
If the IV Included flag was negotiated in SKE, or CTR mode is used to
-protect channel messages where the IV will be included in the Message
-Payload, the Initialization Vector (IV) to be used is a 64-bit block
-containing randomness and packet counter. Also note, that in this case
-the decryption process is not stateful and receiver cannot precompute
-the key stream. Hence, the Initialization Vector (IV) when CTR mode is
-used is as follows.
-
-.in 5
-.nf
- 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Nonce |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Packet Counter |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-.in 3
-
-.ce
-Figure 7: CTR Mode Initialization Vector
-
-o Nonce (4 bytes) - This field should be random or otherwise not
- easily determinable and SHOULD change for each packet.
-
-o Packet Counter (4 bytes) - This is MSB first ordered monotonically
- increasing packet counter. It is set value 1 for first packet and
- increases for subsequent packets. After rekey the counter MUST
- restart from 1.
-
-When decrypting the packet the Counter Block is assembled by concatenating
-the truncated hash, with the received nonce and packet counter, and with
-the block counter. The Counter Block is then used to compute the key
-stream to perform the decryption.
+protect channel messages where the counter block will be included in the
+Message Payload, implementations SHOULD still use the same counter block
+format as defined above. However, implementations are RECOMMENDED to
+replace the Truncated HASH field with a 32 bit random value for each IV
+(counter block) per encrypted SILC packet. Also note, that in this case
+the decryption process is not stateful and receiver cannot precompute the
+key stream.
.ti 0
The "rcbc" encryption mode is CBC mode with randomized IV. This means
that each IV for each packet MUST be chosen randomly. When encrypting
-more than one block the normal IV chaining is used, but for the first
-block new random IV is selected in each packet. In this mode the IV
-is appended to the ciphertext. If this mode is used to secure the SILC
-session, the IV Included flag must be negotiated in SILC Key Exchange
-protocol. It may also be used to secure Message Payloads which can
-deliver the IV to the recipient.
+more than one block the normal inter-packet chaining is used, but for
+the first block new random IV is selected in each packet. In this mode
+the IV is appended at the end of the last ciphertext block and thus
+delivered to the recipient. This mode increases the ciphertext size by
+one ciphertext block. Note also that some data payloads in SILC are
+capable of delivering the IV to the recipient. When explicitly
+encrypting these payloads with randomized CBC the IV MUST NOT be appended
+at the end of the ciphertext, but is placed at the specified location
+in the payload. However, Message Payload for example has the IV at
+the location which is equivalent to placing it after the last ciphertext
+block. When using CBC mode with such payloads it is actually equivalent
+to using randomized CBC since the IV is selected in random and included
+in the ciphertext.
.ti 0
.in 3
DSS is described in [Menezes]. The RSA MUST be implemented according
-PKCS #1 [PKCS1]. When using SILC Public Key version 2 the PKCS #1
-implementation MUST be compliant with PKCS #1 version 1.5. The signatures
-are computed with appendix; the hash OID is included in the signature.
-The user may always select the hash algorithm for the signatures. When
-using SILC Public Key version 1 the PKCS #1 implementation MUST be
-compliant with PKCS #1 version 1.5 where signatures are computed without
-appendix; the hash OID is not present in the signature. The hash
-algorithm used is specified separately or the default hash algorithm is
-used, as defined below.
+PKCS #1 [PKCS1]. The mandatory PKCS #1 implementation in SILC MUST be
+compliant to either PKCS #1 version 1.5 or newer with the following
+notes: The signature encoding is always in same format as the encryption
+encoding regardless of the PKCS #1 version. The signature with appendix
+(with hash algorithm OID in the data) MUST NOT be used in the SILC. The
+rationale for this is that there is no binding between the PKCS #1 OIDs
+and the hash algorithms used in the SILC protocol. Hence, the encoding
+is always in PKCS #1 version 1.5 format.
Additional public key algorithms MAY be defined to be used in SILC.
When signatures are computed in SILC the computing of the signature is
-denoted as sign(). The signature computing procedure is dependent of
-the public key algorithm, and the public key or certificate encoding.
+represented as sign(). The signature computing procedure is dependent
+of the public key algorithm, and the public key or certificate encoding.
When using SILC public key the signature is computed as described in
previous paragraph for RSA and DSS keys. If the hash function is not
-specified separately for signing process SHA-1 MUST be used, except with
-SILC public key version 2 and RSA algorithm when the user MAY always
-select the hash algorithm. In this case the hash algorithm is included
-in the signature and can be retrieved during verification. When using
+specified separately for signing process SHA-1 MUST be used. When using
SSH2 public keys the signature is computed as described in [SSH-TRANS].
When using X.509 version 3 certificates the signature is computed as
described in [PKCS7]. When using OpenPGP certificates the signature is
-computed as described in [PGP] and the PGP signature type used is 0x00.
+computed as described in [PGP].
.ti 0
3.10.2.1 Multi-Precision Integers
Multi-Precision (MP) integers in SILC are encoded and decoded as defined
-in PKCS #1 [PKCS1]. MP integers are unsigned, encoded with the exact
-octet length of the integer. No extra leading zero octets may appear.
-The actual length of the integer is the bit size of the integer not
-counting any leading zero bits. The octet length is derived by calculating
-(bit_length + 7) / 8.
+in PKCS #1 [PKCS1]. MP integers are unsigned, encoded with desired octet
+length. This means that if the octet length is more than the actual
+length of the integer one or more leading zero octets will appear at the
+start of the encoding. The actual length of the integer is the bit size
+of the integer not counting any leading zero bits.
.ti 0
The following Hash algorithm are defined in SILC protocol:
.in 6
-sha1 SHA-1, length = 20 bytes (REQUIRED)
-sha256 SHA-256, length = 32 bytes (RECOMMENDED)
-md5 MD5, length = 16 bytes (RECOMMENDED)
+sha1 SHA-1, length = 20 (REQUIRED)
+md5 MD5, length = 16 (RECOMMENDED)
.in 3
The following MAC algorithms are defined in SILC protocol:
.in 6
-hmac-sha1-96 HMAC-SHA1, length = 12 bytes (REQUIRED)
-hmac-sha256-96 HMAC-SHA256, length = 12 bytes (RECOMMENDED)
-hmac-md5-96 HMAC-MD5, length = 12 bytes (OPTIONAL)
-hmac-sha1 HMAC-SHA1, length = 20 bytes (OPTIONAL)
-hmac-sha256 HMAC-SHA256, length = 32 bytes (OPTIONAL)
-hmac-md5 HMAC-MD5, length = 16 bytes (OPTIONAL)
-none No MAC (OPTIONAL)
+hmac-sha1-96 HMAC-SHA1, length = 12 bytes (REQUIRED)
+hmac-md5-96 HMAC-MD5, length = 12 bytes (OPTIONAL)
+hmac-sha1 HMAC-SHA1, length = 20 bytes (OPTIONAL)
+hmac-md5 HMAC-MD5, length = 16 bytes (OPTIONAL)
+none No MAC (OPTIONAL)
.in 3
The "none" MAC is not recommended to be used as the packet is not
The HMAC algorithm is described in [HMAC]. The hash algorithms used
in HMACs, the SHA-1 is described in [RFC3174] and MD5 is described
-in [RFC1321]. The SHA-256 algorithm and its used with HMAC is described
-in [SHA256].
+in [RFC1321].
Additional MAC algorithms MAY be defined to be used in SILC.
the Identifier field, not including this field.
o Identifier (variable length) - Indicates the identifier
- of the public key. This data can be used to identify the
- owner of the key. The identifier may be of the following
+ of the public key. This data can be used to identify
+ the owner of the key. The identifier is of the following
format:
- UN User name
- HN Host name or IP address
- RN Real name
- E EMail address
- O Organization
- C Country
- V Version
+ UN User name
+ HN Host name or IP address
+ RN Real name
+ E EMail address
+ O Organization
+ C Country
+
Examples of an identifier:
`UN=priikone, HN=poseidon.pspt.fi, E=priikone@poseidon.pspt.fi'
- `UN=sam, HN=dummy.fi, RN=Sammy Sam, C=Finland, V=2'
+ `UN=sam, HN=dummy.fi, RN=Sammy Sam, O=Company XYZ, C=Finland'
At least user name (UN) and host name (HN) MUST be provided as
identifier. The fields are separated by commas (`,'). If
comma is in the identifier string it must be escaped as `\\,',
for example, `O=Company XYZ\\, Inc.'. Other characters that
require escaping are listed in [RFC2253] and are to be escaped
- as defined therein. The Version (V) may only be a decimal digit.
+ as defined therein.
o Public Data (variable length) - Includes the actual
public data of the public key.
field if they are used.
.in 3
-The SILC Public Key is version is 2. If the Version (V) identifier is
-not present the SILC Public Key version is expected to be 1. All new
-implementations SHOULD support version 1 but SHOULD only generate version 2.
-In this case the Version (V) identifier MUST be present.
-
All fields in the public key are in MSB (most significant byte first)
order. All strings in the public key MUST be UTF-8 encoded.
they are defined here for external protocols (protocols that may like
to use SILC Public Key).
-A fingerprint from SILC Public Key is computed from the whole encoded
-public key data block. All fields are included in computation. Compliant
-implementations MUST support computing a 160-bit SHA-1 fingerprint.
-
.ti 0
3.12 SILC Version Detection
Identifier strings are special strings in SILC protocol that require
more careful processing, than the general UTF-8 strings described in the
-previous section. These strings include the nicknames, server names,
-hostnames and some other identifier strings. These strings are prepared
-using the stringprep [RFC3454] standard. The Appendix A defines the
-stringprep profile for SILC identifier strings and conforming
+previous section. These strings include the nicknames, server names,
+hostnames and some other identifier strings. These strings are prepared
+using the stringprep [RFC3454] standard. The Appendix A defines the
+stringprep profile for SILC identifier strings and conforming
implementation MUST use the profile to prepare any identifier string.
The stringprep profile describes how identifier strings are prepared,
backup routers, servers and other routers in the network.
It must be noted that some of the channel messages and private messages
-may be lost during the switch to the backup router, unless the message
-flag SILC_MESSAGE_FLAG_ACK is set in the message. The announcements
+may be lost during the switch to the backup router. The announcements
assure that the state of the network is not lost during the switch.
It is RECOMMENDED that there would be at least one backup router in
If the action is allowed type value 21 is sent back to the server from
the backup router. It is RECOMMENDED that implementations use the
SILC_COMMAND_PING command to detect whether primary router is responsive.
-If the backup router notices that the primary router is unresponsive
-it SHOULD NOT start sending data to server links before the server has
-sent the SILC_PACKET_RESUME_ROUTER with type value 21.
The servers connected to the backup router must then announce their
clients, channels, channel users, channel user modes, channel modes,
SILC_NOTIFY_TYPE_WATCH to the watcher.
+
+
.ti 0
4.2 Creating Server Connection
router's Server ID as Destination when communicating with the router.
-
-
.ti 0
4.2.1 Announcing Clients, Channels and Servers
When client receives the SILC_PACKET_CHANNEL_KEY packet with the
Channel Key Payload it MUST process the key data to create encryption
-and decryption key, and to create the MAC key that is used to compute
+and decryption key, and to create the HMAC key that is used to compute
the MACs of the channel messages. The processing is as follows:
channel_key = raw key data
- MAC key = hash(raw key data)
+ HMAC key = hash(raw key data)
The raw key data is the key data received in the Channel Key Payload.
-It is used for both encryption and decryption. The hash() is the hash
-function used with the HMAC of the channel. Note that the server also
-MUST save the channel key.
+The hash() function is the hash function used in the HMAC of the channel.
+Note that the server also MUST save the channel key.
.ti 0
After both parties have regenerated the session key, both MUST send
SILC_PACKET_REKEY_DONE packet to each other. These packets are still
secured with the old key. After these packets, the subsequent packets
-MUST be protected with the new key. Note that, in case SKE was performed
-again the SILC_PACKET_SUCCESS is not sent. The SILC_PACKET_REKEY_DONE
-is sent in its stead.
+MUST be protected with the new key.
.ti 0
persistent as long as the server is running.
-
-.ti 0
-4.12 UDP/IP Connections
-
-SILC protocol allows the use of UDP/IP instead of TCP/IP. There may be
-many reasons to use UDP, such as video and audio conferencing might
-be more efficient with UDP.
-
-When UDP/IP is used, in the SILC Key Exchange protocol the IV Included
-flag MUST be set and the first 16-bits of the Cookie field in the Key
-Exchange Start Payload MUST include the port that the other end will use
-as the SILC session port. The port is in MSB first order. Both initiator
-and responder will set the port they are going to use and all packets
-after the SKE has been completed with the SILC_PACKET_SUCCESS packet MUST
-be sent to the specified port. Initiator will send them to the port
-responder specified and vice versa. When verifying the cookie for
-modifications the first two bytes are to be ignored in case IV Included
-flag has been set.
-
-The default SILC port or port where the SILC server is listenning for
-incoming packets is used only during initial key exchange protocol. After
-SKE has been completed all packets are sent to the specified ports,
-including connection authentication packets and rekey packets even when
-PFS is used in rekey.
-
-Changing the ports during SILC session is possible only by first detaching
-from the server (with client-server connections) and then performing the
-SILC Key Exchange protocol from the beginning and resuming the detached
-session.
-
-Since the UDP is unreliable transport the SKE packets may not arrive to
-the recipient. Implementation should support retransmission of SKE
-packets by using exponential backoff algorithm. Also other SILC packets
-such as messages may drop en route. With message packets only way to
-assure reliable delivery is to use message acking and retransmit the
-message by using for example exponential backoff algorithm. With SKE
-packets the initial timeout value should be no more than 1000
-milliseconds. With message packets the initial timeout value should be
-around 5000 milliseconds.
-
-
.ti 0
5 Security Considerations
It however must be noted that if the client requires absolute security
by not trusting any of the servers or routers in the SILC Network, it can
-be accomplished by negotiating private secret keys outside the SILC
-Network, either using SKE or some other key exchange protocol, or to use
-some other external means for distributing the keys. This applies for
-all messages, private messages and channel messages.
+be accomplished by negotiating private keys outside the SILC Network,
+either using SKE or some other key exchange protocol, or to use some
+other external means for distributing the keys. This applies for all
+messages, private messages and channel messages.
It is important to note that SILC, like any other security protocol, is
not a foolproof system; the SILC servers and routers could very well be
6 References
[SILC2] Riikonen, P., "SILC Packet Protocol", Internet Draft,
- January 2007.
+ May 2002.
[SILC3] Riikonen, P., "SILC Key Exchange and Authentication
- Protocols", Internet Draft, January 2007.
+ Protocols", Internet Draft, May 2002.
-[SILC4] Riikonen, P., "SILC Commands", Internet Draft, January 2007.
+[SILC4] Riikonen, P., "SILC Commands", Internet Draft, May 2002.
[IRC] Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
RFC 1459, May 1993.
[RFC3454] Hoffman, P., et al., "Preparation of Internationalized
Strings ("stringprep")", RFC 3454, December 2002.
-[SHA256] Eastlake 3rd, D., et al., "US Secure Hash Algorithms (SHA
- and HMAC-SHA)", RFC 4634, July 2006.
-
-
.ti 0
7 Author's Address
.nf
Pekka Riikonen
-Helsinki
+Snellmaninkatu 34 A 15
+70100 Kuopio
Finland
EMail: priikone@iki.fi
profile defines the following as required by [RFC3454].
- Intended applicability of the profile: the following identifiers in
- the SILC Protocol; nicknames, usernames, server names, hostnames,
+ the SILC Protocol; nicknames, usernames, server names, hostnames,
service names, algorithm names and other security property names [SILC3],
and SILC Public Key name.
.ti 0
Appendix B
-This appendix defines the stringprep [RFC3454] profile for channel name
-strings in SILC protocol. Compliant implementation MUST use this profile
-to prepare the channel name strings in the SILC protocol. The profile
+This appendix defines the stringprep [RFC3454] profile for channel name
+strings in SILC protocol. Compliant implementation MUST use this profile
+to prepare the channel name strings in the SILC protocol. The profile
defines the following as required by [RFC3454].
- Intended applicability of the profile: channel names.
This appendix defines additional prohibited characters in the identifier
strings as defined in the stringprep profile in Appendix A and Appendix B.
Note that the prohibited character tables listed in the Appendix A and
-Appendix B may include some of the same characters listed in this
+Appendix B may include some of the same characters listed in this
appendix as well.
Symbol characters and other symbol like characters
.ti 0
Full Copyright Statement
-Copyright (C) The Internet Society (2007).
-
-This document is subject to the rights, licenses and restrictions
-contained in BCP 78, and except as set forth therein, the authors
-retain all their rights.
-
-This document and the information contained herein are provided on an
-"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
-OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
-ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
-INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
-WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
# Configured hash functions
#
hash {
- name = "sha256";
+ name = "sha1";
blocklength = 64;
- digestlength = 32;
+ digestlength = 20;
};
hash {
- name = "sha1";
+ name = "sha256";
blocklength = 64;
- digestlength = 20;
+ digestlength = 32;
};
hash {
name = "md5";
# be configured in the hash section.
#
hmac {
- name = "hmac-sha256-96";
- hash = "sha256";
+ name = "hmac-sha1-96";
+ hash = "sha1";
maclength = 12;
};
hmac {
- name = "hmac-sha1-96";
- hash = "sha1";
+ name = "hmac-sha256-96";
+ hash = "sha256";
maclength = 12;
};
hmac {
#ifdef SILC_DIST_TOOLKIT
include_HEADERS = \
- silc.h \
+ silcincludes.h \
silcwin32.h \
- silcsymbian.h \
+ silcepoc.h \
+ silcbeos.h \
+ silcos2.h \
silcversion.h
#endif SILC_DIST_TOOLKIT
EXTRA_DIST = \
- silc.h \
+ silcincludes.h \
silcwin32.h \
- silcsymbian.h \
+ silcepoc.h \
+ silcbeos.h \
+ silcos2.h \
silcversion.h.in \
silcdistdefs.h
/*
- client_keyagr.h
+ silcepoc.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2006 Pekka Riikonen
+ Copyright (C) 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
GNU General Public License for more details.
*/
-
-#ifndef CLIENT_KEYAGR_H
-#define CLIENT_KEYAGR_H
-
-SILC_FSM_STATE(silc_client_key_agreement);
-SILC_FSM_STATE(silc_client_key_agreement_error);
-
-#endif /* CLIENT_KEYAGR_H */
+/* Native EPOC specific includes and definitions. */
+
+#ifndef SILCEPOC_H
+#define SILCEPOC_H
+
+#include <e32std.h>
+#include <e32base.h>
+#include <e32cons.h>
+#include <e32svr.h>
+#include <e32hal.h>
+#include <w32std.h>
+#include <apgtask.h>
+#include <es_sock.h>
+#include <in_sock.h>
+
+#endif
/*
- silc.h
+ silcincludes.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
#endif
#endif
-#if defined(__EPOC32__) || defined(__SYMBIAN32__)
-#ifndef SILC_SYMBIAN
-#define SILC_SYMBIAN
+#if defined(__EPOC32__)
+#ifndef SILC_EPOC
+#define SILC_EPOC
+#undef SILC_UNIX
+#endif
+#endif
+
+#ifdef BEOS
+#ifndef SILC_BEOS
+#define SILC_BEOS
+#undef SILC_UNIX
+#endif
+#elif defined(__BEOS__)
+#ifndef SILC_BEOS
+#define SILC_BEOS
+#undef SILC_UNIX
+#endif
+#endif
+
+#if defined(OS2)
+#ifndef SILC_OS2
+#define SILC_OS2
#undef SILC_UNIX
-#undef SILC_WIN32
#endif
#endif
#if defined(__MACH__) && defined(__APPLE__)
#ifndef SILC_MACOSX
#define SILC_MACOSX
-#undef SILC_WIN32
-#undef SILC_SYMBIAN
#endif
#endif
#if defined(HAVE_SILCDEFS_H)
/* Automatically generated configuration header */
-#ifndef SILC_SYMBIAN
#include "silcdefs.h"
-#else
-#include "../symbian/silcdefs.h"
-#endif /* SILC_SYMBIAN */
#include "silcdistdefs.h"
#endif /* HAVE_SILCDEFS_H */
#include "silcwin32.h"
#endif
-#if defined(SILC_SYMBIAN)
-#include "silcsymbian.h"
+#if defined(SILC_EPOC)
+#include "silcepoc.h"
+#endif
+
+#if defined(SILC_BEOS)
+#include "silcbeos.h"
+#endif
+
+#if defined(SILC_OS2)
+#include "silcos2.h"
#endif
#ifndef DLLAPI
#include <unistd.h>
#include <sys/time.h>
#include <pwd.h>
-#include <sys/times.h>
-
-#ifdef HAVE_GRP_H
#include <grp.h>
-#endif
+#include <sys/times.h>
#if defined(HAVE_GETOPT_H) && defined(HAVE_GETOPT)
#include <getopt.h>
/* Include generic SILC type definitions */
#include "silctypes.h"
-#include "silcmutex.h"
-#include "silcatomic.h"
#include "silcversion.h"
-/* SILC util library includes */
-#include "silcstack.h"
-#include "silcmemory.h"
-#include "silcsnprintf.h"
-
/* Math library includes */
#include "silcmp.h"
#include "silcmath.h"
-/* More SILC util library includes */
-#include "silctime.h"
-#include "silccond.h"
-#include "silcthread.h"
-#include "silcschedule.h"
-#include "silclog.h"
+/* SILC util library includes */
+#include "silcmemory.h"
#include "silcbuffer.h"
#include "silcbuffmt.h"
#include "silchmac.h"
#include "silcrng.h"
#include "silcpkcs.h"
-#include "silcpk.h"
#include "silcpkcs1.h"
/* More SILC util library includes */
+#include "silcmutex.h"
+#include "silcthread.h"
+#include "silcschedule.h"
#include "silchashtable.h"
+#include "silclog.h"
#include "silclist.h"
#include "silcdlist.h"
-#include "silcasync.h"
-#include "silcstream.h"
#include "silcnet.h"
#include "silcfileutil.h"
#include "silcstrutil.h"
#include "silcstringprep.h"
#include "silcutil.h"
#include "silcconfig.h"
-#include "silcfsm.h"
-#include "silcsocketstream.h"
-#include "silcfdstream.h"
+#include "silcprotocol.h"
+#include "silcsockconn.h"
#include "silcvcard.h"
+#include "silcapputil.h"
#include "silcmime.h"
-#ifdef SILC_DIST_ASN1
-#include "silcasn1.h"
-#include "silcber.h"
-#endif /* SILC_DIST_ASN1 */
-
/* SILC core library includes */
#include "silcargument.h"
#include "silcstatus.h"
#include "silcid.h"
+#include "silcidcache.h"
#include "silccommand.h"
-#include "silcauth.h"
#include "silcmessage.h"
#include "silcchannel.h"
#include "silcpacket.h"
#include "silcnotify.h"
#include "silcmode.h"
+#include "silcauth.h"
#include "silcattrs.h"
-#include "silcpubkey.h"
-
-/* Application utility includes */
-#include "silcapputil.h"
-#ifdef SILC_DIST_IDCACHE
-#include "silcidcache.h"
-#endif /* SILC_DIST_IDCACHE */
-
-#ifdef SILC_DIST_SKR
-#include "silcskr.h"
-#endif /* SILC_DIST_SKR */
+#include "silcvcard.h"
#if defined(SILC_SIM)
/* SILC Module library includes */
#include "silcske.h"
#include "silcske_payload.h"
#include "silcske_groups.h"
-#include "silcconnauth.h"
#ifdef SILC_DIST_SFTP
/* SILC SFTP library */
#include "silcsftp_fs.h"
#endif /* SILC_DIST_SFTP */
-#ifdef SILC_DIST_HTTP
-/* SILC HTTP library */
-#include "silchttpserver.h"
-#include "silchttpphp.h"
-#endif /* SILC_DIST_HTTP */
-
#ifdef __cplusplus
}
#endif
+++ /dev/null
-/*
-
- silcsymbian.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2002 - 2006 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.
-
-*/
-/* Native Symbian specific includes and definitions. */
-
-#ifndef SILCSYMBIAN_H
-#define SILCSYMBIAN_H
-
-/* Various hacks follow */
-
-/* Do not treat conversions from 'unsigned char *' to 'char *' as errors
- with WINSCW */
-#ifdef __WINSCW__
-#pragma mpwc_relax on
-#endif /* __WINSCW__ */
-
-/* Define the need for wchar_t, otherwise the stddef.h may not define it,
- as it is not guaranteed that the stddef.h used is from Symbian headers
- (due to some include path ordering problem in some cases). */
-#ifndef __need_wchar_t
-#define __need_wchar_t
-#endif /* __need_wchar_t */
-
-/* And just in case, include stddef.h here to get the Symbian one as
- early as possible. */
-#include <stddef.h>
-
-#endif /* SILCSYMBIAN_H */
AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
# SILC Library dirs
-SILCLIB_DIRS = \
- contrib \
- silccore \
- silcutil \
- silcapputil \
-#ifdef SILC_DIST_CRYPTO
- silccrypt \
-#endif SILC_DIST_CRYPTO
-#ifdef SILC_DIST_SKR
- silcskr \
-#endif SILC_DIST_SKR
-#ifdef SILC_DIST_MATH
- silcmath \
-#endif SILC_DIST_MATH
+SILCLIB_DIRS = \
+ contrib \
+ silccore \
+ silccrypt \
#ifdef SILC_DIST_SIM
- silcsim \
+ silcsim \
#endif SILC_DIST_SIM
-#ifdef SILC_DIST_ASN1
- silcasn1 \
-#endif SILC_DIST_ASN1
- silcske \
-#ifdef SILC_DIST_HTTP
- silchttp \
-#endif SILC_DIST_HTTP
+#ifdef SILC_DIST_MATH
+ silcmath \
+#endif SILC_DIST_MATH
#ifdef SILC_DIST_SFTP
- silcsftp \
+ silcsftp \
#endif SILC_DIST_SFTP
-#ifdef SILC_DIST_VCARD
- silcvcard \
-#endif SILC_DIST_VCARD
+ silcske \
+ silcutil
SILCLIB = libsilc.a
SILCCLIENTLIB = libsilcclient.a
#endif SILC_DIST_CLIENTLIB
-#ifdef SILC_DIST_SERVERLIB
-# SILC Server Library dirs
-SILCSERVERLIB_DIRS = silcserver
-SILCSERVERLIB = libsilcserver.a
-#endif SILC_DIST_SERVERLIB
-
-SUBDIRS = $(SILCLIB_DIRS) $(SILCSERVERLIB_DIRS) $(SILCCLIENTLIB_DIRS)
+SUBDIRS = $(SILCLIB_DIRS) $(SILCCLIENTLIB_DIRS)
-CLEANFILES = libsilc.a $(SILCCLIENTLIB) $(SILCSERVERLIB)
-DISTCLEANFILES = libsilc.a $(SILCCLIENTLIB) $(SILCSERVERLIB)
+CLEANFILES = libsilc.a libsilcclient.a
+DISTCLEANFILES = libsilc.a libsilcclient.a
remove:
- -rm -f $(CLEANFILES)
+ -rm -f libsilc.a
+ -rm -f libsilcclient.a
all:
$(MAKE) remove $(SILCLIB) $(SILCSERVERLIB) $(SILCCLIENTLIB)
install-exec-hook:
-mkdir -p $(DESTDIR)$(libdir)
-$(LIBTOOL) $(INSTALL) libsilc.la $(DESTDIR)$(libdir)/
-#ifdef SILC_DIST_CLIENTLIB
-$(LIBTOOL) $(INSTALL) libsilcclient.la $(DESTDIR)$(libdir)/
-#endif SILC_DIST_CLIENTLIB
-#ifdef SILC_DIST_SERVERLIB
- -$(LIBTOOL) $(INSTALL) libsilcserver.la $(DESTDIR)$(libdir)/
-#endif SILC_DIST_SERVERLIB
#else !SILC_DIST_TOOLKIT
-#ifdef SILC_DIST_SERVERLIB
+#ifdef SILC_DIST_SERVER
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_SERVERLIB
+#endif SILC_DIST_SERVER
-#ifdef SILC_DIST_CLIENTLIB
+#ifdef SILC_DIST_CLIENT
install-exec-hook:
if SILC_ENABLE_SHARED
-mkdir -p $(libdir)
-rm -rf $(DESTDIR)$(libdir)/libsilc.a
-rm -rf $(DESTDIR)$(libdir)/libsilcclient.a
endif
-#endif SILC_DIST_CLIENTLIB
+#endif SILC_DIST_CLIENT
#endif SILC_DIST_TOOLKIT
LIB_BASE_VERSION=@LIB_BASE_VERSION@
-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 \
-#ifdef SILC_DIST_CLIENTLIB
- silcclient.pc \
-#endif SILC_DIST_CLIENTLIB
-#ifdef SILC_DIST_SERVERLIB
- silcserver.pc
-#endif SILC_DIST_SERVERLIB
+pkgconfig_DATA = silc.pc silcclient.pc
-EXTRA_DIST = silc.pc.in \
-#ifdef SILC_DIST_CLIENTLIB
- silcclient.pc.in \
-#endif SILC_DIST_CLIENTLIB
-#ifdef SILC_DIST_SERVERLIB
- silcserver.pc.in
-#endif SILC_DIST_SERVERLIB
+EXTRA_DIST = silc.pc.in silcclient.pc.in
+#endif SILC_DIST_TOOLKIT
+#ifdef SILC_DIST_TOOLKIT
toolkit-install:
-mkdir -p $(docdir)/toolkit/
-$(INSTALL_DATA) $(top_srcdir)/doc/toolkit/* $(docdir)/toolkit
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2005, 2007 Pekka Riikonen
+# 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
# SILC Library directories
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/contrib"
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silccore"
-#ifdef SILC_DIST_CRYPTO
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silccrypt"
-#endif SILC_DIST_CRYPTO
#ifdef SILC_DIST_MATH
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcmath"
#endif SILC_DIST_MATH
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcutil"
-SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcapputil"
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcske"
#ifdef SILC_DIST_SFTP
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_CLIENTLIB
+#ifdef SILC_DIST_CLIENT
SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcclient"
-#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
-#ifdef SILC_DIST_HTTP
-SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silchttp"
-#endif SILC_DIST_HTTP
-#ifdef SILC_DIST_VCARD
-SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcvcard"
-#endif SILC_DIST_VCARD
+#endif SILC_DIST_CLIENT
##
## Library versioning.
# - If functions were added, increment [LIB]_AGE
# - If functions were removed, set [LIB]_AGE to 0
#
-# where [LIB] is LIBSILC, LIBSILCCLIENT or LIBSILCSERVER, and where
-# "functions" means functions public interfaces (API).
+# where [LIB] is LIBSILC and LIBSILCCLIENT, and where "functions" means
+# functions public interfaces.
#
# The LIB_BASE_VERSION defines the SILC software major.minor version and
# it is increment only when these version numbers actually change.
# Base version for libraries. Do not change this unless SILC version
# changes too.
-LIB_BASE_VERSION=1.1
+LIB_BASE_VERSION=1.0
# libsilc versions
-LIBSILC_CURRENT=1 # prev = 0
-LIBSILC_REVISION=0 # prev = 0
-LIBSILC_AGE=0 # prev = 0
+LIBSILC_CURRENT=6 # prev = 6 (Toolkit 1.0.1)
+LIBSILC_REVISION=1 # prev = 0
+LIBSILC_AGE=4 # prev = 4
# libsilcclient versions
-LIBSILCCLIENT_CURRENT=1 # prev = 0
-LIBSILCCLIENT_REVISION=0 # prev = 0
-LIBSILCCLIENT_AGE=0 # prev = 0
-
-# libsilcserver versions
-LIBSILCSERVER_CURRENT=1 # prev = 0
-LIBSILCSERVER_REVISION=0 # prev = 0
-LIBSILCSERVER_AGE=0 # prev = 0
+LIBSILCCLIENT_CURRENT=4 # prev = 4 (Toolkit 1.0.1)
+LIBSILCCLIENT_REVISION=2 # prev = 1
+LIBSILCCLIENT_AGE=3 # prev = 3
# Substitute the version numbers
AC_SUBST(LIB_BASE_VERSION)
AC_SUBST(LIBSILCCLIENT_CURRENT)
AC_SUBST(LIBSILCCLIENT_REVISION)
AC_SUBST(LIBSILCCLIENT_AGE)
-AC_SUBST(LIBSILCSERVER_CURRENT)
-AC_SUBST(LIBSILCSERVER_REVISION)
-AC_SUBST(LIBSILCSERVER_AGE)
-
-# Check for big-endian machines
-AC_C_BIGENDIAN
-
-# Check for epoll_wait and verify that epoll_create works
-AC_CHECK_FUNC(epoll_wait,
- [
- AC_RUN_IFELSE(
- [
- #include <sys/epoll.h>
- int main()
- {
- int ret = epoll_create(5);
- if (ret < 0)
- return 1;
- close(ret);
- return 0;
- }
- ],
- [
- AC_DEFINE([HAVE_EPOLL_WAIT], [1], [HAVE_EPOLL_WAIT])
- ],
- )
- ])
#ifdef SILC_DIST_SIM
# SIM modules directory
)
#endif SILC_DIST_TOOLKIT
-#ifdef SILC_DIST_INPLACE
-#
-# Profiling options (never delivered to distributions)
-#
-AC_MSG_CHECKING(whether to enable gprof)
-AC_ARG_ENABLE(gprof,
- [ --enable-gprof enable gprof profiling],
- [
- case "${enableval}" in
- yes)
- AC_MSG_RESULT(yes)
- SILC_ADD_CFLAGS(-pg)
- LIBS="$LIBS -pg"
- ;;
- *)
- AC_MSG_RESULT(no)
- ;;
- esac
- ],
- [
- AC_MSG_RESULT(no)
- ])
-
-AC_MSG_CHECKING(whether to enable gcov)
-AC_ARG_ENABLE(gcov,
- [ --enable-gcov enable gcov],
- [
- case "${enableval}" in
- yes)
- AC_MSG_RESULT(yes)
- SILC_ADD_CFLAGS(-fprofile-arcs)
- LIBS="$LIBS -lgcov"
- ;;
- *)
- AC_MSG_RESULT(no)
- ;;
- esac
- ],
- [
- AC_MSG_RESULT(no)
- ])
-#endif SILC_DIST_INPLACE
-
#
# Makefile outputs
#
lib/Makefile
lib/contrib/Makefile
lib/silccore/Makefile
+lib/silccrypt/Makefile
#ifdef SILC_DIST_SIM
lib/silcsim/Makefile
#endif SILC_DIST_SIM
lib/silcutil/Makefile
lib/silcutil/unix/Makefile
lib/silcutil/win32/Makefile
-lib/silcutil/symbian/Makefile
-lib/silcapputil/Makefile
+lib/silcutil/beos/Makefile
+lib/silcutil/os2/Makefile
+lib/silcutil/epoc/Makefile
#ifdef SILC_DIST_SFTP
lib/silcsftp/Makefile
#endif SILC_DIST_SFTP
#ifdef SILC_DIST_INPLACE
lib/silcutil/tests/Makefile
+lib/silccrypt/tests/Makefile
lib/silccore/tests/Makefile
lib/silcsftp/tests/Makefile
#endif SILC_DIST_INPLACE
AC_CONFIG_FILES(
lib/silc.pc
lib/silcclient.pc
-lib/silcserver.pc
)
#endif SILC_DIST_TOOLKIT
#ifdef SILC_DIST_CLIENTLIB
-AC_CONFIG_FILES(
-lib/silcclient/Makefile
-lib/silcclient/tests/Makefile
-)
+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
-#ifdef SILC_DIST_INPLACE
-lib/silcasn1/tests/Makefile
-#endif SILC_DIST_INPLACE
-)
-#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
-
-#ifdef SILC_DIST_HTTP
-AC_CONFIG_FILES(
-lib/silchttp/Makefile
-lib/silchttp/tests/Makefile
-)
-#endif SILC_DIST_HTTP
-
-#ifdef SILC_DIST_VCARD
-AC_CONFIG_FILES(
-lib/silcvcard/Makefile
-)
-#endif SILC_DIST_VCARD
-
fi # compile_libs
#endif SILC_DIST_LIB
libcontrib_la_SOURCES = getopti.c $(STRINGPREP) $(REGEX)
endif
+#ifdef SILC_DIST_TOOLKIT
+if HAVE_REGEX
+REGEXH =
+else
+REGEXH = regexpr.h
+endif
+include_HEADERS = \
+ $(REGEXH) \
+ getopti.h \
+ gunicomp.h \
+ gunidecomp.h \
+ stringprep.h
+#endif SILC_DIST_TOOLKIT
+
EXTRA_DIST = *.c *.h
include $(top_srcdir)/Makefile.defines.in
/* Our own convenience getopt. Public Domain. */
-#include "silc.h"
+#include "silcincludes.h"
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
#if !defined(HAVE_GETOPT) && !defined(HAVE_GETOPT_H)
int opterr = 1;
int optind = 1;
return c;
}
#endif /* !HAVE_GETOPT && !HAVE_GETOPT_H */
-#endif /* !SILC_SYMBIAN */
+#endif /* !SILC_EPOC */
#ifndef GETOPTI_H
#define GETOPTI_H
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
#if !defined(HAVE_GETOPT) && !defined(HAVE_GETOPT_H)
/* Our own convenience getopt. */
extern int opterr;
extern char *optarg;
int getopt(int argc, char * const *argv, const char *optstring);
#endif /* !HAVE_GETOPT && !HAVE_GETOPT_H */
-#endif /* !SILC_SYMBIAN */
+#endif /* !SILC_EPOC */
#endif /* GETOPTI_H */
*/
-#include "silc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
+//#include "silcincludes.h"
#include "regexpr.h"
#define MACRO_BEGIN do {
#include <stddef.h> /* size_t */
#include <stdlib.h>
-#include "silc.h"
+#include "silcincludes.h"
#ifndef uint32_t
#define uint32_t SilcUInt32
<br />
<small>
Version: @VERSION@<br />
-Copyright © 1997 - 2007 The SILC Project<br />
+Copyright © 1997 - 2005 The SILC Project<br />
Updated: @DATE@
</small>
-<br /><br /><br />
-<b>NOTE: This is reference manual of alpha version of SILC Toolkit 1.1 and
-the reference may be incomplete, inaccurate and document nonexistent APIs.
-The APIs provided by alpha versions of SILC Toolkit 1.1 may not be stable yet.
-</b>
-
<br /><br /><br />
Welcome to the SILC Toolkit Reference Manual. The manual is a complete
developer guide and reference for the SILC application programmer. The manual
of the Toolkit always delivers the latest version of this reference manual.
<br /><br /><br />
-<li><a href="porting.html">Porting from Toolkit 1.0 to 1.1</a><br />
<li><a href="intro_reference.html">Introduction to the Manual</a><br />
<li><a href="programming_conv.html">Programming Conventions</a><br />
<li><a href="building.html">Building the Toolkit</a>
<br /><br />
<b>Resource Links</b>
<br /><br />
-Please refer to these outside links for more information about the SILC
+Please refer to these outside links for more information about the SILC
project and SILC Protocol.
<br /><br />
<td><small>
Returns information about user. The following pointers may be NULL: 'channels',
'fingerprint', 'channel_usermodes' and 'attrs'. If 'fingerprint' is valid its
-length is 20 bytes. If 'channels' is valid each entry in the list is
-SilcChannelPayload. If the `channel_usermodes' is valid then the table
-has as many entries as there are entries in the `channels' list, and the
-first entry in the table is the user mode on the first channel in the
-`channels' list. The `channel_usermodes' is the table of the user's modes
-no the joined channels. The 'attr' is the Requested Attributes that may
-have been returned by the client and it can be parsed by traversing the
-SilcDList and using silc_attribute_get_attribute function. Each entry in
-the list is SilcAttribute.
+length is 20 bytes. If 'channels' is valid it can be parsed with
+silc_channel_payload_parse_list function. It is the list of channels user
+has joined. If the 'channel_usermodes' is valid it can be parsed with
+silc_get_mode_list function. It is the list of the user's modes on the
+joined channels. The 'attr' is the Requested Attributes that may have been
+returned by the client and it can be parsed by traversing the SilcDList
+and using silc_attribute_get_attribute function.
</td>
<td width="50%"><small>SilcClientEntry client_entry, char *nickname,
-char *username, char *realname, SilcDList channels, SilcUInt32 usermode,
-SilcUInt32 idletime, unsigned char *fingerprint, SilcUInt32 *channel_usermodes,
+char *username, char *realname, SilcBuffer channels, SilcUInt32 usermode,
+SilcUInt32 idletime, unsigned char *fingerprint, SilcBuffer channel_usermodes,
SilcDList attrs
</td>
</tr>
<td><small>SILC_COMMAND_NICK</td>
<td><small>
Returns the new Client ID and new nickname inside the SilcClientEntry.
-The `old_client_id' is the old Client ID used by the client before the
-nickname was changed. The `nickname' is the new nickname.
+The `old_client_id' is the odl Client ID used by the client before the
+nickname was changed.
</td>
<td width="50%"><small>SilcClientEntry local_entry, char *nickname,
const SilcClientID *old_client_id
Returns the invite list of the channel. Called also even if invite list
was not modified but SILC_COMMAND_INVITE command was used to invite a user
into a channel. In this case the invite list is not returned by the
-server and 'invite_list' is NULL. The 'invite_list' is SilcArgumenPayload
-which contains one or more arguments, each is one invite list entry. The
-entries can be retrieved with silc_argument_get_first_arg,
-silc_argument_get_next_arg, silc_argument_get_arg_type and
-silc_argument_get_decoded functions.
+server and 'invite_list' is NULL. The 'invite_list' is list of
+SilcArgumentPayloads. The first 2 bytes are the number of arguments in
+the list and can be parsed with SILC_GET16_MSB macro. The list can be
+parsed with silc_argument_payload_parse function.
</td>
-<td width="50%"><small>SilcChannelEntry channel,
-SilcArgumentPayload invite_list
+<td width="50%"><small>SilcChannelEntry channel, SilcBuffer invite_list
</td>
</tr>
<td><small>SILC_COMMAND_KILL</td>
<td><small>
Called after killing a client. Returns the client that was killed.
-The `client_entry' may be NULL. The `client_entry' will become invalid
-after the command reply has returned from application. The
-SILC_NOTIFY_TYPE_KILLED will not be delivered for clients that you killed.
+The `client_entry' may be NULL.
</td>
<td width="50%"><small>SilcClientEntry client_entry
</td>
<tr>
<td><small>SILC_COMMAND_STATS</td>
<td><small>
-Returns network statistics from the server. The `stats' structure contains
-the statistics returned by the server.
+Returns network statistics from the server. The 'stats_buffer' of length of
+'buffer_length' bytes includes 32-bit integers one after the other each
+representing some statistics. The integers can be parsed for example with
+SILC_GET32_MSB macro. The integers in the buffer are: starttime, uptime,
+local_clients, local_channels, local_serverops, local_routerops, cell_clients,
+cell_channels, cell_servers, all_clients, all_channel, all_servers,
+all_routers, all_serverops, all_routerops. All integers are always present.
</td>
-<td width="50%"><small>SilcClientStats *stats
+<td width="50%"><small>unsigned char *stats_buffer, SilcUInt32 buffer_length
</td>
</tr>
<tr>
<td><small>SILC_COMMAND_JOIN</td>
<td><small>
-Reply received when user joined a channel. The `channel_mode' contains
-the current channel mode. The `user_list' is the user list on the channel
-and may be traversed with silc_hash_table_get function. Each entry in the
-`user_list' is SilcChannelUser structure, which contains the SilcClientEntry
-and the client's mode on the channel. The library will free the list.
-The `topic' is the current topic on channel or NULL if no topic is set.
-The `cipher' is the encryption algorithm used on channel or NULL if it is
-not available. The `hmac' is the HMAC algorithm used on channel or NULL if
-it is not available. The `founder_key' is the channel founder's public key
-or NULL if founder public key has not been set. The `channel_pubkeys' is
-a list of channel public keys (for authentication on joining) or NULL if
-they have not been set. Each entry in the list is SilcArgumentDecodedList
-each containing one channel public key. The library will free the list.
+Reply received when user joined a channel. The 'ignored' argument can
+be ignored by the application. The 'topic' and 'hmac_name' may be NULL.
+The 'key_payload' is usually ignored by the application. The 'list_count'
+is the number of entries in both 'client_id_list' and 'client_mode_list'.
+The 'client_id_list' is a list of clients on the channel and 'client_mode_list'
+includes those clients' modes on the channel. If application likes to
+resolve information about the clients on the channel it may call
+silc_client_get_clients_by_list function and pass the 'client_id_list' as
+argument to it. The 'client_mode_list' includes 32-bit integers one after
+the other and they are in same order as clients in 'client_mode_list'.
+If application resolves the information with silc_client_get_clients_by_list
+parsing the 'client_mode_list' is not necessary. The 'founder_key' is the
+channel founder's key and may be NULL. The 'channel_pubkeys' is Argument
+List Payload containing Public Key Payloads of all added channel public
+keys, it may be NULL.
</td>
<td width="50%"><small>char *channel_name, SilcChannelEntry channel,
-SilcUInt32 channel_mode, SilcHashTableList *user_list, char *topic,
-char *cipher, char *hmac, SilcPublicKey founder_key,
-SilcDList channel_pubkeys, SilcUint32 user_limit
+SilcUInt32 channel_mode, int ignored, SilcBuffer key_payload, NULL, NULL,
+char *topic, char *hmac_name, SilcUInt32 list_count, SilcBuffer client_id_list,
+SilcBuffer client_mode_list, SilcPublicKey founder_key,
+SilcBuffer channel_pubkeys, SilcUint32 user_limit
</td>
</tr>
Returns channel's mode after changing it. Optionally may also return
founder's public key when it was set. It may also return the channel
public key list when the list was altered. The 'founder_key' and
-'channel_pubkeys' arguments may be NULL. The 'channel_pubkeys' is a list
-of SilcArgumentDecodedList contexts which each contain one channel public
-key. The library will automatically free the list.
+'channel_pubkeys' arguments may be NULL. The 'channel_pubkeys' is an
+Argument List Payload where each argument includes one Public Key
+Payload.
</td>
<td width="50%"><small>SilcChannelEntry channel, SilcUInt32 mode,
-SilcPublicKey founder_key, SilcDList channel_pubkeys, SilcUint32 user_limit
+SilcPublicKey founder_key, SilcBuffer channel_pubkeys,
+SilcUint32 user_limit
</td>
</tr>
<td><small>SILC_COMMAND_KICK</td>
<td><small>
Called after kicking a client. Returns the client that was kicked from
-the 'channel'.
+the 'channel'. The `client_entry' and 'channel' may be NULL.
</td>
<td width="50%"><small>SilcChannelEntry channel, SilcClientEntry client_entry
</td>
of that list is equivalent to invite list. See description of
SILC_COMMAND_INVITE command reply.
</td>
-<td width="50%"><small>SilcChannelEntry channel, SilcArgumentPayload ban_list
+<td width="50%"><small>SilcChannelEntry channel, SilcBuffer ban_list
</td>
</tr>
<tr>
<td><small>SILC_COMMAND_DETACH</td>
<td><small>
-Called after being detached from the SILC network. The command reply delivers
-the detachment data buffer `detach_data' that the application should save
-for example into a file. The data will be needed when resuming back to
-the network. When resuming the data is saved into SilcClientConnectionParams
-structure and given as argument to silc_client_connect_to_server or
-silc_client_key_exchange functions.
+Called after being detached from the SILC network. There is no arguments
+to this reply.
</td>
-<td width="50%"><small>SilcBuffer detach_data
+<td width="50%"><small>none
</td>
</tr>
<tr>
<td><small>SILC_COMMAND_USERS</td>
<td><small>
-Returns list of users in channel. The `user_list' may be traversed with
-silc_hash_table_get function. Each entry in the `user_list' is
-SilcChannelUser structure, which contains the SilcClientEntry and the
-client's mode on the channel.
+Returns list of users in channel. If application wishes not to parse
+the raw lists the channel->user_list hash table is updated before calling
+this command reply and application may traverse that table instead of
+parssing the raw lists.
</td>
-<td width="50%"><small>SilcChannelEntry channel, SilcHashTableList *user_list
+<td width="50%"><small>SilcChannelEntry channel, SilcUInt32 list_count,
+SilcBuffer client_id_list, SilcBuffer client_mode_list
</td>
</tr>
<tr>
<td><small>SILC_NOTIFY_TYPE_INVITE</td>
<td><small>
-Sent to the client if the user is invited on a channel. The 'channel
-argument may be NULL but the `channel_name' is always provided.
+Sent to the client if the user is invited on a channel. The 'channel_name'
+argument may be NULL.
</td>
<td width="50%"><small>SilcClientChannel channel, char *channel_name,
SilcClientEntry inviter
<tr>
<td><small>SILC_NOTIFY_TYPE_JOIN</td>
<td><small>
-Sent when someone joins to a channel. This is also sent whenever you join
-a channel, in addition of receiving SILC_COMMAND_JOIN command reply.
+Sent when someone joins to a channel.
</td>
<td width="50%"><small>SilcClientEntry joining_client, SilcChannelEntry channel
</td>
<tr>
<td><small>SILC_NOTIFY_TYPE_NICK_CHANGE</td>
<td><small>
-Sent when someone changes their nickname. The 'client_entry' is the client
-whose nickname is changed. The `old_nickname' is the old nickname and the
-`new_nickname' is the new nickname. It has been already updated into the
-`client_entry'.
+Sent when someone changes their nickname. The 'old_client_entry' includes
+the old nickname and the 'new_client_entry' includes the new nickname.
+Application must understand that the 'old_client_entry' pointer becomes
+invalid after returning from the function. Note that this notify is not
+delivered when user changes its own nickname.
</td>
-<td width="50%"><small>SilcClientEntry client_entry, const char *old_nickname,
-const char *new_nickname
+<td width="50%"><small>SilcClientEntry old_client_entry,
+SilcClientEntry new_client_entry
</td>
</tr>
The `hmac_name' is the HMAC set for the channel. The `passphrase'
is the passphrase that was set for the channel. The `founder_key' is the
founder's public key when it was set for the channel. The `channel_pubkeys'
-is a list of SilcArgumentDecodedList contexts each containing one channel
-public key. The library will free the list automatically. The arguments
-'cipher_name', 'hmac_name', 'passphrase', 'founder_key' and 'channel_pubkeys'
-may be NULL.
+is an Argument List Payload where each argument is Public Key Payload
+containing one channel public key. The arguments 'cipher_name', 'hmac_name',
+'passphrase', 'founder_key' and 'channel_pubkeys' may be NULL.
</td>
<td width="50%"><small>SilcIdType changer_id_type, void *changer_entry,
SilcUInt32 mode, char *cipher_name, char *hmac_name, char *passphrase,
-SilcPublicKey founder_key, SilcDList channel_pubkeys, SilcChannelEntry channel
+SilcPublicKey founder_key, SilcBuffer channel_pubkeys, SilcChannelEntry channel
</td>
</tr>
<tr>
<td><small>SILC_NOTIFY_TYPE_SERVER_SIGNOFF</td>
<td><small>
-Sent when a server quits the network. The 'clients' is a list of
-SilcClientEntry pointers. Each client in the entry is one client signing
-off from the SILC network. The library will free the list. The `server'
-is the quitting server, and it is NULL if the server isn't cached in the
-client library.
+Sent when a server quits the network. The 'clients' is an array
+SilcClientEntry pointers of size of 'clients_count'. Each client in the
+entry is one client signing off from the SILC network.
</td>
-<td width="50%"><small>SilcServerEntry server, SilcDList clients
+<td width="50%"><small>NULL, SilcClientEntry *clients, SilcUInt32 clients_count
</td>
</tr>
Otherwise this pointer is NULL. The 'user_mode' is the client's mode in
the SILC network. The 'notification' contains the notify type that
happened for the 'watched_client' (for example
-SILC_NOTIFY_TYPE_NICK_CHANGE if the client changed their nickname). If
-the `new_nickname' is NULL and `notification' is SILC_NOTIFY_TYPE_NONE the
-`watched_client' has just joined the network.
+SILC_NOTIFY_TYPE_NICK_CHANGE if the client changed their nickname).
</td>
<td width="50%"><small>SilcClientEntry watched_client, char *new_nickname,
-SilcUInt32 user_mode, SilcNotifyType notification, SilcPublicKey
+SilcUInt32 user_mode, SilcNotifyType notification, SilcPublicKey
public_key
</td>
</tr>
<li><a href="#unix">Unix & Linux Implementation</a><br />
<li><a href="#windows">Windows Implementation</a><br />
<li><a href="#macosx">Mac OS X Implementation</a>
-<li><a href="#symbian">Symbian Implementation</a>
<br /> <br /> <br />
<b>Supported Platforms</b>
<br /> <br />
-SILC Toolkit supports by default all Unix and Linux platforms, Windows
+SILC Toolkit supports by default all Unix and Linux platforms, Windows
platforms from Windows 98 and newer, and Mac OS X. In the future there is
also plans to add support for other platforms such as Symbian OS (EPOC).
OS X platform. There are no special Mac OS X platform related
implementation issues with current version of SILC Toolkit.
-
-<br /> <br /> <br />
-<b><a name="symbian"></a>Symbian Implementation</b>
-
-<br /> <br />
-Symbian support in SILC Toolkit is still experimental. By default all
-feature and components delivered with SILC Toolkit are supported on
-Symbian. However, there are some certain issues with the Symbian version
-of the SILC Toolkit
-
-<br /> <br />
-<li>The function <tt>silc_schedule</tt> on Symbian will return immediately,
-instead of blocking the calling thread/process as on other platforms. On
-symbian the function is equivalent to <tt>silc_schedule_one</tt>, and that
-function should be used instead. The design of SilcSchedule on Symbian
-enables efficient data I/O even when <tt>silc_schedule_one</tt> is called
-from a timer task. The data I/O is scheduled separately by the Symbian
-Active Scheduler and the SilcSchedule will merely schedule timeouts.
-
-<li>The function <tt>silc_client_run</tt> on Symbian will return immediately.
-On symbian the <tt>silc_client_run_one<tt> should be used instead. It can
-used from a timer or from an idle task.
<br /> <br />
<tt>
-#include "silc.h"<br />
+#include "silcincludes.h"<br />
#include "silcclient.h"
</tt>
<br /> <br />
<pre>
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
int main()
Name: @PACKAGE@
Description: SILC Library
Version: @VERSION@
+Conflicts: libsilc <= 0.9.12
Libs: -L${libdir} -lsilc @LIBS@
Cflags: -I${includedir}
+++ /dev/null
-<!--
-@LIBRARY=SILC Application Utility Library
-@FILENAME=silcaputillib.html
-@LINK=silcapputil.html:SILC Application Utilities
-@LINK=silcidcache.html:SILC ID Cache Interface
--->
-
-<big><b>SILC Application Utility Library</b></big>
-<br />
-<small>Directory: lib/silcapputil/</small>
-<br />
-<small>Library: libsilc.a, libsilc.lib</small>
-<br /><br />
-<b>Introduction</b>
-
-<br /><br />
-SILC Application Utility library provides various SILC application
-specific utility functions. For example, it provides routines for
-creating and loading SILC key pair.
-
-<br /><br />
-@LINKS@
+++ /dev/null
-#
-# Makefile.ad
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2006 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 = libsilcapputil.la
-
-libsilcapputil_la_SOURCES = \
- silcapputil.c \
-#ifdef SILC_DIST_IDCACHE
- silcidcache.c
-#endif SILC_DIST_IDCACHE
-
-#ifdef SILC_DIST_TOOLKIT
-include_HEADERS = \
- silcapputil.h \
-#ifdef SILC_DIST_IDCACHE
- silcidcache.h
-#endif SILC_DIST_IDCACHE
-
-SILC_EXTRA_DIST =
-#endif SILC_DIST_TOOLKIT
-
-EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-/*
-
- silcapputil.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2002 - 2007 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"
-
-static char *silc_create_pk_identifier(void)
-{
- char *username = NULL, *realname = NULL;
- char *hostname, email[256];
- char *ident;
-
- /* Get realname */
- realname = silc_get_real_name();
-
- /* Get hostname */
- hostname = silc_net_localhost();
- if (!hostname)
- return NULL;
-
- /* Get username (mandatory) */
- username = silc_get_username();
- if (!username)
- return NULL;
-
- /* Create default email address, whether it is right or not */
- silc_snprintf(email, sizeof(email), "%s@%s", username, hostname);
-
- ident = silc_pkcs_silc_encode_identifier(username, hostname, realname,
- email, NULL, NULL, NULL);
- if (realname)
- silc_free(realname);
- silc_free(hostname);
- silc_free(username);
-
- return ident;
-}
-
-/* Generate key pair */
-
-SilcBool silc_create_key_pair(const char *pkcs_name,
- SilcUInt32 key_len_bits,
- const char *pub_filename,
- const char *prv_filename,
- const char *pub_identifier,
- const char *passphrase,
- SilcPublicKey *return_public_key,
- SilcPrivateKey *return_private_key,
- SilcBool interactive)
-{
- SilcRng rng;
- char line[256];
- char *pkfile = pub_filename ? strdup(pub_filename) : NULL;
- char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
- char *alg = pkcs_name ? strdup(pkcs_name) : NULL;
- char *identifier = pub_identifier ? strdup(pub_identifier) : NULL;
- char *pass = passphrase ? strdup(passphrase) : NULL;
- SilcPublicKey public_key;
- SilcPrivateKey private_key;
-
- if (interactive && (!alg || !pub_filename || !prv_filename))
- printf("\
-New pair of keys will be created. Please, answer to following questions.\n\
-");
-
- if (!alg) {
- if (interactive) {
- while (!alg) {
- alg = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
- if (!alg)
- alg = strdup("rsa");
-
- if (*alg == 'l' || *alg == 'L') {
- char *list = silc_pkcs_get_supported();
- printf("%s\n", list);
- silc_free(list);
- silc_free(alg);
- alg = NULL;
- }
- }
- } else {
- alg = strdup("rsa");
- }
- }
-
- if (!silc_pkcs_find_algorithm(alg, NULL)) {
- fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library"
- "is not initialized", alg);
- return FALSE;
- }
-
- if (!key_len_bits) {
- if (interactive) {
- char *length = NULL;
- length = silc_get_input("Key length in key_len_bits [2048]: ", FALSE);
- if (length)
- key_len_bits = atoi(length);
- silc_free(length);
- }
- if (!key_len_bits)
- key_len_bits = 2048;
- }
-
- if (!identifier) {
- char *def = silc_create_pk_identifier();
-
- if (interactive) {
- memset(line, 0, sizeof(line));
- if (def)
- silc_snprintf(line, sizeof(line), "Identifier [%s]: ", def);
- else
- silc_snprintf(line, sizeof(line),
- "Identifier (eg. UN=jon, HN=jon.dummy.com, "
- "RN=Jon Johnson, E=jon@dummy.com): ");
-
- while (!identifier) {
- identifier = silc_get_input(line, FALSE);
- if (!identifier && def)
- identifier = strdup(def);
- }
- } else {
- if (!def) {
- fprintf(stderr, "Could not create public key identifier: %s\n",
- strerror(errno));
- return FALSE;
- }
- identifier = strdup(def);
- }
-
- silc_free(def);
- }
-
- rng = silc_rng_alloc();
- silc_rng_init(rng);
- silc_rng_global_init(rng);
-
- if (!pkfile) {
- if (interactive) {
- memset(line, 0, sizeof(line));
- silc_snprintf(line, sizeof(line), "Public key filename [public_key.pub]: ");
- pkfile = silc_get_input(line, FALSE);
- }
- if (!pkfile)
- pkfile = strdup("public_key.pub");
- }
-
- if (!prvfile) {
- if (interactive) {
- memset(line, 0, sizeof(line));
- silc_snprintf(line, sizeof(line), "Private key filename [private_key.prv]: ");
- prvfile = silc_get_input(line, FALSE);
- }
- if (!prvfile)
- prvfile = strdup("private_key.prv");
- }
-
- if (!pass) {
- while (TRUE) {
- char *pass2 = NULL;
- pass = silc_get_input("Private key passphrase: ", TRUE);
- if (!pass) {
- pass = strdup("");
- break;
- } else {
- SilcBool match;
- printf("\n");
- pass2 = silc_get_input("Retype private key passphrase: ", TRUE);
- if (!pass2)
- pass2 = strdup("");
- match = !strcmp(pass, pass2);
- silc_free(pass2);
- if (match)
- break;
- fprintf(stderr, "\nPassphrases do not match\n\n");
- }
- }
- }
-
- if (interactive)
- printf("\nGenerating the key pair...\n");
-
- /* Generate keys */
- if (!silc_pkcs_silc_generate_key(alg, key_len_bits,
- identifier, rng, &public_key,
- &private_key))
- return FALSE;
-
- /* Save public key into file */
- silc_pkcs_save_public_key(pkfile, public_key, SILC_PKCS_FILE_BASE64);
-
- /* Save private key into file */
- silc_pkcs_save_private_key(prvfile, private_key,
- (const unsigned char *)pass, strlen(pass),
- SILC_PKCS_FILE_BIN, rng);
-
- if (return_public_key)
- *return_public_key = public_key;
- else
- silc_pkcs_public_key_free(public_key);
-
- if (return_private_key)
- *return_private_key = private_key;
- else
- silc_pkcs_private_key_free(private_key);
-
- printf("Public key has been saved into `%s'.\n", pkfile);
- printf("Private key has been saved into `%s'.\n", prvfile);
- if (interactive) {
- printf("Press <Enter> to continue...\n");
- getchar();
- }
-
- silc_rng_free(rng);
- silc_free(alg);
- silc_free(pkfile);
- silc_free(prvfile);
- silc_free(identifier);
- memset(pass, 0, strlen(pass));
- silc_free(pass);
-
- return TRUE;
-}
-
-/* Load key pair */
-
-SilcBool silc_load_key_pair(const char *pub_filename,
- const char *prv_filename,
- const char *passphrase,
- SilcPublicKey *return_public_key,
- SilcPrivateKey *return_private_key)
-{
- char *pass = passphrase ? strdup(passphrase) : NULL;
-
- SILC_LOG_DEBUG(("Loading public and private keys"));
-
- if (!silc_pkcs_load_public_key(pub_filename, return_public_key)) {
- if (pass)
- memset(pass, 0, strlen(pass));
- silc_free(pass);
- return FALSE;
- }
-
- if (!pass) {
- pass = silc_get_input("Private key passphrase: ", TRUE);
- if (!pass)
- pass = strdup("");
- }
-
- if (!silc_pkcs_load_private_key(prv_filename,
- (const unsigned char *)pass, strlen(pass),
- return_private_key)) {
- memset(pass, 0, strlen(pass));
- silc_free(pass);
- return FALSE;
- }
-
- memset(pass, 0, strlen(pass));
- silc_free(pass);
- return TRUE;
-}
-
-/* Dump public key into stdout */
-
-SilcBool silc_show_public_key(SilcPublicKey public_key)
-{
- SilcSILCPublicKey silc_pubkey;
- SilcPublicKeyIdentifier ident;
- char *fingerprint, *babbleprint;
- unsigned char *pk;
- SilcUInt32 pk_len;
- SilcUInt32 key_len = 0;
-
- silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
- if (!silc_pubkey) {
- silc_pkcs_public_key_free(public_key);
- return FALSE;
- }
-
- ident = &silc_pubkey->identifier;
- key_len = silc_pkcs_public_key_get_len(public_key);
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
- if (!pk) {
- silc_pkcs_public_key_free(public_key);
- return FALSE;
- }
- fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
- babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
-
- printf("Algorithm : %s\n", silc_pkcs_get_name(public_key));
- if (key_len)
- printf("Key length (bits) : %d\n", (unsigned int)key_len);
- if (ident->version)
- printf("Version : %s\n", ident->version);
- if (ident->realname)
- printf("Real name : %s\n", ident->realname);
- if (ident->username)
- printf("Username : %s\n", ident->username);
- if (ident->host)
- printf("Hostname : %s\n", ident->host);
- if (ident->email)
- printf("Email : %s\n", ident->email);
- if (ident->org)
- printf("Organization : %s\n", ident->org);
- if (ident->country)
- printf("Country : %s\n", ident->country);
- printf("Fingerprint (SHA1) : %s\n", fingerprint);
- printf("Babbleprint (SHA1) : %s\n", babbleprint);
-
- fflush(stdout);
-
- silc_free(fingerprint);
- silc_free(babbleprint);
- silc_free(pk);
-
- return TRUE;
-}
-
-/* Dump public key into stdout */
-
-SilcBool silc_show_public_key_file(const char *pub_filename)
-{
- SilcPublicKey public_key;
- SilcBool ret;
-
- if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
- fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
- return FALSE;
- }
-
- printf("Public key file : %s\n", pub_filename);
- ret = silc_show_public_key(public_key);
- silc_pkcs_public_key_free(public_key);
-
- return ret;
-}
-
-/* Change private key passphrase */
-
-SilcBool silc_change_private_key_passphrase(const char *prv_filename,
- const char *old_passphrase,
- const char *new_passphrase)
-{
- SilcPrivateKey private_key;
- char *pass;
- SilcRng rng;
-
- pass = old_passphrase ? strdup(old_passphrase) : NULL;
- if (!pass) {
- pass = silc_get_input("Old passphrase: ", TRUE);
- if (!pass)
- pass = strdup("");
- }
-
- if (!silc_pkcs_load_private_key(prv_filename,
- (const unsigned char *)pass, strlen(pass),
- &private_key)) {
- memset(pass, 0, strlen(pass));
- silc_free(pass);
- fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
- return FALSE;
- }
-
- memset(pass, 0, strlen(pass));
- silc_free(pass);
-
- pass = new_passphrase ? strdup(new_passphrase) : NULL;
- if (!pass) {
- char *pass2 = NULL;
- fprintf(stdout, "\n");
- pass = silc_get_input("New passphrase: ", TRUE);
- if (!pass) {
- pass = strdup("");
- } else {
- while (TRUE) {
- printf("\n");
- pass2 = silc_get_input("Retype new passphrase: ", TRUE);
- if (!pass2)
- pass2 = strdup("");
- if (!strcmp(pass, pass2))
- break;
- fprintf(stderr, "\nPassphrases do not match");
- }
- silc_free(pass2);
- }
- }
-
- rng = silc_rng_alloc();
- silc_rng_init(rng);
-
- silc_pkcs_save_private_key((char *)prv_filename, private_key,
- (unsigned char *)pass, strlen(pass),
- SILC_PKCS_FILE_BIN, rng);
-
- fprintf(stdout, "\nPassphrase changed\n");
-
- memset(pass, 0, strlen(pass));
- silc_free(pass);
-
- silc_pkcs_private_key_free(private_key);
- silc_rng_free(rng);
-
- return TRUE;
-}
-
-/* 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, channel names,
- server names, usernames, hostnames, service names, algorithm names,
- other security property names, and SILC Public Key name. */
-
-unsigned char *silc_identifier_check(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length,
- SilcUInt32 *out_len)
-{
- unsigned char *utf8s;
- SilcUInt32 utf8s_len;
- SilcStringprepStatus status;
-
- if (!identifier || !identifier_len)
- return NULL;
-
- if (max_allowed_length && identifier_len > max_allowed_length)
- return NULL;
-
- status = silc_stringprep(identifier, identifier_len,
- identifier_encoding, SILC_IDENTIFIER_PREP, 0,
- &utf8s, &utf8s_len, SILC_STRING_UTF8);
- if (status != SILC_STRINGPREP_OK) {
- SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
- return NULL;
- }
-
- if (out_len)
- *out_len = utf8s_len;
-
- return utf8s;
-}
-
-/* Same as above but does not allocate memory, just checks the
- validity of the string. */
-
-SilcBool silc_identifier_verify(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length)
-{
- SilcStringprepStatus status;
-
- if (!identifier || !identifier_len)
- return FALSE;
-
- if (max_allowed_length && identifier_len > max_allowed_length)
- return FALSE;
-
- status = silc_stringprep(identifier, identifier_len,
- identifier_encoding, SILC_IDENTIFIER_PREP, 0,
- NULL, NULL, SILC_STRING_UTF8);
- if (status != SILC_STRINGPREP_OK) {
- SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-unsigned char *silc_channel_name_check(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length,
- SilcUInt32 *out_len)
-{
- unsigned char *utf8s;
- SilcUInt32 utf8s_len;
- SilcStringprepStatus status;
-
- if (!identifier || !identifier_len)
- return NULL;
-
- if (max_allowed_length && identifier_len > max_allowed_length)
- return NULL;
-
- status = silc_stringprep(identifier, identifier_len,
- identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
- &utf8s, &utf8s_len, SILC_STRING_UTF8);
- if (status != SILC_STRINGPREP_OK) {
- SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
- return NULL;
- }
-
- if (out_len)
- *out_len = utf8s_len;
-
- return utf8s;
-}
-
-/* Same as above but does not allocate memory, just checks the
- validity of the string. */
-
-SilcBool silc_channel_name_verify(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length)
-{
- SilcStringprepStatus status;
-
- if (!identifier || !identifier_len)
- return FALSE;
-
- if (max_allowed_length && identifier_len > max_allowed_length)
- return FALSE;
-
- status = silc_stringprep(identifier, identifier_len,
- identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
- NULL, NULL, SILC_STRING_UTF8);
- if (status != SILC_STRINGPREP_OK) {
- SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Return mode list */
-
-SilcBool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
- SilcUInt32 **list)
-{
- int i;
-
- if (silc_buffer_len(mode_list) / 4 != mode_list_count)
- return FALSE;
-
- *list = silc_calloc(mode_list_count, sizeof(**list));
-
- for (i = 0; i < mode_list_count; i++) {
- SILC_GET32_MSB((*list)[i], mode_list->data);
- silc_buffer_pull(mode_list, 4);
- }
-
- silc_buffer_push(mode_list, mode_list->data - mode_list->head);
-
- return TRUE;
-}
-
-/* Status message structure. Messages are defined below. */
-typedef struct {
- SilcStatus status;
- const char *message;
-} SilcStatusMessage;
-
-#define STAT(x) SILC_STATUS_ERR_##x
-static const SilcStatusMessage silc_status_messages[] = {
-
- { STAT(NO_SUCH_NICK), "There was no such nickname" },
- { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
- { STAT(NO_SUCH_SERVER), "There was no such server" },
- { STAT(INCOMPLETE_INFORMATION), "Incomplete registration information" },
- { STAT(NO_RECIPIENT), "No recipient given" },
- { STAT(UNKNOWN_COMMAND), "Unknown command" },
- { STAT(WILDCARDS), "Wilcrads not allowed" },
- { STAT(NO_CLIENT_ID), "No Client ID given" },
- { STAT(NO_CHANNEL_ID), "No Channel ID given" },
- { STAT(NO_SERVER_ID), "No Server ID given" },
- { STAT(BAD_CLIENT_ID), "Bad Client ID" },
- { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
- { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
- { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
- { STAT(NICKNAME_IN_USE), "Nickname already exists" },
- { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
- { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
- { STAT(USER_ON_CHANNEL), "User already on the channel" },
- { STAT(NOT_REGISTERED), "You have not registered" },
- { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
- { STAT(TOO_MANY_PARAMS), "Too many parameters" },
- { STAT(PERM_DENIED), "Permission denied" },
- { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
- { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
- { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
- { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
- { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
- { STAT(UNKNOWN_MODE), "Unknown mode" },
- { STAT(NOT_YOU), "Cannot change mode for other users" },
- { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
- { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
- { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
- { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
- { STAT(BAD_NICKNAME), "Bad nickname" },
- { STAT(BAD_CHANNEL), "Bad channel name" },
- { STAT(AUTH_FAILED), "Authentication failed" },
- { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
- { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
- { STAT(RESOURCE_LIMIT), "No more free resources" },
- { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
- { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
- { STAT(BAD_SERVER_ID), "Server ID is not valid" },
- { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
- { STAT(BAD_VERSION), "Bad version" },
- { STAT(TIMEDOUT), "Service timed out" },
- { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" },
- { STAT(OPERATION_ALLOWED), "Operation is not allowed" },
- { STAT(BAD_SERVER), "Bad server name" },
- { STAT(BAD_USERNAME), "Bad user name" },
-
- { 0, NULL }
-};
-
-/* Returns status message string */
-
-const char *silc_get_status_message(unsigned char status)
-{
- int i;
-
- for (i = 0; silc_status_messages[i].message; i++) {
- if (silc_status_messages[i].status == status)
- break;
- }
-
- if (silc_status_messages[i].message == NULL)
- return "";
-
- return silc_status_messages[i].message;
-}
-
-static const char *packet_name[] = {
- "NONE",
- "DISCONNECT",
- "SUCCESS",
- "FAILURE",
- "REJECT",
- "NOTIFY",
- "ERROR",
- "CHANNEL MESSAGE",
- "CHANNEL KEY",
- "PRIVATE MESSAGE",
- "PRIVATE MESSAGE KEY",
- "COMMAND",
- "COMMAND REPLY",
- "KEY EXCHANGE",
- "KEY EXCHANGE 1",
- "KEY EXCHANGE 2",
- "CONNECTION AUTH REQUEST",
- "CONNECTION AUTH",
- "NEW ID",
- "NEW CLIENT",
- "NEW SERVER",
- "NEW CHANNEL",
- "REKEY",
- "REKEY_DONE",
- "HEARTBEAT",
- "KEY AGREEMENT",
- "RESUME ROUTER",
- "FTP",
- "RESUME CLIENT",
-};
-
-/* Returns packet type name */
-
-const char *silc_get_packet_name(unsigned char type)
-{
- if (type >= SILC_PACKET_MAX)
- return "RESERVED";
- if (type >= SILC_PACKET_PRIVATE)
- return "PRIVATE RANGE";
- if (type > (sizeof(packet_name) / sizeof(*packet_name)))
- return "UNKNOWN";
- return packet_name[type];
-}
-
-static const char *command_name[] = {
- "NONE",
- "WHOIS",
- "WHOWAS",
- "IDENTIFY",
- "NICK",
- "LIST",
- "TOPIC",
- "INVITE",
- "QUIT",
- "KILL",
- "INFO",
- "STATS",
- "PING",
- "OPER",
- "JOIN",
- "MOTD",
- "UMODE",
- "CMODE",
- "CUMODE",
- "KICK",
- "BAN",
- "DETACH",
- "WATCH",
- "SILCOPER",
- "LEAVE",
- "USERS",
- "GETKEY",
- "SERVICE",
-};
-
-/* Returns command name */
-
-const char *silc_get_command_name(unsigned char command)
-{
- if (command >= SILC_COMMAND_RESERVED)
- return "RESERVED";
- if (command >= SILC_COMMAND_PRIVATE)
- return "PRIVATE RANGE";
- if (command > (sizeof(command_name) / sizeof(*command_name)))
- return "UNKNOWN";
- return command_name[command];
-}
-
-/* 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)
-{
- char *cp, buf[32];
- int maj = 0, min = 0;
-
- if (!strstr(version, "SILC-"))
- return FALSE;
-
- cp = (char *)version + 5;
- if (!cp)
- return FALSE;
-
- /* Take protocol version */
-
- maj = atoi(cp);
- if (!strchr(cp, '.'))
- return FALSE;
- cp = strchr(cp, '.') + 1;
- if (!cp || !(*cp))
- return FALSE;
- min = atoi(cp);
-
- memset(buf, 0, sizeof(buf));
- silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
- if (protocol_version)
- *protocol_version = atoi(buf);
- memset(buf, 0, sizeof(buf));
- silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
- if (protocol_version_string)
- *protocol_version_string = strdup(buf);
-
- /* Take software version */
-
- maj = 0;
- min = 0;
- if (!strchr(cp, '-'))
- return FALSE;
- cp = strchr(cp, '-') + 1;
- if (!cp || !(*cp))
- return FALSE;
-
- maj = atoi(cp);
- if (strchr(cp, '.')) {
- cp = strchr(cp, '.') + 1;
- if (cp && *cp)
- min = atoi(cp);
- }
-
- memset(buf, 0, sizeof(buf));
- silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
- if (software_version)
- *software_version = atoi(buf);
- memset(buf, 0, sizeof(buf));
- silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
- if (software_version_string)
- *software_version_string = strdup(buf);
-
- /* Take vendor string */
-
- if (strchr(cp, '.')) {
- cp = strchr(cp, '.') + 1;
- if (cp && *cp && vendor_version)
- *vendor_version = strdup(cp);
- }
-
- return TRUE;
-}
-
-/* Converts version string x.x into number representation. */
-
-SilcUInt32 silc_version_to_num(const char *version)
-{
- int maj = 0, min = 0;
- char *cp, buf[32];
-
- if (!version)
- return 0;
-
- cp = (char *)version;
- maj = atoi(cp);
- cp = strchr(cp, '.');
- if (cp)
- min = atoi(cp + 1);
-
- memset(buf, 0, sizeof(buf));
- silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
- return (SilcUInt32)atoi(buf);
-}
-
-/* Parses mode mask and returns the mode as string. */
-
-char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
-{
- char string[100];
-
- if (!mode)
- return NULL;
-
- memset(string, 0, sizeof(string));
-
- if (mode & SILC_CHANNEL_MODE_PRIVATE)
- strncat(string, "p", 1);
-
- if (mode & SILC_CHANNEL_MODE_SECRET)
- strncat(string, "s", 1);
-
- if (mode & SILC_CHANNEL_MODE_PRIVKEY)
- strncat(string, "k", 1);
-
- if (mode & SILC_CHANNEL_MODE_INVITE)
- strncat(string, "i", 1);
-
- if (mode & SILC_CHANNEL_MODE_TOPIC)
- strncat(string, "t", 1);
-
- if (mode & SILC_CHANNEL_MODE_ULIMIT)
- strncat(string, "l", 1);
-
- if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
- strncat(string, "a", 1);
-
- if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
- strncat(string, "f", 1);
-
- if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
- strncat(string, "C", 1);
-
- if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
- strncat(string, "m", 1);
-
- if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
- strncat(string, "M", 1);
-
- if (mode & SILC_CHANNEL_MODE_CIPHER)
- strncat(string, "c", 1);
-
- if (mode & SILC_CHANNEL_MODE_HMAC)
- strncat(string, "h", 1);
-
- if (mode & SILC_CHANNEL_MODE_CIPHER) {
- if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
- strncat(string, " ", 1);
- strncat(string, cipher, strlen(cipher));
- }
- }
-
- if (mode & SILC_CHANNEL_MODE_HMAC) {
- if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
- strncat(string, " ", 1);
- strncat(string, hmac, strlen(hmac));
- }
- }
-
- /* Rest of mode is ignored */
-
- return strdup(string);
-}
-
-/* Parses channel user mode mask and returns te mode as string */
-
-char *silc_client_chumode(SilcUInt32 mode)
-{
- char string[64];
-
- if (!mode)
- return NULL;
-
- memset(string, 0, sizeof(string));
-
- if (mode & SILC_CHANNEL_UMODE_CHANFO)
- strncat(string, "f", 1);
-
- if (mode & SILC_CHANNEL_UMODE_CHANOP)
- strncat(string, "o", 1);
-
- if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
- strncat(string, "b", 1);
-
- if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
- strncat(string, "u", 1);
-
- if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
- strncat(string, "r", 1);
-
- if (mode & SILC_CHANNEL_UMODE_QUIET)
- strncat(string, "q", 1);
-
- return strdup(string);
-}
-
-/* Parses channel user mode and returns it as special mode character. */
-
-char *silc_client_chumode_char(SilcUInt32 mode)
-{
- char string[64];
-
- if (!mode)
- return NULL;
-
- memset(string, 0, sizeof(string));
-
- if (mode & SILC_CHANNEL_UMODE_CHANFO)
- strncat(string, "*", 1);
-
- if (mode & SILC_CHANNEL_UMODE_CHANOP)
- strncat(string, "@", 1);
-
- if (mode & SILC_CHANNEL_UMODE_QUIET)
- strncat(string, "&", 1);
-
- return strdup(string);
-}
-
-/* Renders ID to suitable to print for example to log file. */
-
-static char rid[256];
-#define _PUT_STRING(__d__, __s__) \
-do { \
- int __sp = sizeof(__d__) - 1 - strlen(__d__); \
- if (__sp < strlen(__s__)) { \
- if (__sp) \
- strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \
- } else { \
- strncat(__d__, __s__, strlen(__s__)); \
- } \
-} while(0)
-
-char *silc_id_render(void *id, SilcIdType id_type)
-{
- char tmp[100];
- unsigned char tmps[2];
- char *cp;
-
- memset(rid, 0, sizeof(rid));
- switch(id_type) {
- case SILC_ID_SERVER:
- {
- SilcServerID *server_id = (SilcServerID *)id;
- if (server_id->ip.data_len > 4) {
-#ifdef HAVE_IPV6
- struct sockaddr_in6 ipv6;
- memset(&ipv6, 0, sizeof(ipv6));
- ipv6.sin6_family = AF_INET6;
- memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
- if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
- tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
- _PUT_STRING(rid, tmp);
-#endif
- } else {
- struct in_addr ipv4;
- memmove(&ipv4.s_addr, server_id->ip.data, 4);
- cp = inet_ntoa(ipv4);
- if (cp)
- _PUT_STRING(rid, cp);
- }
-
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
- _PUT_STRING(rid, tmp);
- SILC_PUT16_MSB(server_id->rnd, tmps);
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
- _PUT_STRING(rid, tmp);
- }
- break;
- case SILC_ID_CLIENT:
- {
- SilcClientID *client_id = (SilcClientID *)id;
- if (client_id->ip.data_len > 4) {
-#ifdef HAVE_IPV6
- struct sockaddr_in6 ipv6;
- memset(&ipv6, 0, sizeof(ipv6));
- ipv6.sin6_family = AF_INET6;
- memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
- if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
- tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
- _PUT_STRING(rid, tmp);
-#endif
- } else {
- struct in_addr ipv4;
- memmove(&ipv4.s_addr, client_id->ip.data, 4);
- cp = inet_ntoa(ipv4);
- if (cp)
- _PUT_STRING(rid, cp);
- }
-
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
- _PUT_STRING(rid, tmp);
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
- client_id->hash[0], client_id->hash[1],
- client_id->hash[2], client_id->hash[3]);
- _PUT_STRING(rid, tmp);
- }
- break;
- case SILC_ID_CHANNEL:
- {
- SilcChannelID *channel_id = (SilcChannelID *)id;
- if (channel_id->ip.data_len > 4) {
-#ifdef HAVE_IPV6
- struct sockaddr_in6 ipv6;
- memset(&ipv6, 0, sizeof(ipv6));
- ipv6.sin6_family = AF_INET6;
- memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
- if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
- tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
- _PUT_STRING(rid, tmp);
-#endif
- } else {
- struct in_addr ipv4;
- memmove(&ipv4.s_addr, channel_id->ip.data, 4);
- cp = inet_ntoa(ipv4);
- if (cp)
- _PUT_STRING(rid, cp);
- }
-
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
- _PUT_STRING(rid, tmp);
- SILC_PUT16_MSB(channel_id->rnd, tmps);
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
- _PUT_STRING(rid, tmp);
- }
- break;
- }
-
- return rid;
-}
-#undef _PUT_STRING
+++ /dev/null
-/*
-
- silcapputil.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2002 - 2007 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* silcapputil/SILC Application Utilities
- *
- * DESCRIPTION
- *
- * This interface provides utility functions for applications'
- * convenience. It provides functions that may be used for example by
- * command line applications but also other applications may find some
- * routines helpful. None of these routines are mandatory in any other
- * SILC routines or libraries, and are purely provided for convenience.
- * These routines for example provide simple public key and private key
- * pair generation, public key and private key file saving and loading
- * for application, and other similar routines.
- *
- ***/
-
-#ifndef SILCAPPUTIL_H
-#define SILCAPPUTIL_H
-
-/****f* silcapputil/SilcAppUtil/silc_create_key_pair
- *
- * SYNOPSIS
- *
- * SilcBool silc_create_key_pair(const char *pkcs_name,
- * SilcUInt32 key_len_bits,
- * const char *pub_filename,
- * const char *prv_filename,
- * const char *pub_identifier,
- * const char *passphrase,
- * SilcPublicKey *return_public_key,
- * SilcPrivateKey *return_private_key,
- * SilcBool interactive);
- *
- * DESCRIPTION
- *
- * This routine can be used to generate new public key and private key
- * pair. The `pkcs_name' is the name of public key algorithm, or if
- * NULL it defaults to "rsa". The `key_len_bits' is the key length
- * in bits and if zero (0) it defaults to 2048 bits. The `pub_filename'
- * and `prv_filename' is the public key and private key filenames.
- * The `pub_identifier' is the public key identifier (for example:
- * "UN=foobar, HN=hostname"), or if NULL the routine generates it
- * automatically. The `return_public_key' and `return_private_key' may
- * be NULL.
- *
- * The `passphrase' is the passphrase that is used to encrypt the
- * private key file. It is recommended that you would protect your
- * private key file with a passphrase.
- *
- * If the `interactive' is TRUE then this asks the user (by blocking
- * the process for input) some questions about key generation (like
- * public key algorithm, key length, filenames, etc). If all
- * arguments are provided to this function already then `interactive'
- * has no effect.
- *
- * NOTES
- *
- * Before calling this function the application must have initialized
- * the crypto library by registering the public key algorithms with
- * silc_pkcs_register_default function.
- *
- ***/
-SilcBool silc_create_key_pair(const char *pkcs_name,
- SilcUInt32 key_len_bits,
- const char *pub_filename,
- const char *prv_filename,
- const char *pub_identifier,
- const char *passphrase,
- SilcPublicKey *return_public_key,
- SilcPrivateKey *return_private_key,
- SilcBool interactive);
-
-/****f* silcapputil/SilcAppUtil/silc_load_key_pair
- *
- * SYNOPSIS
- *
- * SilcBool silc_load_key_pair(const char *pub_filename,
- * const char *prv_filename,
- * const char *passphrase,
- * SilcPublicKey *return_public_key,
- * SilcPrivateKey *return_private_key);
- *
- * DESCRIPTION
- *
- * This routine can be used to load the public key and private key
- * from files. This retuns FALSE it either of the key could not be
- * loaded. This function returns TRUE on success and returns the
- * public key into `return_public_key' pointer and private key into
- * `return_private_key'. The `passphrase' is the passphrase which
- * will be used to decrypt the private key file.
- *
- ***/
-SilcBool silc_load_key_pair(const char *pub_filename,
- const char *prv_filename,
- const char *passphrase,
- SilcPublicKey *return_public_key,
- SilcPrivateKey *return_private_key);
-
-/****f* silcapputil/SilcAppUtil/silc_show_public_key
- *
- * SYNOPSIS
- *
- * SilcBool silc_show_public_key(SilcPublicKey public_key);
- *
- * DESCRIPTION
- *
- * This routine can be used to dump the SILC public key into human
- * readable form into stdout. Returns FALSE on error.
- *
- ***/
-SilcBool silc_show_public_key(SilcPublicKey public_key);
-
-/****f* silcapputil/SilcAppUtil/silc_show_public_key_file
- *
- * SYNOPSIS
- *
- * SilcBool silc_show_public_key_file(const char *pub_filename);
- *
- * DESCRIPTION
- *
- * This routine can be used to dump the contents of the public key
- * in the public key file `pub_filename'. This dumps the public key
- * into human readable form into stdout. Returns FALSE on error.
- *
- ***/
-SilcBool silc_show_public_key_file(const char *pub_filename);
-
-/****f* silcapputil/SilcAppUtil/silc_change_private_key_passphrase
- *
- * SYNOPSIS
- *
- * SilcBool silc_change_private_key_passphrase(const char *prv_filename,
- * const char *old_passphrase,
- * const char *new_passphrase);
- *
- * DESCRIPTION
- *
- * This routine can be used to change the passphrase of the private
- * key file, which is used to encrypt the private key. If the old
- * and new passphrase is not provided for this function this will
- * prompt for them.
- *
- ***/
-SilcBool silc_change_private_key_passphrase(const char *prv_filename,
- const char *old_passphrase,
- const char *new_passphrase);
-
-
-/****f* silcapputil/SilcAppUtil/silc_identifier_check
- *
- * SYNOPSIS
- *
- * unsigned char *
- * silc_identifier_check(const unsigned char *identifier,
- * SilcUInt32 identifier_len,
- * SilcStringEncoding identifier_encoding,
- * SilcUInt32 max_allowed_length,
- * SilcUInt32 *out_len);
- *
- * DESCRIPTION
- *
- * 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
- * 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
- * one anyway.
- *
- * Returns the validated string, that the caller must free. Returns
- * NULL if the identifier string is not valid or contain unassigned or
- * prohibited characters. Such identifier strings must not be used
- * SILC protocol. The returned string is always in UTF-8 encoding.
- * The length of the returned string is in 'out_len'.
- *
- * NOTES
- *
- * In addition of validating the identifier string, this function
- * may map characters to other characters or remove characters from the
- * original string. This is done as defined in the SILC protocol. Error
- * is returned only if the string contains unassigned or prohibited
- * characters. The original 'identifier' is not modified at any point.
- *
- ***/
-unsigned char *silc_identifier_check(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length,
- SilcUInt32 *out_len);
-
-/****f* silcapputil/SilcAppUtil/silc_identifier_verify
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_identifier_check(const unsigned char *identifier,
- * SilcUInt32 identifier_len,
- * SilcStringEncoding identifier_encoding,
- * SilcUInt32 max_allowed_length);
- *
- * DESCRIPTION
- *
- * 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
- * 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
- * one anyway.
- *
- * Returns TRUE if the string is valid and FALSE if it is prohibited.
- *
- ***/
-SilcBool silc_identifier_verify(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length);
-
-/****f* silcapputil/SilcAppUtil/silc_channel_name_check
- *
- * SYNOPSIS
- *
- * unsigned char *
- * silc_channel_name_check(const unsigned char *identifier,
- * SilcUInt32 identifier_len,
- * SilcStringEncoding identifier_encoding,
- * SilcUInt32 max_allowed_length,
- * SilcUInt32 *out_len);
- *
- * DESCRIPTION
- *
- * Checks that the 'identifier' string is valid channel name string
- * and does not contain any unassigned or prohibited character.
- *
- * 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 channel names the max length must be 256
- * bytes.
- *
- * Returns the validated string, that the caller must free. Returns
- * NULL if the identifier string is not valid or contain unassigned or
- * prohibited characters. Such identifier strings must not be used
- * SILC protocol. The returned string is always in UTF-8 encoding.
- * The length of the returned string is in 'out_len'.
- *
- * NOTES
- *
- * In addition of validating the channel name string, this function
- * may map characters to other characters or remove characters from the
- * original string. This is done as defined in the SILC protocol. Error
- * is returned only if the string contains unassigned or prohibited
- * characters. The original 'identifier' is not modified at any point.
- *
- ***/
-unsigned char *silc_channel_name_check(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length,
- SilcUInt32 *out_len);
-
-/****f* silcapputil/SilcAppUtil/silc_channel_name_verify
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_channel_name_veirfy(const unsigned char *identifier,
- * SilcUInt32 identifier_len,
- * SilcStringEncoding identifier_encoding,
- * SilcUInt32 max_allowed_length);
- *
- * DESCRIPTION
- *
- * Checks that the 'identifier' string is valid channel name string
- * and does not contain any unassigned or prohibited character.
- *
- * 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 channel names the max length must be 256
- * bytes.
- *
- * Returns TRUE if the string is valid and FALSE if it is prohibited.
- *
- ***/
-SilcBool silc_channel_name_verify(const unsigned char *identifier,
- SilcUInt32 identifier_len,
- SilcStringEncoding identifier_encoding,
- SilcUInt32 max_allowed_length);
-
-/****f* silcapputil/SilcAppUtil/silc_get_mode_list
- *
- * SYNOPSIS
- *
- * SilcBool silc_get_mode_list(SilcBuffer mode_list,
- * SilcUInt32 mode_list_count,
- * SilcUInt32 **list);
- *
- * DESCRIPTION
- *
- * Returns modes from list of 32 bit MSB first order values that are
- * encoded one after the other in the `mode_list' into the `list'
- * array. The caller must free the returned list. Return FALSE if
- * there is error parsing the list.
- *
- ***/
-SilcBool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
- SilcUInt32 **list);
-
-/****f* silcapputil/SilcAppUtil/silc_get_status_message
- *
- * SYNOPSIS
- *
- * char *silc_get_status_message(SilcStatus status)
- *
- * DESCRIPTION
- *
- * Returns status message string
- *
- ***/
-const char *silc_get_status_message(unsigned char status);
-
-/****f* silcapputil/SilcAppUtil/silc_get_packet_name
- *
- * SYNOPSIS
- *
- * char *silc_get_packet_name(SilcPacketType type);
- *
- * DESCRIPTION
- *
- * Returns the name corresponding packet type `type'.
- *
- ***/
-const char *silc_get_packet_name(unsigned char type);
-
-/****f* silcapputil/SilcAppUtil/silc_get_command_name
- *
- * SYNOPSIS
- *
- * char *silc_get_command_name(SilcCommand command);
- *
- * DESCRIPTION
- *
- * Returns the name corresponding SILC command `command'.
- *
- ***/
-const char *silc_get_command_name(unsigned char command);
-
-/****f* silcapputil/SilcAppUtil/silc_parse_version_string
- *
- * SYNOPSIS
- *
- * 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);
- *
- * DESCRIPTION
- *
- * 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);
-
-/****f* silcapputil/SilcAppUtil/silc_version_to_num
- *
- * SYNOPSIS
- *
- * SilcUInt32 silc_version_to_num(const char *version);
- *
- * DESCRIPTION
- *
- * Converts version string x.x into number representation.
- *
- ***/
-SilcUInt32 silc_version_to_num(const char *version);
-
-/****f* silcapputil/SilcAppUtil/silc_client_chmode
- *
- * SYNOPSIS
- *
- * char *silc_client_chmode(SilcUInt32 mode, const char *cipher,
- * const char *hmac);
- *
- * DESCRIPTION
- *
- * Parses mode mask and returns the mode as string.
- *
- ***/
-char *silc_client_chmode(SilcUInt32 mode, const char *cipher,
- const char *hmac);
-
-/****f* silcapputil/SilcAppUtil/silc_client_chumode
- *
- * SYNOPSIS
- *
- * char *silc_client_chumode(SilcUInt32 mode);
- *
- * DESCRIPTION
- *
- * Parses channel user mode mask and returns te mode as string.
- *
- ***/
-char *silc_client_chumode(SilcUInt32 mode);
-
-/****f* silcapputil/SilcAppUtil/silc_client_chumode_char
- *
- * SYNOPSIS
- *
- * char *silc_client_chumode_char(SilcUInt32 mode);
- *
- * DESCRIPTION
- *
- * Parses channel user mode and returns it as special mode character.
- *
- ***/
-char *silc_client_chumode_char(SilcUInt32 mode);
-
-/****f* silcutil/SilcUtilAPI/silc_id_render
- *
- * SYNOPSIS
- *
- * char *silc_id_render(void *id, SilcIdType id_type);
- *
- * DESCRIPTION
- *
- * Renders ID to suitable to print for example to log file.
- *
- ***/
-char *silc_id_render(void *id, SilcIdType id_type);
-
-#endif /* SILCAPPUTIL_H */
+++ /dev/null
-/*
-
- silcidcache.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2000 - 2007 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 "silcidcache.h"
-
-/************************** Types and definitions ***************************/
-
-/* 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 */
-};
-
-
-/************************ Static utility functions **************************/
-
-/* Callback that is called by the hash table routine when traversing
- entries in the hash table. */
-
-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);
-}
-
-/* Cache entry destructor */
-
-static void silc_idcache_destructor(SilcIDCache cache,
- SilcIDCacheEntry entry,
- void *app_context)
-{
- if (cache->destructor)
- cache->destructor(cache, entry, cache->destructor, app_context);
-
- memset(entry, 'F', sizeof(*entry));
- silc_free(entry);
-}
-
-
-/****************************** Public API **********************************/
-
-/* Allocates new ID cache object. */
-
-SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
- SilcIDCacheDestructor destructor,
- void *destructor_context)
-{
- SilcIDCache cache;
-
- SILC_LOG_DEBUG(("Allocating new cache"));
-
- 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),
- NULL, NULL, TRUE);
- cache->name_table = silc_hash_table_alloc(count, silc_hash_utf8_string, NULL,
- silc_hash_utf8_compare, NULL,
- NULL, NULL, TRUE);
- cache->context_table = silc_hash_table_alloc(count, silc_hash_ptr, NULL,
- NULL, NULL, NULL, NULL, TRUE);
- cache->destructor = destructor;
- cache->context = destructor_context;
- cache->id_type = id_type;
-
- if (!cache->id_table || !cache->name_table || !cache->context_table) {
- if (cache->id_table)
- silc_hash_table_free(cache->id_table);
- if (cache->name_table)
- silc_hash_table_free(cache->name_table);
- if (cache->context_table)
- silc_hash_table_free(cache->context_table);
- silc_free(cache);
- return NULL;
- }
-
- return cache;
-}
-
-/* Frees ID cache object and cache entries */
-
-void silc_idcache_free(SilcIDCache 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 cache */
-
-SilcIDCacheEntry
-silc_idcache_add(SilcIDCache cache, char *name, void *id, void *context)
-{
- SilcIDCacheEntry c;
-
- if (!cache || !id)
- return NULL;
-
- /* Allocate new cache entry */
- c = silc_calloc(1, sizeof(*c));
- if (!c)
- return NULL;
-
- c->id = id;
- c->name = name;
- c->context = context;
-
- SILC_LOG_DEBUG(("Adding cache entry %p", c));
-
- /* Add the new entry to the hash tables */
- if (silc_idcache_find_by_id_one(cache, id, NULL)) {
- SILC_LOG_ERROR(("Attempted to add same ID twice to ID Cache, id %s",
- silc_id_render(id, cache->id_type)));
- SILC_ASSERT(FALSE);
- goto err;
- }
- if (!silc_hash_table_add(cache->id_table, id, c))
- goto err;
- if (name)
- if (!silc_hash_table_add(cache->name_table, name, c))
- goto err;
- if (context)
- if (!silc_hash_table_add(cache->context_table, context, c))
- goto err;
-
- return c;
-
- 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);
-
- return NULL;
-}
-
-/* Delete cache entry from cache. */
-
-SilcBool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry entry,
- void *app_context)
-{
- SilcBool ret = FALSE;
-
- if (!cache)
- return FALSE;
-
- SILC_LOG_DEBUG(("Deleting cache entry %p", entry));
-
- 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 (ret)
- silc_idcache_destructor(cache, entry, app_context);
-
- return ret;
-}
-
-/* Deletes ID cache entry by ID. */
-
-SilcBool silc_idcache_del_by_id(SilcIDCache cache, void *id,
- void *app_context)
-{
- SilcIDCacheEntry c;
-
- if (!cache)
- return FALSE;
-
- if (!silc_hash_table_find(cache->id_table, id, NULL, (void *)&c))
- return FALSE;
-
- return silc_idcache_del(cache, c, app_context);
-}
-
-/* Deletes ID cache entry by context. */
-
-SilcBool silc_idcache_del_by_context(SilcIDCache cache, void *context,
- void *app_context)
-{
- SilcIDCacheEntry c;
-
- if (!cache)
- return FALSE;
-
- if (!silc_hash_table_find(cache->context_table, context, NULL, (void *)&c))
- return FALSE;
-
- return silc_idcache_del(cache, c, app_context);
-}
-
-/* Update entry */
-
-SilcBool silc_idcache_update(SilcIDCache cache, SilcIDCacheEntry entry,
- void *new_id, char *new_name,
- SilcBool free_old_name)
-{
- if (!cache)
- return FALSE;
-
- if (new_id) {
- if (!silc_hash_table_del_by_context(cache->id_table, entry->id, entry))
- return FALSE;
-
- if (cache->id_type == SILC_ID_CLIENT)
- *(SilcClientID *)entry->id = *(SilcClientID *)new_id;
- if (cache->id_type == SILC_ID_SERVER)
- *(SilcServerID *)entry->id = *(SilcServerID *)new_id;
- if (cache->id_type == SILC_ID_CHANNEL)
- *(SilcChannelID *)entry->id = *(SilcChannelID *)new_id;
-
- if (!silc_hash_table_add(cache->id_table, entry->id, entry))
- return FALSE;
- }
-
- if (new_name) {
- if (entry->name)
- if (!silc_hash_table_del_by_context(cache->name_table, entry->name,
- entry))
- return FALSE;
-
- if (free_old_name)
- silc_free(entry->name);
- entry->name = new_name;
-
- if (!silc_hash_table_add(cache->name_table, entry->name, entry))
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Update entry by context */
-
-SilcBool silc_idcache_update_by_context(SilcIDCache cache, void *context,
- void *new_id, char *new_name,
- SilcBool free_old_name)
-{
- SilcIDCacheEntry c;
-
- if (!cache)
- return FALSE;
-
- if (!silc_hash_table_find(cache->context_table, context, NULL, (void *)&c))
- return FALSE;
-
- return silc_idcache_update(cache, c, new_id, new_name, free_old_name);
-}
-
-/* Returns all cache entrys from the ID cache to the `ret' ID Cache List. */
-
-SilcBool silc_idcache_get_all(SilcIDCache cache, SilcList *ret_list)
-{
- if (!cache || !ret_list)
- return FALSE;
-
- if (!silc_hash_table_count(cache->id_table))
- return FALSE;
-
- silc_list_init(*ret_list, struct SilcIDCacheEntryStruct, next);
- 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. */
-
-SilcBool silc_idcache_find_by_id(SilcIDCache cache, void *id,
- SilcList *ret_list)
-{
- if (!cache || !ret_list)
- return FALSE;
-
- if (!silc_hash_table_count(cache->id_table))
- return FALSE;
-
- silc_list_init(*ret_list, struct SilcIDCacheEntryStruct, next);
- silc_hash_table_find_foreach(cache->id_table, id,
- silc_idcache_get_all_foreach, ret_list);
-
- if (!silc_list_count(*ret_list))
- return FALSE;
-
- return TRUE;
-}
-
-/* Find one specific ID entry. Compare full IDs */
-
-SilcBool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
- SilcIDCacheEntry *ret)
-{
- if (!cache)
- return FALSE;
- return silc_hash_table_find_ext(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. */
-
-SilcBool silc_idcache_find_by_context(SilcIDCache cache, void *context,
- SilcIDCacheEntry *ret)
-{
- if (!cache)
- return FALSE;
- return silc_hash_table_find(cache->context_table, context, NULL,
- (void *)ret);
-}
-
-/* Find ID Cache entry by name. Returns list of cache entries. */
-
-SilcBool silc_idcache_find_by_name(SilcIDCache cache, char *name,
- SilcList *ret_list)
-{
- if (!cache || !ret_list)
- return FALSE;
-
- if (!silc_hash_table_count(cache->name_table))
- return FALSE;
-
- silc_list_init(*ret_list, struct SilcIDCacheEntryStruct, next);
- silc_hash_table_find_foreach(cache->name_table, name,
- silc_idcache_get_all_foreach, ret_list);
-
- if (!silc_list_count(*ret_list))
- return FALSE;
-
- return TRUE;
-}
-
-/* Find ID Cache entry by name. Returns one cache entry. */
-
-SilcBool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
- SilcIDCacheEntry *ret)
-{
- if (!cache)
- return FALSE;
- return silc_hash_table_find(cache->name_table, name, NULL, (void *)ret);
-}
+++ /dev/null
-/*
-
- silcidcache.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2000 - 2007 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* silcapputil/SILC ID Cache Interface
- *
- * DESCRIPTION
- *
- * SILC ID Cache is an cache for all kinds of ID's used in the SILC
- * protocol. Application can save here the ID's it uses and the interface
- * provides fast retrieval of the ID's from the cache.
- *
- * SILC ID Cache is not thread-safe. If the same cache context must be
- * used in multithreaded environment concurrency control must be employed.
- *
- ***/
-
-#ifndef SILCIDCACHE_H
-#define SILCIDCACHE_H
-
-/****s* silcapputil/SilcIDCacheAPI/SilcIDCacheEntry
- *
- * NAME
- *
- * typedef struct SilcIDCacheEntryStruct { ... } SilcIDCacheEntry;
- *
- * DESCRIPTION
- *
- * 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 SilcIDCacheEntryStruct {
- struct SilcIDCacheEntryStruct *next;
- void *id; /* Associated ID */
- char *name; /* Associated entry name */
- void *context; /* Associated context */
-} *SilcIDCacheEntry;
-/***/
-
-/****s* silcapputil/SilcIDCacheAPI/SilcIDCache
- *
- * NAME
- *
- * typedef struct SilcIDCacheStruct *SilcIDCache;
- *
- * DESCRIPTION
- *
- * This context is the actual ID Cache and is allocated by
- * silc_idcache_alloc and given as argument usually to all
- * silc_idcache_* functions. It is freed by the
- * silc_idcache_free function.
- *
- ***/
-typedef struct SilcIDCacheStruct *SilcIDCache;
-
-/****f* silcapputil/SilcIDCacheAPI/SilcIDCacheDestructor
- *
- * SYNOPSIS
- *
- * typedef void (*SilcIDCacheDestructor)(SilcIDCache cache,
- * const SilcIDCacheEntry entry,
- * void *destructor_context,
- * void *app_context);
- *
- * DESCRIPTION
- *
- * 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,
- const SilcIDCacheEntry entry,
- void *destructor_context,
- void *app_context);
-
-/* Prototypes */
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_alloc
- *
- * SYNOPSIS
- *
- * SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
- * SilcIDCacheDestructor destructor,
- * void *destructor_context,
- * SilcBool delete_id, SilcBool delete_name);
- *
- * DESCRIPTION
- *
- * 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.
- *
- ***/
-SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
- SilcIDCacheDestructor destructor,
- void *destructor_context);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_free
- *
- * SYNOPSIS
- *
- * void silc_idcache_free(SilcIDCache cache);
- *
- * DESCRIPTION
- *
- * Frees ID cache context and all cache entries.
- *
- ***/
-void silc_idcache_free(SilcIDCache cache);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_add
- *
- * SYNOPSIS
- *
- * SilcIDCacheEntry
- * silc_idcache_add(SilcIDCache cache, char *name, void *id, void *context);
- *
- * DESCRIPTION
- *
- * 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 caller is responsible of
- * freeing the `name' and `id' when the entry is deleted.
- *
- ***/
-SilcIDCacheEntry
-silc_idcache_add(SilcIDCache cache, char *name, void *id, void *context);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_del
- *
- * SYNOPSIS
- *
- * 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 will be called for the entry. The `app_context' is
- * delivered to the destructor.
- *
- ***/
-SilcBool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry entry,
- void *app_context);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_del_by_id
- *
- * SYNOPSIS
- *
- * SilcBool silc_idcache_del_by_id(SilcIDCache cache, void *id,
- * void *app_context);
- *
- * DESCRIPTION
- *
- * 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.
- *
- ***/
-SilcBool silc_idcache_del_by_id(SilcIDCache cache, void *id,
- void *app_context);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_del_by_context
- *
- * SYNOPSIS
- *
- * SilcBool 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 will be called for the
- * entry. The `app_context' is delivered to the destructor.
- *
- ***/
-SilcBool silc_idcache_del_by_context(SilcIDCache cache, void *context,
- void *app_context);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_update
- *
- * SYNOPSIS
- *
- * SilcBool silc_idcache_update(SilcIDCache cache, SilcIDCacheEntry entry,
- * void *new_id, char *new_name,
- * SilcBool free_old_name);
- *
- * DESCRIPTION
- *
- * Updates cache `entry' with new values. If the `new_id' is non-NULL
- * then the new value will be copied over the old value in the `entry'.
- * If the `new_name' is non-NULL then the `entry' will be updated with
- * `new_name'. The caller is responsible of freeing the old name if it
- * was updated with new one. The old ID value does not need to be freed
- * as the new value is copied over the old value. If the `free_old_name'
- * is TRUE the library will free the old name from the entry.
- *
- ***/
-SilcBool silc_idcache_update(SilcIDCache cache, SilcIDCacheEntry entry,
- void *new_id, char *new_name,
- SilcBool free_old_name);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_update_by_context
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_idcache_update_by_context(SilcIDCache cache, void *context,
- * void *new_id, char *new_name,
- * SilcBool free_old_name);
- *
- * DESCRIPTION
- *
- * Same as silc_idcache_update but finds the corrent ID cache entry by
- * the `context' added to the ID cache.
- *
- ***/
-SilcBool silc_idcache_update_by_context(SilcIDCache cache, void *context,
- void *new_id, char *new_name,
- SilcBool free_old_name);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_get_all
- *
- * SYNOPSIS
- *
- * SilcBool silc_idcache_get_all(SilcIDCache cache, SilcList *ret_list);
- *
- * DESCRIPTION
- *
- * Returns all cache entries into the SilcList `ret_list' pointer. Each
- * entry in the list is SilcIDCacheEntry. Returns FALSE if the cache
- * is empty.
- *
- ***/
-SilcBool silc_idcache_get_all(SilcIDCache cache, SilcList *ret_list);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_find_by_id
- *
- * SYNOPSIS
- *
- * SilcBool silc_idcache_find_by_id(SilcIDCache cache, void *id,
- * SilcList *ret_list);
- *
- * DESCRIPTION
- *
- * 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.
- *
- * NOTES
- *
- * 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).
- *
- * 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.
- *
- ***/
-SilcBool silc_idcache_find_by_id(SilcIDCache cache, void *id,
- SilcList *ret_list);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_find_by_id_one
- *
- * SYNOPSIS
- *
- * SilcBool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
- * SilcIDCacheEntry *ret);
- *
- * DESCRIPTION
- *
- * 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.
- *
- ***/
-SilcBool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
- SilcIDCacheEntry *ret);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_find_by_context
- *
- * SYNOPSIS
- *
- * SilcBool silc_idcache_find_by_context(SilcIDCache cache, void *context,
- * SilcIDCacheEntry *ret);
- *
- * DESCRIPTION
- *
- * Find cache entry by user specified context. Returns TRUE if the
- * entry was found.
- *
- ***/
-SilcBool silc_idcache_find_by_context(SilcIDCache cache, void *context,
- SilcIDCacheEntry *ret);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_find_by_name
- *
- * SYNOPSIS
- *
- * 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 multiple entries to the `ret_list' SilcList context. Returns
- * TRUE if the entry was found.
- *
- ***/
-SilcBool silc_idcache_find_by_name(SilcIDCache cache, char *name,
- SilcList *ret_list);
-
-/****f* silcapputil/SilcIDCacheAPI/silc_idcache_find_by_name_one
- *
- * SYNOPSIS
- *
- * 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
- * one entry and the found entry is considered to be exact match.
- * Returns TRUE if the entry was found.
- *
- ***/
-SilcBool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
- SilcIDCacheEntry *ret);
-
-#endif /* SILCIDCACHE_H */
+++ /dev/null
-<!--
-@LIBRARY=SILC ASN.1 Library
-@FILENAME=silcasn1lib.html
-@LINK=silcasn1.html:SILC ASN.1 Interface
-@LINK=silcber.html:SILC BER interface
--->
-
-<big><b>SILC ASN.1 Library</b></big>
-<br />
-<small>Directory: lib/silcasn1/</small>
-<br />
-<small>Library: libsilc.a, libsilc.lib</small>
-<br /><br />
-<b>Introduction</b>
-
-<br /><br />
-SILC Abstract Syntax Notation One (ASN.1) Library provides interface for
-efficient ASN.1 encoder and decoder. The library also provides BER/DER
-encoder and decoder.
-
-<br /><br />
-@LINKS@
+++ /dev/null
-#
-# Makefile.ad
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# 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
-# 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 = libsilcasn1.la
-
-libsilcasn1_la_SOURCES = \
- silcber.c \
- silcasn1.c \
- silcasn1_decode.c \
- silcasn1_encode.c
-
-#ifdef SILC_DIST_TOOLKIT
-include_HEADERS = \
- silcber.h \
- silcasn1.h \
- silcasn1_i.h
-
-SILC_EXTRA_DIST = tests
-#endif SILC_DIST_TOOLKIT
-
-EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-/*
-
- silcasn1.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2007 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 "silcasn1.h"
-#include "silcber.h"
-
-/* Allocate ASN.1 context. */
-
-SilcAsn1 silc_asn1_alloc(void)
-{
- SilcAsn1 asn1 = silc_calloc(1, sizeof(*asn1));
- if (!asn1)
- return NULL;
-
- if (!silc_asn1_init(asn1))
- return NULL;
-
- return asn1;
-}
-
-/* Free ASN.1 context */
-
-void silc_asn1_free(SilcAsn1 asn1)
-{
- silc_asn1_uninit(asn1);
- silc_free(asn1);
-}
-
-/* Init pre-allocated ASN.1 context */
-
-SilcBool silc_asn1_init(SilcAsn1 asn1)
-{
- asn1->stack1 = silc_stack_alloc(768);
- if (!asn1->stack1)
- return FALSE;
-
- asn1->stack2 = silc_stack_alloc(768);
- if (!asn1->stack2) {
- silc_stack_free(asn1->stack2);
- return FALSE;
- }
-
- asn1->accumul = 0;
-
- return TRUE;
-}
-
-/* Uninit ASN.1 context */
-
-void silc_asn1_uninit(SilcAsn1 asn1)
-{
- silc_stack_free(asn1->stack1);
- silc_stack_free(asn1->stack2);
-}
-
-#if defined(SILC_DEBUG)
-/* Returns string representation of a tag */
-
-const char *silc_asn1_tag_name(SilcAsn1Tag tag)
-{
- switch (tag) {
- case SILC_ASN1_END:
- return "END";
- case SILC_ASN1_TAG_OPTS:
- return "";
- case SILC_ASN1_TAG_CHOICE:
- return "choice";
- case SILC_ASN1_TAG_ANY:
- return "any";
- case SILC_ASN1_TAG_ANY_PRIMITIVE:
- return "any primitive";
- case SILC_ASN1_TAG_SEQUENCE_OF:
- return "sequence of";
- case SILC_ASN1_TAG_SEQUENCE:
- return "sequence";
- case SILC_ASN1_TAG_SET:
- return "set";
- case SILC_ASN1_TAG_INTEGER:
- return "integer";
- case SILC_ASN1_TAG_SHORT_INTEGER:
- return "short integer";
- case SILC_ASN1_TAG_OID:
- return "oid";
- case SILC_ASN1_TAG_BOOLEAN:
- return "boolean";
- case SILC_ASN1_TAG_OCTET_STRING:
- return "octet-string";
- case SILC_ASN1_TAG_BIT_STRING:
- return "bit-string";
- case SILC_ASN1_TAG_NULL:
- return "null";
- case SILC_ASN1_TAG_ENUM:
- return "enum";
- case SILC_ASN1_TAG_UTC_TIME:
- return "utc-time";
- case SILC_ASN1_TAG_GENERALIZED_TIME:
- return "generalized-time";
- case SILC_ASN1_TAG_UTF8_STRING:
- return "utf8-string";
- case SILC_ASN1_TAG_NUMERIC_STRING:
- return "numeric-string";
- case SILC_ASN1_TAG_PRINTABLE_STRING:
- return "printable-string";
- case SILC_ASN1_TAG_IA5_STRING:
- return "ia5-string";
- case SILC_ASN1_TAG_VISIBLE_STRING:
- return "visible-string";
- case SILC_ASN1_TAG_UNIVERSAL_STRING:
- return "universal-string";
- case SILC_ASN1_TAG_UNRESTRICTED_STRING:
- return "unrestricted-string";
- case SILC_ASN1_TAG_BMP_STRING:
- return "bmp-string";
- case SILC_ASN1_TAG_ODE:
- return "ode";
- case SILC_ASN1_TAG_ETI:
- return "eti";
- case SILC_ASN1_TAG_REAL:
- return "real";
- case SILC_ASN1_TAG_EMBEDDED:
- return "embedded";
- case SILC_ASN1_TAG_ROI:
- return "roi";
- case SILC_ASN1_TAG_TELETEX_STRING:
- return "teletex-string";
- case SILC_ASN1_TAG_VIDEOTEX_STRING:
- return "videotex-string";
- case SILC_ASN1_TAG_GRAPHIC_STRING:
- return "graphic-string";
- case SILC_ASN1_TAG_GENERAL_STRING:
- return "general-string";
- default:
- break;
- }
- return "unknown";
-}
-#endif /* SILC_DEBUG */
-
-#ifdef SILC_DIST_TOOLKIT
-#ifdef SILC_DEBUG
-/* Dumps the ASN.1 data block into standard output (stdout). */
-
-SilcBool silc_asn1_dump(SilcAsn1 asn1, SilcBuffer src)
-{
- SilcBool ret = FALSE;
- SilcBerEncoding renc;
- SilcUInt32 rtag;
- const unsigned char *rdata;
- SilcUInt32 rdata_len, len = 0;
- SilcBool rindef;
-
- SILC_LOG_DEBUG(("Dumping ASN.1"));
-
- while (silc_buffer_len(src)) {
- /* Decode the BER block */
- ret = silc_ber_decode(src, NULL, &renc, &rtag, &rdata,
- &rdata_len, &rindef, &len);
- if (!ret) {
- SILC_LOG_DEBUG(("Error parsing BER block, malformed ASN.1 data"));
- return FALSE;
- }
-
- fprintf(stdout, "Type %s [%d]\n",
- silc_asn1_tag_name(rtag), rtag);
-
- if (renc == SILC_BER_ENC_PRIMITIVE)
- len = len + rdata_len;
- else
- len = len;
-
- if (len)
- silc_buffer_pull(src, len);
- }
-
- return TRUE;
-}
-#endif /* SILC_DEBUG */
-#endif /* SILC_DIST_TOOLKIT */
+++ /dev/null
-/*
-
- silcasn1.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2007 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* silcasn1/ASN.1 Interface
- *
- * DESCRIPTION
- *
- * Efficient Abstract Syntax Notation One (ASN.1) implementation. This
- * interface provides simple and efficient ASN.1 encoder and decoder.
- * The encoder directly encodes BER encoded data blocks from variable
- * argument list of ASN.1 types. Multiple trees can be encoded at once
- * and multiple nodes can be encoded into the tree at once. By default
- * encoder does not allocate any memory during encoding but a pre-allocated
- * SilcStack is used as memory.
- *
- * The decoder directly decodes BER encoded data blocks into the correct
- * types dictated by the variable argument list of ASN.1 types. By
- * default decoder does not allocate any memory during decoding but a
- * pre-allocated SilcStack is used as memory.
- *
- * The encoding and decoding interface is simple. silc_asn1_encode is used
- * to encode and silc_asn1_decode to decode. The actual ASN.1 is defined
- * as variable argument list to the function. Various macros can be used
- * to encode and decode different ASN.1 types. All types may also be used
- * to encode and decode with various options (such as implicit and explicit
- * tagging and defining specific class option).
- *
- * The implementation supports all the common ASN.1 types. This
- * implementation does not support advanced ASN.1 features like macros.
- *
- * References: ITU-T X.680 - X.693
- * http://www.itu.int/ITU-T/studygroups/com17/languages/
- *
- ***/
-
-#ifndef SILCASN1_H
-#define SILCASN1_H
-
-/****s* silcasn1/SilcASN1API/SilcAsn1
- *
- * NAME
- *
- * typedef struct SilcAsn1Object *SilcAsn1;
- *
- * DESCRIPTION
- *
- * This context is the actual ASN.1 encoder/decoder and is allocated
- * by silc_asn1_alloc and given as argument to all silc_asn1_*
- * functions. It is freed by the silc_asn1_free function. It is
- * also possible to use pre-allocated ASN.1 context by using the
- * SilcAsn1Struct instead of SilcAsn1.
- *
- ***/
-typedef struct SilcAsn1Object *SilcAsn1;
-
-/****s* silcasn1/SilcASN1API/SilcAsn1Struct
- *
- * NAME
- *
- * typedef struct SilcAsn1Object SilcAsn1Struct;
- *
- * DESCRIPTION
- *
- * This context is the actual ASN.1 encoder/decoder and can be
- * used as pre-allocated ASN.1 context instead of SilcAsn1 context.
- * This context is initialized with silc_asn1_init and uninitialized
- * with silc_asn1_uninit.
- *
- ***/
-typedef struct SilcAsn1Object SilcAsn1Struct;
-
-/****d* silcasn1/SilcASN1API/SilcAsn1Options
- *
- * NAME
- *
- * typedef enum { ... } SilcAsn1Options;
- *
- * DESCRIPTION
- *
- * Options for ASN.1 encoder and decoder. The ASN.1 options can be
- * given to the SILC_ASN1_*_T macros and/or SILC_ASN1_OPTS macro.
- *
- * NOTES
- *
- * The SILC_ASN1_ALLOC and SILC_ASN1_ACCUMUL flags can be given only
- * with SILC_ASN1_OPTS macro. Other options can be given with various
- * SILC_ASN1_*_T macros.
- *
- * EXAMPLE
- *
- * // Encodes boolean value with explicit tag and private class, and
- * // the result is allocated into `dest'.
- * silc_asn1_encode(asn1, &dest,
- * SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- * SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE |
- * SILC_ASN1_EXPLICIT, 100, boolval),
- * SILC_ASN1_END);
- *
- * SOURCE
- */
-typedef enum {
- /* Default. If only this is set then defaults are implied. */
- SILC_ASN1_DEFAULT = 0x0000,
-
- /* Class options. User does not need to set these unless specificly
- wanted to do so. If SILC_ASN1_DEFAULT is set the SILC_ASN1_CONTEXT is
- implied if any of the tag options are set. Otherwise SILC_ASN1_UNIVERSAL
- is implied. Only one of these can bet set at once. */
- SILC_ASN1_UNIVERSAL = 0x0001, /* Universal class (default) */
- SILC_ASN1_APP = 0x0002, /* Application specific class */
- SILC_ASN1_CONTEXT = 0x0003, /* Context specific class */
- SILC_ASN1_PRIVATE = 0x0004, /* Private class */
-
- /* Tag options (bitmask) */
- SILC_ASN1_IMPLICIT = 0x0010, /* Tag is implicit (default) */
- SILC_ASN1_EXPLICIT = 0x0020, /* Tag is explicit */
- SILC_ASN1_DEFINITE = 0x0040, /* Length is definite (default) */
- SILC_ASN1_INDEFINITE = 0x0080, /* Length is indefinite */
-
- /* Decoding options (bitmask) */
- SILC_ASN1_OPTIONAL = 0x0100, /* Zero or more may be found. The
- argument must be pointer to the
- type pointer so that NULL can be
- returned if type is not found. */
-
- /* ASN.1 encoder/decoder options (bitmask). These can be given
- only with SILC_ASN1_OPTS macro at the start of encoding/decoding. */
- SILC_ASN1_ALLOC = 0x0400, /* Dynamically allocate results */
- SILC_ASN1_ACCUMUL = 0x0800, /* Accumulate memory for results,
- next call to silc_asn1_decode
- will not cancel old results. */
-} SilcAsn1Options;
-/***/
-
-/****d* silcasn1/SilcASN1API/SilcAsn1Tag
- *
- * NAME
- *
- * typedef enum { ... } SilcAsn1Tag;
- *
- * DESCRIPTION
- *
- * Universal ASN.1 tags. Usually these tags are given automatically
- * to the silc_asn1_encode and silc_asn1_decode by using the various
- * macros (such as SILC_ASN1_BOOLEAN). Some macros may take the tag
- * as additional argument.
- *
- * SOURCE
- */
-typedef enum {
- SILC_ASN1_TAG_BOOLEAN = 1, /* SILC_ASN1_BOOLEAN */
- SILC_ASN1_TAG_INTEGER = 2, /* SILC_ASN1_INT */
- SILC_ASN1_TAG_BIT_STRING = 3, /* SILC_ASN1_BIT_STRING */
- SILC_ASN1_TAG_OCTET_STRING = 4, /* SILC_ASN1_OCTET_STRING */
- SILC_ASN1_TAG_NULL = 5, /* SILC_ASN1_NULL */
- SILC_ASN1_TAG_OID = 6, /* SILC_ASN1_OID */
- SILC_ASN1_TAG_ODE = 7, /* not supported */
- SILC_ASN1_TAG_ETI = 8, /* not supported */
- SILC_ASN1_TAG_REAL = 9, /* not supported */
- SILC_ASN1_TAG_ENUM = 10, /* SILC_ASN1_ENUM */
- SILC_ASN1_TAG_EMBEDDED = 11, /* not supported */
- SILC_ASN1_TAG_UTF8_STRING = 12, /* SILC_ASN1_UTF8_STRING */
- SILC_ASN1_TAG_ROI = 13, /* not supported */
- SILC_ASN1_TAG_SEQUENCE = 16, /* SILC_ASN1_SEQUENCE */
- SILC_ASN1_TAG_SET = 17, /* SILC_ASN1_SET */
- SILC_ASN1_TAG_NUMERIC_STRING = 18, /* SILC_ASN1_NUMERIC_STRING */
- SILC_ASN1_TAG_PRINTABLE_STRING = 19, /* SILC_ASN1_PRINTABLE_STRING */
- SILC_ASN1_TAG_TELETEX_STRING = 20, /* SILC_ASN1_TELETEX_STRING */
- SILC_ASN1_TAG_VIDEOTEX_STRING = 21, /* not supported */
- SILC_ASN1_TAG_IA5_STRING = 22, /* SILC_ASN1_IA5_STRING */
- SILC_ASN1_TAG_UTC_TIME = 23, /* SILC_ASN1_UTC_TIME */
- SILC_ASN1_TAG_GENERALIZED_TIME = 24, /* SILC_ASN1_GENERAL_STRING */
- SILC_ASN1_TAG_GRAPHIC_STRING = 25, /* not supported */
- SILC_ASN1_TAG_VISIBLE_STRING = 26, /* SILC_ASN1_VISIBLE_STRING */
- SILC_ASN1_TAG_GENERAL_STRING = 27, /* SILC_ASN1_GENERAL_STRING */
- SILC_ASN1_TAG_UNIVERSAL_STRING = 28, /* SILC_ASN1_UNIVERSAL_STRING */
- SILC_ASN1_TAG_UNRESTRICTED_STRING = 29, /* SILC_ASN1_UNRESTRICTED_STRING */
- SILC_ASN1_TAG_BMP_STRING = 30, /* SILC_ASN1_BMP_STRING */
-} SilcAsn1Tag;
-/***/
-
-#include "silcasn1_i.h"
-
-/****f* silcasn1/SilcASN1API/silc_asn1_alloc
- *
- * SYNOPSIS
- *
- * SilcAsn1 silc_asn1_alloc(void);
- *
- * DESCRIPTION
- *
- * Allocates and initializes ASN.1 encoder/decoder and returns SilcAsn1
- * context or NULL on error. This context can be used with both
- * silc_asn1_encode and silc_asn1_decode functions.
- *
- * Usually SilcAsn1 is allocated when encoder or decoder is needed,
- * however it is also possible to allocate long-lasting SilcAsn1 and
- * use that every time ASN.1 routines are needed. Application could
- * for example allocate one SilcAsn1 and use that for all ASN.1 encoding
- * and decoding.
- *
- * When this context is freed with silc_asn1_free all memory will be
- * freed, and all encoded ASN.1 buffers becomes invalid. Also all
- * data that is returned by silc_asn1_decode function becomes invalid.
- *
- ***/
-SilcAsn1 silc_asn1_alloc(void);
-
-/****f* silcasn1/SilcASN1API/silc_asn1_free
- *
- * SYNOPSIS
- *
- * void silc_asn1_free(SilcAsn1 asn1);
- *
- * DESCRIPTION
- *
- * Frees the SilcAsn1 context and all allocated memory. All encoded
- * buffers and all decoded buffers with this context becomes invalid
- * after this call.
- *
- ***/
-void silc_asn1_free(SilcAsn1 asn1);
-
-/****f* silcasn1/SilcASN1API/silc_asn1_init
- *
- * SYNOPSIS
- *
- * SilcBool silc_asn1_init(SilcAsn1 asn1);
- *
- * DESCRIPTION
- *
- * Initializes a pre-allocated SilcAsn1 context. This call is
- * equivalent to silc_asn1_alloc except that this takes the pre-allocated
- * context as argument.
- *
- * EXAMPLE
- *
- * SilcAsn1Struct asn1;
- * if (!silc_asn1_init(&asn1))
- * error;
- *
- ***/
-SilcBool silc_asn1_init(SilcAsn1 asn1);
-
-/****f* silcasn1/SilcASN1API/silc_asn1_uninit
- *
- * SYNOPSIS
- *
- * void silc_asn1_uninit(SilcAsn1 asn1);
- *
- * DESCRIPTION
- *
- * Uninitializes a pre-allocated SilcAsn1 context. Use this function
- * instead of silc_asn1_free if you used silc_asn1_init.
- *
- ***/
-void silc_asn1_uninit(SilcAsn1 asn1);
-
-/****f* silcasn1/SilcASN1API/silc_asn1_encode
- *
- * SYNOPSIS
- *
- * SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...);
- *
- * DESCRIPTION
- *
- * Encodes ASN.1 encoded buffer into `dest', from variable argument
- * list of ASN.1 types. The variable argument list forms the ASN.1
- * trees and nodes that are encoded into the `dest'. By default, the
- * memory for `dest' is allocated from the `asn1', and the buffer becomes
- * invalid either by calling silc_asn1_free, silc_asn1_uninit, or when
- * silc_asn1_encode is called for the next time.
- *
- * If the SILC_ASN1_OPTS macro with SILC_ASN1_ALLOC option is given then
- * the `dest' is dynamically allocated and caller must free it by itself.
- * Alternatively if SILC_ASN1_ACCUMUL is given then memory is accumulated
- * from `asn1' for `dest' and it is freed only when silc_asn1_free or
- * silc_asn1_uninit is called. Next call to silc_asn1_encode will not
- * cancel the previous result, but will accumulate more memory for new
- * result.
- *
- * The variable argument list is constructed by using various
- * macros, for example SILC_ASN1_SEQUENCE, etc. The variable argument
- * list must always be ended with SILC_ASN1_END type.
- *
- * If encoding is successful this returns TRUE, FALSE on error.
- *
- * EXAMPLE
- *
- * silc_asn1_encode(asn1, buf,
- * SILC_ASN1_SEQUENCE,
- * SILC_ASN1_BOOLEAN(bool_val),
- * SILC_ASN1_OCTET_STRING(string, string_len),
- * SILC_ASN1_SEQUENCE_T(0, 2),
- * SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 100, foo),
- * SILC_ASN1_END,
- * SILC_ASN1_OCTET_STRING_T(0, 1, string2, string2_len),
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- * Creates ASN.1 tree that looks something like:
- *
- * buf ::= SEQUENCE {
- * bool_val BOOLEAN,
- * string OCTET-STRING,
- * [2] SEQUENCE {
- * foo [100] EXPLICIT BOOLEAN }
- * string2 [1] OCTET-STRING }
- *
- ***/
-SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...);
-
-/****f* silcasn1/SilcASN1API/silc_asn1_decode
- *
- * SYNOPSIS
- *
- * SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
- *
- * DESCRIPTION
- *
- * Decodes the ASN.1 encoded buffer `src' by the ASN.1 types sent
- * as argument. The ASN.1 types sent as argument must be found from
- * the `src' for this function to decode successfully.
- *
- * The memory allocated for the results are allocated from `asn1' and
- * they become invalid if `asn1' becomes invalid. Next (second) call
- * to this function does NOT invalidate the previous results. However,
- * third call to this function does invalidate the results of the first
- * call but not second. On the other hand, fourth call invalidates
- * the results of the second call but not third, fifth call invalidates
- * the results of the third call but not fourth, and so on. This allows
- * efficient decoding, when silc_asn1_decode must be called multiple times
- * to decode all data, without new memory allocations. However, caller
- * must be cautios and understand that the every second call invalidates
- * the results of every second previous results.
- *
- * If the SILC_ASN1_OPTS macro with SILC_ASN1_ALLOC option is given then
- * all results are dynamically allocated and caller must free them by
- * itself. Alternatively if SILC_ASN1_ACCUMUL is given then memory is
- * accumulated from `asn1' for results and they are freed only when the
- * silc_asn1_free or silc_asn1_uninit is called. Next calls to the
- * silc_asn1_decode will NOT invalidate the old results, but will
- * accumulate more memory for new results. If the SILC_ASN1_OPTS is not
- * given at all then the default allocation method (decribed above)
- * applies.
- *
- * If caller needs to store the results even after `asn1' becomes invalid
- * then call must either use SILC_ASN1_ALLOC option or duplicate the
- * results by itself.
- *
- * EXAMPLE
- *
- * SilcBool bool_val, foo;
- * unsigned char *string, string2;
- * SilcUInt32 string_len, string2_len;
- *
- * silc_asn1_decode(asn1, tree,
- * SILC_ASN1_SEQUENCE,
- * SILC_ASN1_BOOLEAN(&bool_val),
- * SILC_ASN1_OCTET_STRING(&string, &string_len),
- * SILC_ASN1_SEQUENCE_T(0, 2),
- * SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 100, &foo),
- * SILC_ASN1_END,
- * SILC_ASN1_OCTET_STRING_T(0, 1, &str2, &str2_len),
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_OPTS
- *
- * SYNOPSIS
- *
- * SILC_ASN1_OPTS(opts)
- *
- * DESCRIPTION
- *
- * The `opts' is SilcAsn1Options. This macro can be used to set
- * options for silc_asn1_encode and silc_asn1_decode functions.
- *
- * NOTES
- *
- * Only the SILC_ASN1_ALLOC and SILC_ASN1_ACCUMUL flags may be
- * set with this macro.
- *
- * This macro must be the first macro in the variable argument list
- * in the function.
- *
- * EXAMPLE
- *
- * silc_asn1_decode(asn1, tree,
- * SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- * SILC_ASN1_SEQUENCE,
- * SILC_ASN1_BOOLEAN(&bool_val),
- * SILC_ASN1_OCTET_STRING(&string, &string_len),
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_OPTS(opts) SILC_ASN1_TAG_OPTS, (opts)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_ANY
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_ANY(buffer)
- * SILC_ASN1_ANY_T(opts, tag, buffer)
- *
- * Decoding:
- * SILC_ASN1_ANY(&buffer)
- * SILC_ASN1_ANY_T(opts, tag, buffer)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode another ASN.1 node. The buffer type
- * is SilcBuffer. This macro can be used for example to split large
- * tree into multiple nodes, and then decoding the nodes separately from
- * the buffers.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * EXAMPLE
- *
- * // Encode node of two boolean values
- * silc_asn1_encode(asn1, node,
- * SILC_ASN1_BOOLEAN(val1),
- * SILC_ASN1_BOOLEAN(val2),
- * SILC_ASN1_END);
- *
- * // Encode tree with the node
- * silc_asn1_encode(asn1, tree,
- * SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- * SILC_ASN1_ANY(node),
- * SILC_ASN1_BOOLEAN(boolval),
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_ANY(x) SILC_ASN1_U1(ANY, x)
-#define SILC_ASN1_ANY_T(o, t, x) SILC_ASN1_T1(ANY, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_ANY_PRIMITIVE
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_ANY_PRIMITIVE(tag, buffer)
- * SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer)
- *
- * Decoding:
- * SILC_ASN1_ANY_PRIMITIVE(tag, &buffer)
- * SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer)
- *
- * DESCRIPTION
- *
- * Special macro used to encode pre-encoded primitive data blob. The data
- * can be any primitive type that is already encoded in correct format.
- * The caller is responsible of making sure the data is formatted
- * correctly. When decoding this returns the raw data blob and the caller
- * must know of what type and format it is. The buffer type is SilcBuffer.
- *
- * This macro can be used in cases when the data to be encoded is already
- * in encoded format, and it only needs to be added to ASN.1 tree. The
- * SILC_ASN1_ANY cannot be used with primitives when tagging implicitly,
- * in these cases this macro can be used.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * EXAMPLE
- *
- * // Get MP integer in encoded format
- * mpbuf = mp_get_octet_string(mp);
- *
- * // Encode the MP integer data to the tree
- * silc_asn1_encode(asn1, tree,
- * SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_INTEGER, mpbuf),
- * SILC_ASN1_END);
- *
- * // Decode the MP integer data from the tree
- * silc_asn1_decode(asn1, tree,
- * SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_INTEGER, &buffer),
- * SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_ANY_PRIMITIVE(t, x) SILC_ASN1_T1(ANY_PRIMITIVE, 0, t, x)
-#define SILC_ASN1_ANY_PRIMITIVE_T(o, t, x) SILC_ASN1_T1(ANY_PRIMITIVE, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_SEQUENCE
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_SEQUENCE
- * SILC_ASN1_SEQUENCE_T(opts, tag)
- *
- * Decoding:
- * SILC_ASN1_SEQUENCE
- * SILC_ASN1_SEQUENCE_T(opts, tag)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode sequence. The sequence must be
- * terminated with SILC_ASN1_END.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * EXAMPLE
- *
- * silc_asn1_encode(asn1, tree,
- * SILC_ASN1_SEQUENCE,
- * SILC_ASN1_ANY(node),
- * SILC_ASN1_BOOLEAN(boolval),
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_SEQUENCE SILC_ASN1_U0(SEQUENCE)
-#define SILC_ASN1_SEQUENCE_T(o, t) SILC_ASN1_T0(SEQUENCE, o, t)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_SET
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_SET
- * SILC_ASN1_SET_T(opts, tag)
- *
- * Decoding:
- * SILC_ASN1_SET
- * SILC_ASN1_SET_T(opts, tag)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode set. The set must be terminated
- * with SILC_ASN1_END.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * EXAMPLE
- *
- * silc_asn1_encode(asn1, tree,
- * SILC_ASN1_SET_T(SILC_ASN1_EXPLICIT, 0),
- * SILC_ASN1_BOOLEAN(boolval),
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_SET SILC_ASN1_U0(SET)
-#define SILC_ASN1_SET_T(o, t) SILC_ASN1_T0(SET, o, t)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_SEQUENCE_OF
- *
- * SYNOPSIS
- *
- * Decoding:
- * SILC_ASN1_SEQUENCE_OF(bufarray, numbufs)
- *
- * DESCRIPTION
- *
- * Macro used to decode sequence of specified type. This returns
- * an array of SilcBuffers and number of buffers in the array. The
- * SILC_ASN1_CHOICE macro may also be used with this macro.
- *
- * NOTES
- *
- * This macro must be used either with SILC_ASN1_ALLOC or SILC_ASN1_ACCUMUL
- * flags. Do not use this macro without flags.
- *
- * EXAMPLE
- *
- * SilcBuffer bufs;
- * SilcUInt32 count;
- *
- * // Decode sequence of sequences. Each returned buffer in the array
- * // is a sequence.
- * silc_asn1_decode(asn1, exts,
- * SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
- * SILC_ASN1_SEQUENCE_OF(&bufs, &count),
- * SILC_ASN1_TAG_SEQUENCE,
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_SEQUENCE_OF(x, c) SILC_ASN1_U2(SEQUENCE_OF, x, c)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_SET_OF
- *
- * SYNOPSIS
- *
- * Decoding:
- * SILC_ASN1_SET_OF(bufarray, numbufs)
- *
- * DESCRIPTION
- *
- * Macro used to decode set of specified type. This returns
- * an array of SilcBuffers and number of buffers in the array. The
- * SILC_ASN1_CHOICE macro may also be used with this macro.
- *
- * NOTES
- *
- * This macro must be used either with SILC_ASN1_ALLOC or SILC_ASN1_ACCUMUL
- * flags. Do not use this macro without flags.
- *
- * EXAMPLE
- *
- * // Decode set of sequences. Each returned buffer in the array
- * // is a sequence.
- * silc_asn1_decode(asn1, exts,
- * SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- * SILC_ASN1_SET_OF(&bufs, &count),
- * SILC_ASN1_TAG_SEQUENCE,
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_SET_OF(x, c) SILC_ASN1_U2(SEQUENCE_OF, x, c)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_CHOICE
- *
- * SYNOPSIS
- *
- * Decoding:
- * SILC_ASN1_CHOICE
- *
- * DESCRIPTION
- *
- * Macro used to specify choices in decoding. The choice list must
- * be terminated with SILC_ASN1_END. There is no limit how many choices
- * can be specified in the list.
- *
- * EXAMPLE
- *
- * // Decode timeval that is either UTC or generalized time
- * silc_asn1_decode(asn1, tree,
- * SILC_ASN1_SEQUENCE,
- * SILC_ASN1_CHOICE,
- * SILC_ASN1_UTC_TIME(&timeval),
- * SILC_ASN1_GEN_TIME(&timeval),
- * SILC_ASN1_END,
- * SILC_ASN1_END, SILC_ASN1_END);
- *
- ***/
-#define SILC_ASN1_CHOICE SILC_ASN1_U0(CHOICE)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_BOOLEAN
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_BOOLEAN(boolval)
- * SILC_ASN1_BOOLEAN_T(opts, tag, boolval)
- *
- * Decoding:
- * SILC_ASN1_BOOLEAN(&boolval)
- * SILC_ASN1_BOOLEAN_T(opts, tag, &boolval)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode boolean value. The boolean type
- * is SilcBool.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_BOOLEAN(x) SILC_ASN1_U1(BOOLEAN, x)
-#define SILC_ASN1_BOOLEAN_T(o, t, x) SILC_ASN1_T1(BOOLEAN, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_INT
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_INT(integer)
- * SILC_ASN1_INT_T(opts, tag, &integer)
- *
- * Decoding:
- * SILC_ASN1_INT(&integer)
- * SILC_ASN1_INT_T(opts, tag, &integer);
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode multiple precision integer. The
- * integer type is SilcMPInt.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_INT(x) SILC_ASN1_U1(INTEGER, x)
-#define SILC_ASN1_INT_T(o, t, x) SILC_ASN1_T1(INTEGER, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_SHORT_INT
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_SHORT_INT(integer)
- * SILC_ASN1_SHORT_INT_T(opts, tag, &integer)
- *
- * Decoding:
- * SILC_ASN1_SHORT_INT(&integer)
- * SILC_ASN1_SHORT_INT_T(opts, tag, &integer);
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode short integer (32 bits). The
- * integer type is SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_SHORT_INT(x) SILC_ASN1_U1(SHORT_INTEGER, x)
-#define SILC_ASN1_SHORT_INT_T(o, t, x) SILC_ASN1_T1(SHORT_INTEGER, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_ENUM
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_ENUM(enum)
- * SILC_ASN1_ENUM_T(opts, tag, &enum)
- *
- * Decoding:
- * SILC_ASN1_ENUM(&enum)
- * SILC_ASN1_ENUM_T(opts, tag, &enum);
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode enumeration value. The enumeration
- * type is SilcMPInt.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_ENUM(x) SILC_ASN1_U1(ENUM, x)
-#define SILC_ASN1_ENUM_T(o, t, x) SILC_ASN1_T1(ENUM, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_BIT_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_BIT_STRING(str, str_len)
- * SILC_ASN1_BIT_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_BIT_STRING(&str, &str_len)
- * SILC_ASN1_BIT_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode bit string. The string length in
- * encoding must be in bits (bytes * 8). The decoded length is in
- * bits as well. The string type is unsigned char and string length
- * SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_BIT_STRING(x, xl) SILC_ASN1_U2(BIT_STRING, x, xl)
-#define SILC_ASN1_BIT_STRING_T(o, t, x, xl) SILC_ASN1_T2(BIT_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_NULL
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_NULL
- * SILC_ASN1_NULL_T(opts, tag)
- *
- * Decoding:
- * SILC_ASN1_NULL
- * SILC_ASN1_NULL_T(opts, tag)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode null value.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_NULL SILC_ASN1_U0(NULL)
-#define SILC_ASN1_NULL_T(o, t) SILC_ASN1_T0(NULL, 0, t)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_OID
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_OID(oid)
- * SILC_ASN1_OID_T(opts, tag, oid)
- *
- * Decoding:
- * SILC_ASN1_OID(&oid)
- * SILC_ASN1_OID_T(opts, tag, &oid)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode OID string. The OID string type
- * is NULL terminated char. Its length can be determinted with strlen().
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_OID(x) SILC_ASN1_U1(OID, x)
-#define SILC_ASN1_OID_T(o, t, x) SILC_ASN1_UT(OID, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_OCTET_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_OCTET_STRING(str, str_len)
- * SILC_ASN1_OCTET_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_OCTET_STRING(&str, &str_len)
- * SILC_ASN1_OCTET_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode octet string. The string type is
- * unsigned char and string length SilcUInt32. Octet string is
- * considered to be 8-bit unsigned binary data.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_OCTET_STRING(x, xl) SILC_ASN1_U2(OCTET_STRING, x, xl)
-#define SILC_ASN1_OCTET_STRING_T(o, t, x, xl) SILC_ASN1_T2(OCTET_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_UTF8_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_UTF8_STRING(str, str_len)
- * SILC_ASN1_UTF8_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_UTF8_STRING(&str, &str_len)
- * SILC_ASN1_UTF8_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode UTF-8 string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The data is also encoded to
- * or decoded from UTF-8.
- *
- ***/
-#define SILC_ASN1_UTF8_STRING(x, xl) SILC_ASN1_U2(UTF8_STRING, x, xl)
-#define SILC_ASN1_UTF8_STRING_T(o, t, x, xl) SILC_ASN1_T2(UTF8_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_NUMERIC_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_NUMERIC_STRING(str, str_len)
- * SILC_ASN1_NUMERIC_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_NUMERIC_STRING(&str, &str_len)
- * SILC_ASN1_NUMERIC_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode numerical string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from numerical.
- *
- ***/
-#define SILC_ASN1_NUMERIC_STRING(x, xl) SILC_ASN1_U2(NUMERIC_STRING, x, xl)
-#define SILC_ASN1_NUMERIC_STRING_T(o, t, x, xl) SILC_ASN1_T2(NUMERIC_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_PRINTABLE_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_PRINTABLE_STRING(str, str_len)
- * SILC_ASN1_PRINTABLE_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_PRINTABLE_STRING(&str, &str_len)
- * SILC_ASN1_PRINTABLE_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode printable string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from printable.
- *
- ***/
-#define SILC_ASN1_PRINTABLE_STRING(x, xl) SILC_ASN1_U2(PRINTABLE_STRING, x, xl)
-#define SILC_ASN1_PRINTABLE_STRING_T(o, t, x, xl) SILC_ASN1_T2(PRINTABLE_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_TELETEX_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_TELETEX_STRING(str, str_len)
- * SILC_ASN1_TELETEX_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_TELETEX_STRING(&str, &str_len)
- * SILC_ASN1_TELETEX_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode teletex (T61) string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from teletex (T61).
- *
- ***/
-#define SILC_ASN1_TELETEX_STRING(x, xl) SILC_ASN1_U2(TELETEX_STRING, x, xl)
-#define SILC_ASN1_TELETEX_STRING_T(o, t, x, xl) SILC_ASN1_T2(TELETEX_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_IA5_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_IA5_STRING(str, str_len)
- * SILC_ASN1_IA5_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_IA5_STRING(&str, &str_len)
- * SILC_ASN1_IA5_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode US ASCII (IA5) string. The string type
- * is unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from US ASCII (IA5).
- *
- ***/
-#define SILC_ASN1_IA5_STRING(x, xl) SILC_ASN1_U2(IA5_STRING, x, xl)
-#define SILC_ASN1_IA5_STRING_T(o, t, x, xl) SILC_ASN1_T2(IA5_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_VISIBLE_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_VISIBLE_STRING(str, str_len)
- * SILC_ASN1_VISIBLE_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_VISIBLE_STRING(&str, &str_len)
- * SILC_ASN1_VISIBLE_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode visible string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from visible.
- *
- ***/
-#define SILC_ASN1_VISIBLE_STRING(x, xl) SILC_ASN1_U2(VISIBLE_STRING, x, xl)
-#define SILC_ASN1_VISIBLE_STRING_T(o, t, x, xl) SILC_ASN1_T2(VISIBLE_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_UNIVERSAL_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_UNIVERSAL_STRING(str, str_len)
- * SILC_ASN1_UNIVERSAL_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_UNIVERSAL_STRING(&str, &str_len)
- * SILC_ASN1_UNIVERSAL_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode universal (UCS-4) string. The string
- * type is unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from universal (UCS-4).
- *
- ***/
-#define SILC_ASN1_UNIVERSAL_STRING(x, xl) SILC_ASN1_U2(UNIVERSAL_STRING, x, xl)
-#define SILC_ASN1_UNIVERSAL_STRING_T(o, t, x, xl) SILC_ASN1_T2(UNIVERSAL_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_BMP_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_BMP_STRING(str, str_len)
- * SILC_ASN1_BMP_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_BMP_STRING(&str, &str_len)
- * SILC_ASN1_BMP_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode BMP (UCS-2) string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from BMP (UCS-2)
- *
- ***/
-#define SILC_ASN1_BMP_STRING(x, xl) SILC_ASN1_U2(BMP_STRING, x, xl)
-#define SILC_ASN1_BMP_STRING_T(o, t, x, xl) SILC_ASN1_T2(BMP_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_UNRESTRICTED_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_UNRESTRICTED_STRING(str, str_len)
- * SILC_ASN1_UNRESTRICTED_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_UNRESTRICTED_STRING(&str, &str_len)
- * SILC_ASN1_UNRESTRICTED_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode unrestricted string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from unrestricted. NOTE: this implementation use 8-bit ASCII.
- *
- ***/
-#define SILC_ASN1_UNRESTRICTED_STRING(x, xl) SILC_ASN1_U2(UNRESTRICTED_STRING, x, xl)
-#define SILC_ASN1_UNRESTRICTED_STRING_T(o, t, x, xl) SILC_ASN1_T2(UNRESTRICTED_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_GENERAL_STRING
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_GENERAL_STRING(str, str_len)
- * SILC_ASN1_GENERAL_STRING_T(opts, tag, str, str_len)
- *
- * Decoding:
- * SILC_ASN1_GENERAL_STRING(&str, &str_len)
- * SILC_ASN1_GENERAL_STRING_T(opts, tag, &str, &str_len)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode general string. The string type is
- * unsigned char and string length SilcUInt32.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- * NOTES
- *
- * The string must be in UTF-8 encoding when encoding. The decoded
- * string will be in UTF-8 encoding. The actual data is encoded to
- * or decoded from general. NOTE: this implementation use 8-bit ASCII.
- *
- ***/
-#define SILC_ASN1_GENERAL_STRING(x, xl) SILC_ASN1_U2(GENERAL_STRING, x, xl)
-#define SILC_ASN1_GENERAL_STRING_T(o, t, x, xl) SILC_ASN1_T2(GENERAL_STRING, o, t, x, xl)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_UTC_TIME
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_UTC_TIME(timeval)
- * SILC_ASN1_UTC_TIME_T(opts, tag, timeval)
- *
- * Decoding:
- * SILC_ASN1_UTC_TIME(&str, &timeval)
- * SILC_ASN1_UTC_TIME_T(opts, tag, timeval)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode universal (UTC) time value. The
- * time value type is SilcTime.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_UTC_TIME(x) SILC_ASN1_U1(UTC_TIME, x)
-#define SILC_ASN1_UTC_TIME_T(o, t, x) SILC_ASN1_T1(UTC_TIME, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_GEN_TIME
- *
- * SYNOPSIS
- *
- * Encoding:
- * SILC_ASN1_GEN_TIME(timeval)
- * SILC_ASN1_GEN_TIME_T(opts, tag, timeval)
- *
- * Decoding:
- * SILC_ASN1_GEN_TIME(&str, &timeval)
- * SILC_ASN1_GEN_TIME_T(opts, tag, timeval)
- *
- * DESCRIPTION
- *
- * Macro used to encode or decode generalized time value. The
- * time value type is SilcTime.
- *
- * The `opts' is SilcAsn1Options. The `tag' is a tag number.
- *
- ***/
-#define SILC_ASN1_GEN_TIME(x) SILC_ASN1_U1(GENERALIZED_TIME, x)
-#define SILC_ASN1_GEN_TIME_T(o, t, x) SILC_ASN1_T1(GENERALIZED_TIME, o, t, x)
-
-/****f* silcasn1/SilcASN1API/SILC_ASN1_END
- *
- * SYNOPSIS
- *
- * SILC_ASN1_END
- *
- * DESCRIPTION
- *
- * The SILC_ASN1_END is used to terminate the variable argument list in
- * silc_asn1_encode and silc_asn1_decode functions. It is also used to
- * terminate SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE_T, SILC_ASN1_SET,
- * SILC_ASN1_SET_T, SILC_ASN1_SEQUENCE_OF, SILC_ASN1_SET_OF and
- * SILC_ASN1_CHOICE macros.
- *
- ***/
-#define SILC_ASN1_END 0
-
-#endif /* SILCASN1_H */
+++ /dev/null
-/*
-
- silcasn1_decode.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2007 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 "silcasn1.h"
-#include "silcber.h"
-
-/************************** ASN.1 Decoder routines **************************/
-
-/* Internal SEQUENCE OF and SET OF decoder. This is used only when decoding
- these two special tags. Other normal ASN.1 decoding is done in the
- silc_asn1_decoder function. This parses the sequence of types and returns
- them as raw BER buffers in an array of SilcBuffers. */
-
-static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src)
-{
- SilcBool ret = FALSE;
- SilcList types;
- SilcAsn1Tag type;
- SilcBuffer *retb;
- SilcUInt32 *retc, rtag;
- const unsigned char *rdata;
- SilcUInt32 rdata_len, len = 0;
- SilcBool found = FALSE, rindef;
-
- struct SilcAsn1SofStruct {
- SilcAsn1Tag type;
- struct SilcAsn1SofStruct *next;
- } *t = NULL;
-
- SILC_LOG_DEBUG(("Decoding sequence of types"));
-
- silc_list_init(types, struct SilcAsn1SofStruct, next);
-
- /* Take the return arguments */
- retb = va_arg(asn1->ap, SilcBuffer *);
- retc = va_arg(asn1->ap, SilcUInt32 *);
- *retb = NULL;
- *retc = 0;
-
- /* Get the sequence type(s). If the type is CHOICE tag then the sequence
- may include multiple different types. All types are considered
- separately. If CHOICE is not given then only single type is expected. */
- type = va_arg(asn1->ap, SilcUInt32);
- assert(type != SILC_ASN1_END);
-
- if (type == SILC_ASN1_TAG_CHOICE) {
- /* The sequence may consist of the following types. */
- type = va_arg(asn1->ap, SilcUInt32);
- assert(type != SILC_ASN1_END);
- while (type != SILC_ASN1_END) {
- t = silc_smalloc(asn1->stack1, sizeof(*t));
- if (!t)
- goto out;
- t->type = type;
- silc_list_add(types, t);
-
- SILC_LOG_DEBUG(("Looking for %s [%d] from sequence of types",
- silc_asn1_tag_name(type), type));
-
- type = va_arg(asn1->ap, SilcUInt32);
- }
- } else {
- /* The sequence consists of this type. */
- t = silc_smalloc(asn1->stack1, sizeof(*t));
- if (!t)
- goto out;
- t->type = type;
- silc_list_add(types, t);
-
- SILC_LOG_DEBUG(("Looking for %s [%d] from sequence of types",
- silc_asn1_tag_name(type), type));
- }
-
- /* END marker for the sequence */
- type = va_arg(asn1->ap, SilcUInt32);
- assert(type == SILC_ASN1_END);
-
- /* Decode the SEQUENCE or SET */
- ret = silc_ber_decode(src, NULL, NULL, &rtag, &rdata,
- &rdata_len, &rindef, &len);
- if (!ret) {
- SILC_LOG_DEBUG(("Error parsing BER block, malformed ASN.1 data"));
- goto out;
- }
- if (rtag != SILC_ASN1_TAG_SEQUENCE && rtag != SILC_ASN1_TAG_SET) {
- SILC_LOG_DEBUG(("Invalid sequence of/set of"));
- goto out;
- }
- silc_buffer_pull(src, len);
-
- while (silc_buffer_len(src)) {
- /* Decode the BER data. */
- ret = silc_ber_decode(src, NULL, NULL, &rtag, &rdata,
- &rdata_len, &rindef, &len);
- if (!ret) {
- SILC_LOG_DEBUG(("Error parsing BER block, malformed ASN.1 data"));
- goto out;
- }
-
- /* Now check the type(s) that it is supposed to be */
- found = FALSE;
- silc_list_start(types);
- while ((t = silc_list_get(types)) != SILC_LIST_END) {
- if (t->type != rtag)
- continue;
-
- *retb = silc_srealloc(asn1->stack1, sizeof(**retb) * (*retc), *retb,
- sizeof(**retb) * (*retc + 1));
- if (*retb == NULL)
- goto out;
-
- SILC_LOG_DEBUG(("Decode %s [%d] from sequence of types",
- silc_asn1_tag_name(rtag), rtag));
-
- /* Data is duplicated only if SILC_ASN1_ALLOC flag is set */
- if (!asn1->stack1)
- rdata = silc_memdup(rdata - len, rdata_len + len);
- else
- rdata = rdata - len;
- rdata_len += len;
-
- /* Save the data */
- silc_buffer_set(&(*retb)[*retc], (unsigned char *)rdata, rdata_len);
- (*retc)++;
- found = TRUE;
- break;
- }
-
- /* If type was not found we consider it the end of the sequence */
- if (found == FALSE)
- break;
-
- if (rdata_len)
- silc_buffer_pull(src, rdata_len);
- }
-
- SILC_LOG_DEBUG(("Decoded %d types", *retc));
- ret = TRUE;
-
- out:
- if (!asn1->stack1) {
- silc_list_start(types);
- while ((t = silc_list_get(types)) != SILC_LIST_END)
- silc_free(t);
- }
-
- return ret;
-}
-
-/* Macro for decoder to get argument for a type. If OPTIONAL option is
- set then the argument is a pointer to the type pointer. The `type'
- must be a non-pointer type, eg. int, SilcBufferStruct. */
-#define SILC_ASN1_VAD(asn1, opts, type, name) \
- type **name; \
- if ((opts) & SILC_ASN1_OPTIONAL && !choice) { \
- name = va_arg(asn1->ap, type **); \
- if (!found) { \
- if (name) \
- *name = NULL; \
- break; \
- } \
- if (name == NULL) \
- break; \
- *name = silc_scalloc(asn1->stack1, 1, sizeof(**name)); \
- if (*name == NULL) \
- break; \
- } else { \
- type *name ## tmp = va_arg(asn1->ap, type *); \
- if (choice && found && !len) \
- break; \
- if (name ## tmp == NULL) \
- break; \
- name = &name ## tmp; \
- }
-
-/* Same as SILC_ASN1_VAD but for unsigned char and SilcUInt32 */
-#define SILC_ASN1_VAD_UCHAR(asn1, opts, type, name, namelen) \
- type **name = va_arg(asn1->ap, type **); \
- SilcUInt32 *namelen = va_arg(asn1->ap, SilcUInt32 *); \
- if (choice && found && !len) \
- break; \
- if (!found) { \
- if (name) \
- *name = NULL; \
- break; \
- } \
- if (name == NULL) \
- break;
-
-/* Same as SILC_ASN1_VAD but for char only */
-#define SILC_ASN1_VAD_CHAR(asn1, opts, type, name) \
- type **name = va_arg(asn1->ap, type **); \
- if (choice && found && !len) \
- break; \
- if (!found) { \
- if (name) \
- *name = NULL; \
- break; \
- } \
- if (name == NULL) \
- break;
-
-#define SILC_ASN1_VA_FREE(opts, name) \
- if ((opts) & SILC_ASN1_OPTIONAL) \
- silc_free(*name);
-
-/* Decodes string to UTF-8 string which is our internal representation
- of any string. */
-#define SILC_ASN1_DECODE_STRING(enc, s, s_len) \
- *s_len = silc_utf8_encoded_len(rdata, rdata_len, (enc)); \
- if (*s_len == 0) { \
- SILC_LOG_DEBUG(("Malformed %d string value", (enc))); \
- ret = FALSE; \
- goto fail; \
- } \
- *s = silc_smalloc_ua(stack1, *s_len + 1); \
- if (*s) { \
- silc_utf8_encode(rdata, rdata_len, (enc), *s, *s_len); \
- (*s)[*s_len] = '\0'; \
- }
-
-
-/* Internal ASN.1 decoder. The `type', `tag' and `opts' are the first
- arguments (either very first or first for recursion) for a type.
- The `depth' includes the current depth of recursion. */
-
-static SilcBool
-silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type,
- SilcAsn1Tag tag, SilcBerClass ber_class,
- SilcAsn1Options opts, SilcBuffer src, SilcUInt32 depth,
- SilcBool primitive)
-{
- unsigned char *ptr = src->data;
- SilcAsn1Tag rtype;
- SilcAsn1Options ropts;
- SilcBerClass rclass;
- SilcBerEncoding renc;
- SilcUInt32 len = 0, rtag;
- SilcBool ret, indef, rindef, found = FALSE, choice = FALSE;
- const unsigned char *rdata;
- SilcUInt32 rdata_len;
- int i;
-
-#ifdef SILC_DEBUG
- char sp[SILC_ASN1_RECURSION_DEPTH + 1];
- memset(sp, 0, sizeof(sp));
- if (depth)
- memset(sp, 32, depth);
-#endif /* SILC_DEBUG */
-
- if (depth >= SILC_ASN1_RECURSION_DEPTH) {
- SILC_LOG_DEBUG(("Maximum recursion depth reached"));
- return FALSE;
- }
-
- while (1) {
-
- /* If requested type is SEQUENCE OF or SET OF then we decode the sequence
- of types separately in an own decoder which returns array of buffers. */
- if (type == SILC_ASN1_TAG_SEQUENCE_OF) {
- /* Decode the sequence */
- if (!silc_asn1_decoder_sof(asn1, src)) {
- SILC_LOG_DEBUG(("Error decoding SEQUENCE OF"));
- ret = FALSE;
- goto fail;
- }
-
- /* Continue with rest of the decodings if any */
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- if (type == SILC_ASN1_END) {
- ret = TRUE;
- goto ok;
- }
- }
-
- /* Get length encoding */
- indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
-
- /* By default UNIVERSAL is implied unless the following conditions
- are met when CONTEXT will apply. For SILC_ASN1_TAG_ANY_PRIMITIVE
- the class is changed only if flags dictate it. */
- if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
- if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
- if (opts & SILC_ASN1_IMPLICIT ||
- opts & SILC_ASN1_EXPLICIT)
- ber_class = SILC_BER_CLASS_CONTEXT;
- } else {
- if (tag != type ||
- opts & SILC_ASN1_IMPLICIT ||
- opts & SILC_ASN1_EXPLICIT)
- ber_class = SILC_BER_CLASS_CONTEXT;
- }
- }
-
- /* Short integer is actually big integer in the BER data, so handle
- it correctly */
- if (type == SILC_ASN1_TAG_SHORT_INTEGER && type == tag)
- tag = SILC_ASN1_TAG_INTEGER;
-
- /* Now decode a BER encoded block from the source buffer. It must be
- exactly the same user is expecting. */
- ret = silc_ber_decode(src, &rclass, &renc, &rtag, &rdata,
- &rdata_len, &rindef, &len);
- if (!ret) {
- SILC_LOG_DEBUG(("Error parsing BER block, malformed ASN.1 data"));
- return FALSE;
- }
-
- /* Now verify that the decoded BER is the one user wanted to get. If
- requested type is OPTIONAL, then ignore all the sanity tests. The
- while() loop is for re-considering OPTIONAL types without parsing
- new BER object. For CHOICE (tag) all the choice considerations are
- also done within the while(). */
- while (1) {
-
- /* If type is CHOICE then at least one type must match before next
- SILC_ASN1_END is reached. The considerations act interally as
- having OPTIONAL flag set, except that at the end one must have
- been found. */
- if (type == SILC_ASN1_TAG_CHOICE) {
- choice = TRUE;
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- opts |= SILC_ASN1_OPTIONAL;
- found = FALSE;
- }
-
-#ifdef SILC_DEBUG
- SILC_LOG_DEBUG(
- ("%04d: %sDecode %s [%d] %s %s %s %s", depth, sp[0] ? sp : "",
- silc_asn1_tag_name(type), rtag,
- rclass == SILC_BER_CLASS_UNIVERSAL ? "univ" :
- rclass == SILC_BER_CLASS_APPLICATION ? "appl" :
- rclass == SILC_BER_CLASS_CONTEXT ? "cont" : "priv",
- renc == SILC_BER_ENC_PRIMITIVE ? "primit" : "constr",
- rindef ? "indef" : "defin",
- choice ? "choice" : opts & SILC_ASN1_OPTIONAL ? "option" : ""));
-#endif /* SILC_DEBUG */
-
- if (type != SILC_ASN1_TAG_ANY && tag != rtag) {
- if (!(opts & SILC_ASN1_OPTIONAL)) {
- SILC_LOG_DEBUG(("Invalid ASN.1 tag %u, expected %u", rtag, tag));
- return FALSE;
- }
- if (!choice)
- found = FALSE;
-
- } else if (ber_class != rclass) {
- if (!(opts & SILC_ASN1_OPTIONAL)) {
- SILC_LOG_DEBUG(("Invalid ASN.1 class %d, expected %d",
- rclass, ber_class));
- return FALSE;
- }
- if (!choice)
- found = FALSE;
-
- } else if (!(opts & SILC_ASN1_EXPLICIT) && indef != rindef) {
- SILC_LOG_DEBUG(("Invalid ASN.1 length encoding %s, expected %s",
- rindef ? "indefinite" : "definite",
- indef ? "indefinite" : "definite"));
- return FALSE;
-
- } else if (rindef && renc == SILC_BER_ENC_PRIMITIVE) {
- SILC_LOG_DEBUG(("Invalid length encoding for primitive type"));
- return FALSE;
-
- } else {
- found = TRUE;
- }
-
- /* If tagging is explicit we have additional sequence we need to decode
- before we decode the actual underlaying type. */
- if (opts & SILC_ASN1_EXPLICIT) {
- silc_buffer_pull(src, len);
- len = 0;
-
- primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
- type != SILC_ASN1_TAG_SET &&
- type != SILC_ASN1_TAG_ANY);
- opts &= ~SILC_ASN1_EXPLICIT;
-
- ret = silc_asn1_decoder(asn1, stack1, type, type,
- SILC_BER_CLASS_UNIVERSAL, opts, src,
- depth + 1, primitive);
- if (!ret)
- goto fail;
- if (primitive) {
- primitive = FALSE;
- goto cont;
- }
- goto ok;
- }
-
- /* Decode by the type user expects the data to be. */
- switch (type) {
-
- case SILC_ASN1_TAG_ANY:
- {
- /* ANY is another ASN.1 node. We return the raw BER buffer as
- the node */
- SILC_ASN1_VAD(asn1, opts, SilcBufferStruct, node);
-
- *node = silc_buffer_srealloc_size(stack1, *node, len + rdata_len);
- silc_buffer_put(*node, rdata - len, rdata_len + len);
- break;
- }
-
- case SILC_ASN1_TAG_ANY_PRIMITIVE:
- {
- /* ANY_PRIMITIVE returns the raw data blob of any primitive type. */
- SILC_ASN1_VAD(asn1, opts, SilcBufferStruct, prim);
-
- *prim = silc_buffer_srealloc_size(stack1, *prim, rdata_len);
- silc_buffer_put(*prim, rdata, rdata_len);
- break;
- }
-
- case SILC_ASN1_TAG_SEQUENCE:
- case SILC_ASN1_TAG_SET:
- {
- /* SEQUENCE/SET is a sequence of types. */
- silc_buffer_pull(src, len);
- len = 0;
-
- /* Get type, tag and options for the first argument in recursion */
- SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
-
- /* Decode the sequence recursively */
- ret = silc_asn1_decoder(asn1, stack1, rtype, rtag, rclass,
- ropts, src, depth + 1, FALSE);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_INTEGER:
- case SILC_ASN1_TAG_ENUM:
- {
- /* Integer/enum value. */
- SilcMPInt z;
- SILC_ASN1_VAD(asn1, opts, SilcMPInt, intval);
-
- if (rdata_len < 1) {
- SILC_LOG_DEBUG(("Malformed integer value"));
- SILC_ASN1_VA_FREE(opts, intval);
- ret = FALSE;
- goto fail;
- }
-
- silc_mp_sinit(asn1->stack1, *intval);
-
- /* Check whether the integer is positive or negative */
- if (rdata[0] & 0x80) {
- /* Negative integer stored in 1s complement.*/
- for (i = 0; i < rdata_len; i++) {
- silc_mp_mul_2exp(*intval, *intval, 8);
- silc_mp_add_ui(*intval, *intval, ~rdata[i] & 0xff);
- }
-
- /* 2s complement and change sign */
- silc_mp_init(&z);
- silc_mp_set_ui(&z, 0);
- silc_mp_add_ui(*intval, *intval, 1);
- silc_mp_sub(*intval, &z, *intval);
- silc_mp_uninit(&z);
- } else {
- /* Positive */
- silc_mp_bin2mp((unsigned char *)rdata, rdata_len, *intval);
- }
-
- break;
- }
-
- case SILC_ASN1_TAG_SHORT_INTEGER:
- {
- /* Short Integer */
- SilcMPInt z;
- SILC_ASN1_VAD(asn1, opts, SilcUInt32, intval);
-
- if (rdata_len < 1) {
- SILC_LOG_DEBUG(("Malformed integer value"));
- SILC_ASN1_VA_FREE(opts, intval);
- ret = FALSE;
- goto fail;
- }
-
- silc_stack_push(asn1->stack1, NULL);
- silc_mp_sinit(asn1->stack1, &z);
- silc_mp_bin2mp((unsigned char *)rdata, rdata_len, &z);
- *(*intval) = silc_mp_get_ui(&z);
- silc_mp_uninit(&z);
- silc_stack_pop(asn1->stack1);
- break;
- }
-
- case SILC_ASN1_TAG_OID:
- {
- /* Object identifier */
- SilcBufferStruct tmpb;
- char tmpstr[24];
- SilcUInt32 oid;
- SILC_ASN1_VAD_CHAR(asn1, opts, char, oidstr);
-
- if (rdata_len < 1) {
- SILC_LOG_DEBUG(("Malformed object identifier value"));
- SILC_ASN1_VA_FREE(opts, oidstr);
- ret = FALSE;
- goto fail;
- }
-
- /* Set two OID values */
- memset(&tmpb, 0, sizeof(tmpb));
- memset(tmpstr, 0, sizeof(tmpstr));
- silc_snprintf(tmpstr, sizeof(tmpstr) - 1, "%lu.%lu",
- (unsigned long)(rdata[0] & 0xff) / 40,
- (unsigned long)(rdata[0] & 0xff) % 40);
- silc_buffer_sstrformat(asn1->stack1, &tmpb, tmpstr, SILC_STR_END);
-
- /* Set rest of the OID values, each octet having 7 bits of the
- OID value with bit 8 set. An octet not having bit 8 set
- means end of that OID value. */
- for (i = 1; i < rdata_len; i++) {
- oid = 0;
- while (rdata[i] & 0x80) {
- oid <<= 7;
- oid |= rdata[i++] & 0x7f;
- if (i >= rdata_len) {
- SILC_LOG_DEBUG(("Malformed object identifier value"));
- break;
- }
- }
- oid <<= 7;
- oid |= rdata[i];
-
- memset(tmpstr, 0, sizeof(tmpstr));
- silc_snprintf(tmpstr, sizeof(tmpstr) - 1, ".%lu", (unsigned long)oid);
- silc_buffer_sstrformat(asn1->stack1, &tmpb, tmpstr, SILC_STR_END);
- }
- *oidstr = tmpb.head;
-
- break;
- }
-
- case SILC_ASN1_TAG_BOOLEAN:
- {
- /* Decode boolean (TRUE/FALSE) value */
- SILC_ASN1_VAD(asn1, opts, SilcBool, val);
-
- if (rdata_len != 1) {
- SILC_LOG_DEBUG(("Malformed boolean value"));
- SILC_ASN1_VA_FREE(opts, val);
- ret = FALSE;
- goto fail;
- }
-
- *(*val) = (rdata[0] == 0xff ? TRUE : FALSE);
- break;
- }
-
- case SILC_ASN1_TAG_BIT_STRING:
- {
- /* Bit string contains data with exact bit length of the data */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, d, d_len);
-
- if (rdata_len < 2) {
- SILC_LOG_DEBUG(("Malformed bit string value"));
- SILC_ASN1_VA_FREE(opts, d);
- ret = FALSE;
- goto fail;
- }
-
- *d = silc_smemdup(stack1, rdata + 1, rdata_len - 1);
- *d_len = (rdata_len - 1) * 8;
- break;
- }
-
- case SILC_ASN1_TAG_NULL:
- {
- /* Decode empty BER block */
- if (rdata_len != 0) {
- SILC_LOG_DEBUG(("Malformed null value"));
- goto fail;
- }
- break;
- }
-
- case SILC_ASN1_TAG_UTC_TIME:
- {
- /* Universal encoded time string */
- SILC_ASN1_VAD(asn1, opts, SilcTimeStruct, t);
-
- if (rdata_len < 1) {
- SILC_LOG_DEBUG(("Malformed UTC time value"));
- SILC_ASN1_VA_FREE(opts, t);
- ret = FALSE;
- goto fail;
- }
-
- /* Parse the time string */
- if (!silc_time_universal(rdata, *t)) {
- SILC_LOG_DEBUG(("Malformed UTC time value"));
- ret = FALSE;
- goto fail;
- }
-
- break;
- }
-
- case SILC_ASN1_TAG_GENERALIZED_TIME:
- {
- /* Generalized encoded time string */
- SILC_ASN1_VAD(asn1, opts, SilcTimeStruct, t);
-
- if (rdata_len < 1) {
- SILC_LOG_DEBUG(("Malformed generalized time value"));
- SILC_ASN1_VA_FREE(opts, t);
- ret = FALSE;
- goto fail;
- }
-
- /* Parse the time string */
- if (!silc_time_generalized(rdata, *t)) {
- SILC_LOG_DEBUG(("Malformed generalized time value"));
- SILC_ASN1_VA_FREE(opts, t);
- ret = FALSE;
- goto fail;
- }
-
- break;
- }
-
- case SILC_ASN1_TAG_UTF8_STRING:
- {
- /* UTF-8 encoded string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
-
- if (!silc_utf8_valid(rdata, rdata_len)) {
- SILC_LOG_DEBUG(("Malformed UTF-8 string value"));
- SILC_ASN1_VA_FREE(opts, s);
- ret = FALSE;
- goto fail;
- }
-
- *s = silc_smemdup(stack1, rdata, rdata_len);
- *s_len = rdata_len;
- break;
- }
-
- case SILC_ASN1_TAG_OCTET_STRING:
- {
- /* Octet string. Take data as is. */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- *s = silc_smemdup(stack1, rdata, rdata_len);
- *s_len = rdata_len;
- break;
- }
-
- case SILC_ASN1_TAG_NUMERIC_STRING:
- {
- /* Numerical (digit) string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_NUMERICAL, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_PRINTABLE_STRING:
- {
- /* Printable string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_PRINTABLE, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_TELETEX_STRING:
- {
- /* Teletex (T61) string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_TELETEX, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_IA5_STRING:
- {
- /* US ASCII string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_ASCII, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_VISIBLE_STRING:
- {
- /* Visible string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_VISIBLE, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_UNIVERSAL_STRING:
- {
- /* Universal (UCS-4) string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_UNIVERSAL, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_UNRESTRICTED_STRING:
- case SILC_ASN1_TAG_GENERAL_STRING:
- {
- /* Handle now unrestricted and general as 8-bit ascii, which
- probably isn't correct. */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_ASCII, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_BMP_STRING:
- {
- /* BMP (UCS-2) string */
- SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len);
- SILC_ASN1_DECODE_STRING(SILC_STRING_BMP, s, s_len);
- break;
- }
-
- case SILC_ASN1_TAG_ODE:
- case SILC_ASN1_TAG_ETI:
- case SILC_ASN1_TAG_REAL:
- case SILC_ASN1_TAG_EMBEDDED:
- case SILC_ASN1_TAG_ROI:
- case SILC_ASN1_TAG_VIDEOTEX_STRING:
- case SILC_ASN1_TAG_GRAPHIC_STRING:
- {
- SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
- ret = FALSE;
- goto fail;
- break;
- }
-
- default:
- SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot decode ASN.1.",
- type));
- ret = FALSE;
- goto fail;
- break;
- }
-
- cont:
- /* Pull the current data from source which reveals next BER object */
- if (found && len + rdata_len)
- silc_buffer_pull(src, len + rdata_len);
- if (primitive) {
- ret = TRUE;
- goto ok;
- }
-
- /* Get next type, tag and options */
- rtype = type;
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- if (type == SILC_ASN1_END) {
- if (choice) {
- if (!found) {
- /* No choices were found, error */
- SILC_LOG_DEBUG(("Invalid ASN.1 choice: no choices present"));
- ret = FALSE;
- goto fail;
- }
-
- /* Take next type and new BER object, choices are over */
- choice = FALSE;
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- if (type == SILC_ASN1_END) {
- ret = TRUE;
- goto ok;
- }
- break;
- }
-
- /* SEQUENCE/SET end */
- ret = TRUE;
- goto ok;
- }
-
- if (choice) {
- /* Even if the choice was found we must go through rest of
- the choices. */
- if (found && len) {
- SILC_LOG_DEBUG(("Found choice %s type", silc_asn1_tag_name(rtype)));
- rdata_len = len = 0;
- }
- opts |= SILC_ASN1_OPTIONAL;
- continue;
- }
-
- /* Optional type not present, check next one for match */
- if (!found)
- continue;
-
- break;
- }
- }
-
- fail:
- SILC_LOG_DEBUG(("Error decoding type %d (depth %d)", type, depth));
-
- ok:
- if (ptr)
- len = src->data - ptr;
- else
- len = src->data - src->head;
- silc_buffer_push(src, len);
-
- return ret;
-}
-
-SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...)
-{
- SilcAsn1Tag type, tag;
- SilcAsn1Options opts;
- SilcBerClass ber_class;
- SilcStackFrame frame1, frame2;
- SilcStack stack1 = NULL, stack2 = NULL;
- SilcBool ret;
-
- if (!asn1)
- return FALSE;
-
- va_start(asn1->ap, src);
-
- /* Get the first arguments and call the decoder. */
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- if (!type) {
- va_end(asn1->ap);
- return FALSE;
- }
-
- /* Handle internal options for decoder. */
- if (type == SILC_ASN1_TAG_OPTS) {
- SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
-
- if (o & SILC_ASN1_ALLOC) {
- /* User wants to alloate everything. Set the stacks to NULL so
- that stack aware calls revert to normal allocation routines. */
- stack1 = asn1->stack1;
- stack2 = asn1->stack2;
- asn1->stack1 = NULL;
- asn1->stack2 = NULL;
- }
-
- if (o & SILC_ASN1_ACCUMUL) {
- /* If accumul flag is not set yet, then push the stacks. */
- if (!asn1->accumul) {
- silc_stack_push(asn1->stack1, NULL);
- silc_stack_push(asn1->stack2, NULL);
- asn1->accumul = 1;
- }
- }
-
- /* Take again the arguments */
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- } else {
- /* No flags set, all flags will be reset. */
-
- /* If accumul flag is set now pop the stack so that all accumulated
- memory becomes free again. */
- if (asn1->accumul) {
- silc_stack_pop(asn1->stack1);
- silc_stack_pop(asn1->stack2);
- asn1->accumul = 0;
- }
- }
-
- /* Push stacks for normal allocation from stack */
- if (!asn1->accumul) {
- silc_stack_push(asn1->stack1, &frame1);
- silc_stack_push(asn1->stack2, &frame2);
- }
-
- /* Start decoding */
- ret = silc_asn1_decoder(asn1, asn1->stack1, type, tag, ber_class,
- opts, src, 0, FALSE);
-
- /* Pop stacks to free normal allocations from stack. They remain valid
- for every second call to this function. */
- if (!asn1->accumul) {
- silc_stack_pop(asn1->stack1);
- silc_stack_pop(asn1->stack2);
-
- /* Switch the asn1->stack1 and asn1->stack2. This way next call to
- this function does not invalidate these results. Every second call
- invalidates the results of every second previous results. */
- if (asn1->stack1 && asn1->stack2) {
- stack1 = asn1->stack1;
- asn1->stack1 = asn1->stack2;
- asn1->stack2 = stack1;
- }
- }
-
- if (stack1 && stack2 && !asn1->stack1 && !asn1->stack2) {
- /* SILC_ASN1_ALLOC flag was set, restore the stacks. */
- asn1->stack1 = stack1;
- asn1->stack2 = stack2;
- }
-
- va_end(asn1->ap);
-
- return ret;
-}
+++ /dev/null
-/*
-
- silcasn1_encode.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2007 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 "silcasn1.h"
-#include "silcber.h"
-
-#define SILC_ASN1_BUFFER_FREE(b, stack) if (!stack) silc_buffer_purge(b);
-
-/************************** ASN.1 Encoder routines **************************/
-
-/* Encode string from UTF-8 string to other string encodings. Encodes
- diretly to BER blob. */
-#define SILC_ASN1_ENCODE_STRING(enc) \
- unsigned char *s, *d = va_arg(asn1->ap, unsigned char *); \
- SilcUInt32 s_len, d_len = va_arg(asn1->ap, SilcUInt32); \
- if (!d) \
- break; \
- s_len = silc_utf8_decoded_len(d, d_len, (enc)); \
- if (s_len == 0) { \
- SILC_LOG_DEBUG(("Malformed %d string value", (enc))); \
- goto fail; \
- } \
- silc_stack_push(asn1->stack2, &frame); \
- s = silc_smalloc_ua(stack2, s_len + 1); \
- if (s) { \
- silc_utf8_decode(d, d_len, (enc), s, s_len); \
- s[s_len] = '\0'; \
- } \
- len = silc_ber_encoded_len(tag, s_len, indef); \
- dest = silc_buffer_srealloc_size(stack1, dest, \
- silc_buffer_truelen(dest) + len); \
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, \
- tag, s, s_len, indef); \
- silc_stack_pop(asn1->stack2); \
- if (!ret) \
- goto fail;
-
-/* The internal ASN.1 encoder. The `type', `tag' and `opts' are the
- first arguments (either very first or first for recursion) for a type.
- The `depth' includes the current depth of recursion. The `primitive'
- is TRUE if this encoder receives one primitive type as argument. If
- it is a constructed type it must be FALSE value. */
-
-static SilcBool
-silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
- SilcAsn1Tag type, SilcAsn1Tag tag, SilcBerClass ber_class,
- SilcAsn1Options opts, SilcBuffer dest, SilcUInt32 depth,
- SilcBool primitive)
-{
- unsigned char *ptr = dest->data;
- SilcAsn1Tag rtype, rtag;
- SilcAsn1Options ropts;
- SilcBerClass rclass;
- SilcUInt32 len = 0;
- SilcBool ret = FALSE, indef;
- SilcBufferStruct buf;
- SilcStackFrame frame;
-
-#ifdef SILC_DEBUG
- char sp[SILC_ASN1_RECURSION_DEPTH + 1];
- memset(sp, 0, sizeof(sp));
- if (depth)
- memset(sp, 32, depth);
-#endif /* SILC_DEBUG */
-
- if (depth >= SILC_ASN1_RECURSION_DEPTH) {
- SILC_LOG_DEBUG(("Maximum recursion depth reached"));
- return FALSE;
- }
-
- while (1) {
- /* These options cannot be used in encoding */
- opts &= ~SILC_ASN1_OPTIONAL;
-
- /* Get length encoding */
- indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
-
- /* By default UNIVERSAL is implied unless the following conditions
- are met when CONTEXT will apply. For SILC_ASN1_TAG_ANY_PRIMITIVE
- the class is changed only if flags dictate it. */
- if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
- if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
- if (opts & SILC_ASN1_IMPLICIT ||
- opts & SILC_ASN1_EXPLICIT)
- ber_class = SILC_BER_CLASS_CONTEXT;
- } else {
- if (tag != type ||
- opts & SILC_ASN1_IMPLICIT ||
- opts & SILC_ASN1_EXPLICIT)
- ber_class = SILC_BER_CLASS_CONTEXT;
- }
- }
-
-#ifdef SILC_DEBUG
- SILC_LOG_DEBUG(
- ("%04d: %sEncode %s [%d] %s %s %s %s", depth, sp[0] ? sp : "",
- silc_asn1_tag_name(type), tag,
- ber_class == SILC_BER_CLASS_UNIVERSAL ? "univ" :
- ber_class == SILC_BER_CLASS_APPLICATION ? "appl" :
- ber_class == SILC_BER_CLASS_CONTEXT ? "cont" : "priv",
- (type != SILC_ASN1_TAG_SEQUENCE && type != SILC_ASN1_TAG_SET) ?
- opts & SILC_ASN1_EXPLICIT ? "constr" :
- type == SILC_ASN1_TAG_ANY &&
- !(opts & SILC_ASN1_EXPLICIT) ? "constr" : "primit" : "constr",
- indef ? opts & SILC_ASN1_EXPLICIT ? "defin" : "indef" : "defin",
- opts & SILC_ASN1_IMPLICIT ? "implicit" :
- opts & SILC_ASN1_EXPLICIT ? "explicit" : ""));
-#endif /* SILC_DEBUG */
-
- /* If tagging is explicit we add constructed type before the underlaying
- types. The underlaying types are encoded recursively with this
- encoder. */
- if (opts & SILC_ASN1_EXPLICIT) {
- memset(&buf, 0, sizeof(buf));
-
- primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
- type != SILC_ASN1_TAG_SET);
- opts &= ~SILC_ASN1_EXPLICIT;
-
- silc_stack_push(stack2, &frame);
- ret = silc_asn1_encoder(asn1, stack2, stack1, type, type,
- SILC_BER_CLASS_UNIVERSAL, opts,
- &buf, depth + 1, primitive);
-
- if (!ret) {
- SILC_LOG_DEBUG(("Error encoding explicit tag"));
- silc_stack_pop(stack2);
- goto fail;
- }
-
- /* Encode the explicit tag */
- len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
- tag, buf.data, silc_buffer_len(&buf), FALSE);
- SILC_ASN1_BUFFER_FREE(&buf, stack2);
- silc_stack_pop(stack2);
- if (!ret)
- goto fail;
- if (primitive) {
- primitive = FALSE;
- goto cont;
- }
- goto ok;
- }
-
- /* Encode by the type */
- switch (type) {
-
- case SILC_ASN1_TAG_ANY:
- {
- /* ANY is another ASN.1 node which is added to this tree */
- SilcBuffer node = va_arg(asn1->ap, SilcBuffer);
- if (!node)
- break;
-
- /* Encode ASN.1 node into the tree. */
- if (opts & SILC_ASN1_IMPLICIT || type != tag) {
- /* We are tagging implicitly so we need to change the identifier
- of the underlaying type. Only constructed type is allowed with
- ANY when tagging implicitly. */
- const unsigned char *d;
- SilcUInt32 d_len;
- SilcBerEncoding enc;
-
- /* Get the underlaying data */
- ret = silc_ber_decode(node, NULL, &enc, NULL, &d, &d_len,
- NULL, NULL);
- if (!ret) {
- SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
- goto fail;
- }
- assert(enc == SILC_BER_ENC_CONSTRUCTED);
-
- /* Now encode with implicit tagging */
- len = silc_ber_encoded_len(tag, d_len, FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
- tag, d, d_len, FALSE);
- if (!ret)
- goto fail;
- } else {
- /* Copy the data directly into the tree. */
- len = silc_buffer_len(node);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- if (!dest)
- goto fail;
- silc_buffer_put(dest, node->data, len);
- }
- break;
- }
-
- case SILC_ASN1_TAG_ANY_PRIMITIVE:
- {
- /* ANY_PRIMITIVE is any primitive in encoded format. */
- SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
- if (!prim)
- break;
-
- /* Encode the primitive data */
- len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, prim->data, silc_buffer_len(prim), FALSE);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_SEQUENCE:
- case SILC_ASN1_TAG_SET:
- {
- /* SEQUENCE/SET is a sequence of types. Sequences are opened and
- encoded recursively by calling this same encoder. */
- memset(&buf, 0, sizeof(buf));
-
- /* Get type, tag and options for the first argument in recursion */
- SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
-
- silc_stack_push(stack2, &frame);
- ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
- ropts, &buf, depth + 1, FALSE);
- if (!ret) {
- SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
- silc_stack_pop(stack2);
- goto fail;
- }
-
- /* Encode the sequence */
- len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
- tag, buf.data, silc_buffer_len(&buf), indef);
- SILC_ASN1_BUFFER_FREE(&buf, stack2);
- silc_stack_pop(stack2);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_INTEGER:
- case SILC_ASN1_TAG_ENUM:
- {
- /* Integer */
- SilcMPInt *mpint = va_arg(asn1->ap, SilcMPInt *);
- if (!mpint)
- break;
-
- memset(&buf, 0, sizeof(buf));
- if (silc_mp_cmp_ui(mpint, 0) < 0) {
- /* XXX TODO, negative integer. Take 2s complement, then store
- bytes in 1s complement */
- } else {
- /* Positive */
- len = silc_mp_sizeinbase(mpint, 2);
- if (!(len & 7))
- len = ((len + 7) / 8) + 1;
- else
- len = (len + 7) / 8;
- silc_stack_push(stack2, &frame);
- silc_buffer_srealloc_size(stack2, &buf,
- silc_buffer_truelen(&buf) + len);
- buf.data[0] = 0x00;
- silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
- }
-
- /* Encode the integer */
- len = silc_ber_encoded_len(tag, len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, buf.data, silc_buffer_len(&buf), FALSE);
- SILC_ASN1_BUFFER_FREE(&buf, stack2);
- silc_stack_pop(stack2);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_SHORT_INTEGER:
- {
- /* Short Integer */
- SilcUInt32 sint = va_arg(asn1->ap, SilcUInt32);
- SilcMPInt z;
-
- if (tag == SILC_ASN1_TAG_SHORT_INTEGER)
- tag = SILC_ASN1_TAG_INTEGER;
-
- memset(&buf, 0, sizeof(buf));
-
- silc_stack_push(stack2, &frame);
- silc_mp_sinit(stack2, &z);
- silc_mp_set_ui(&z, sint);
-
- len = silc_mp_sizeinbase(&z, 2);
- if (!(len & 7))
- len = ((len + 7) / 8) + 1;
- else
- len = (len + 7) / 8;
- silc_buffer_srealloc_size(stack2, &buf,
- silc_buffer_truelen(&buf) + len);
- buf.data[0] = 0x00;
- silc_mp_mp2bin_noalloc(&z, buf.data, silc_buffer_len(&buf));
- silc_mp_uninit(&z);
-
- /* Encode the integer */
- len = silc_ber_encoded_len(tag, len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, buf.data, silc_buffer_len(&buf), FALSE);
- SILC_ASN1_BUFFER_FREE(&buf, stack2);
- silc_stack_pop(stack2);
- if (!ret)
- goto fail;
- break;
- }
- break;
-
- case SILC_ASN1_TAG_OID:
- {
- /* Object identifier */
- char *cp, *oidstr = va_arg(asn1->ap, char *);
- SilcUInt32 words[24], oid, mask;
- int i, k, c = 0;
- if (!oidstr)
- break;
-
- /* Get OID words from the string */
- cp = strchr(oidstr, '.');
- while (cp) {
- if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
- SILC_LOG_DEBUG(("Malformed OID string"));
- goto fail;
- }
- if (c + 1 > sizeof(words) / sizeof(words[0]))
- goto fail;
- words[c++] = oid;
- oidstr = cp + 1;
- cp = strchr(oidstr, '.');
-
- if (!cp) {
- if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
- SILC_LOG_DEBUG(("Malformed OID string"));
- goto fail;
- }
- if (c + 1 > sizeof(words) / sizeof(words[0]))
- goto fail;
- words[c++] = oid;
- break;
- }
- }
- if (c < 2) {
- SILC_LOG_DEBUG(("Malfromed OID string"));
- goto fail;
- }
-
- /* Get OID data length */
- for (i = 2, len = 1; i < c; i++) {
- if (words[i]) {
- for (oid = words[i]; oid; oid >>= 7)
- len++;
- continue;
- }
- len++;
- }
-
- /* Encode the OID */
- memset(&buf, 0, sizeof(buf));
- silc_stack_push(stack2, &frame);
- silc_buffer_srealloc_size(stack2, &buf,
- silc_buffer_truelen(&buf) + len);
- buf.data[0] = words[0] * 40 + words[1];
- for (i = 2, len = 1; i < c; i++) {
- oid = words[i];
- if (oid) {
- k = len;
- mask = 0;
- while (oid) {
- buf.data[len++] = (oid & 0x7f) | mask;
- oid >>= 7;
- mask |= 0x80;
- }
- mask = len - 1;
- while (k < mask) {
- oid = buf.data[k];
- buf.data[k] = buf.data[mask];
- buf.data[mask] = oid;
- k++;
- mask--;
- }
-
- continue;
- }
- buf.data[len++] = 0x00;
- }
-
- len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, buf.data, silc_buffer_len(&buf), FALSE);
- SILC_ASN1_BUFFER_FREE(&buf, stack2);
- silc_stack_pop(stack2);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_BOOLEAN:
- {
- /* Encodes boolean (TRUE/FALSE) value */
- unsigned char val[1];
- val[0] = (va_arg(asn1->ap, SilcUInt32) ? 0xff : 0x00);
-
- assert(indef == FALSE);
- len = silc_ber_encoded_len(tag, 1, FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, val, 1, FALSE);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_BIT_STRING:
- {
- /* Encode the data as is, with the bit padding. d_len is in bits. */
- unsigned char *d = va_arg(asn1->ap, unsigned char *);
- SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
- unsigned char pad[1];
- if (!d)
- break;
-
- pad[0] = (8 - (d_len & 7)) & 7;
- d_len = ((d_len + 7) / 8) + 1;
-
- memset(&buf, 0, sizeof(buf));
- silc_stack_push(stack2, &frame);
- silc_buffer_srealloc_size(stack2, &buf,
- silc_buffer_truelen(&buf) + d_len);
- silc_buffer_put(&buf, pad, 1);
- silc_buffer_pull(&buf, 1);
- silc_buffer_put(&buf, d, d_len - 1);
- silc_buffer_push(&buf, 1);
-
- len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, buf.data, silc_buffer_len(&buf), indef);
- SILC_ASN1_BUFFER_FREE(&buf, stack2);
- silc_stack_pop(stack2);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_NULL:
- {
- /* Encode empty BER block */
- assert(indef == FALSE);
- len = silc_ber_encoded_len(tag, 0, FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, NULL, 0, FALSE);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_UTC_TIME:
- {
- /* Universal encoded time string */
- SilcTime timeval = va_arg(asn1->ap, SilcTime);
- char timestr[32];
- if (!timeval)
- break;
-
- if (!silc_time_universal_string(timeval, timestr, sizeof(timestr))) {
- SILC_LOG_DEBUG(("Could not encode universal time string"));
- goto fail;
- }
-
- len = silc_ber_encoded_len(tag, strlen(timestr), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, timestr, strlen(timestr), indef);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_GENERALIZED_TIME:
- {
- /* Generalized encoded time string */
- SilcTime timeval = va_arg(asn1->ap, SilcTime);
- char timestr[32];
- if (!timeval)
- break;
-
- if (!silc_time_generalized_string(timeval, timestr, sizeof(timestr))) {
- SILC_LOG_DEBUG(("Could not encode generalized time string"));
- goto fail;
- }
-
- len = silc_ber_encoded_len(tag, strlen(timestr), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, timestr, strlen(timestr), indef);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_UTF8_STRING:
- {
- /* UTF-8 string */
- unsigned char *d = va_arg(asn1->ap, unsigned char *);
- SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
- if (!d)
- break;
-
- /* By default all strings that get here should already be UTF-8 */
- if (!silc_utf8_valid(d, d_len)) {
- SILC_LOG_DEBUG(("Malformed UTF-8 string"));
- goto fail;
- }
-
- len = silc_ber_encoded_len(tag, d_len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, d, d_len, indef);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_OCTET_STRING:
- {
- /* Octet string. Put data as is. */
- unsigned char *d = va_arg(asn1->ap, unsigned char *);
- SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
-
- len = silc_ber_encoded_len(tag, d_len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
- silc_buffer_truelen(dest) + len);
- ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
- tag, d, d_len, indef);
- if (!ret)
- goto fail;
- break;
- }
-
- case SILC_ASN1_TAG_NUMERIC_STRING:
- {
- /* Numerical (digit) string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_NUMERICAL);
- break;
- }
-
- case SILC_ASN1_TAG_PRINTABLE_STRING:
- {
- /* Printable string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_PRINTABLE);
- break;
- }
-
- case SILC_ASN1_TAG_TELETEX_STRING:
- {
- /* Teletex (T61) string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_TELETEX);
- break;
- }
-
- case SILC_ASN1_TAG_IA5_STRING:
- {
- /* US ASCII string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
- break;
- }
-
- case SILC_ASN1_TAG_VISIBLE_STRING:
- {
- /* Visible string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_VISIBLE);
- break;
- }
-
- case SILC_ASN1_TAG_UNIVERSAL_STRING:
- {
- /* Universal (UCS-4) string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
- break;
- }
-
- case SILC_ASN1_TAG_UNRESTRICTED_STRING:
- case SILC_ASN1_TAG_GENERAL_STRING:
- {
- /* Handle now unrestricted and general as 8-bit ascii, which
- probably isn't correct. */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
- break;
- }
-
- case SILC_ASN1_TAG_BMP_STRING:
- {
- /* BMP (UCS-2) string */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
- break;
- }
-
- case SILC_ASN1_TAG_ODE:
- case SILC_ASN1_TAG_ETI:
- case SILC_ASN1_TAG_REAL:
- case SILC_ASN1_TAG_EMBEDDED:
- case SILC_ASN1_TAG_ROI:
- case SILC_ASN1_TAG_VIDEOTEX_STRING:
- case SILC_ASN1_TAG_GRAPHIC_STRING:
- {
- SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
- ret = FALSE;
- goto fail;
- break;
- }
-
- default:
- SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot encode ASN.1.", type));
- ret = FALSE;
- goto fail;
- break;
- }
-
- cont:
- if (len)
- silc_buffer_pull(dest, len);
- if (primitive) {
- ret = TRUE;
- goto ok;
- }
-
- /* Get next type, tag and options */
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- if (type == SILC_ASN1_END) {
- ret = TRUE;
- goto ok;
- }
- }
-
- fail:
- SILC_LOG_DEBUG(("Error encoding type %d (depth %d)", type, depth));
-
- ok:
- if (ptr)
- len = dest->data - ptr;
- else
- len = dest->data - dest->head;
- silc_buffer_push(dest, len);
-
- return ret;
-}
-
-SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
-{
- SilcAsn1Tag type, tag;
- SilcAsn1Options opts;
- SilcBerClass ber_class;
- SilcStackFrame frame1, frame2;
- SilcStack stack1 = NULL;
- SilcBool ret;
-
- if (!asn1)
- return FALSE;
-
- va_start(asn1->ap, dest);
-
- /* Get the first arguments and call the encoder. */
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- if (!type) {
- va_end(asn1->ap);
- return FALSE;
- }
-
- /* Handle internal options for encoder. */
- if (type == SILC_ASN1_TAG_OPTS) {
- SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
-
- if (o & SILC_ASN1_ALLOC) {
- /* User wants to alloate everything. Set the stack to NULL so
- that stack aware calls revert to normal allocation routines. */
- stack1 = asn1->stack1;
- asn1->stack1 = NULL;
- }
-
- if (o & SILC_ASN1_ACCUMUL) {
- /* If accumul flag is not set yet, then push the stack. */
- if (!asn1->accumul) {
- silc_stack_push(asn1->stack1, NULL);
- asn1->accumul = 1;
- }
- }
-
- /* Take again the arguments */
- SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
- } else {
- /* No flags set, all flags will be reset. */
-
- /* If accumul flag is set now pop the stack so that all accumulated
- memory becomes free again. */
- if (asn1->accumul) {
- silc_stack_pop(asn1->stack1);
- asn1->accumul = 0;
- }
- }
-
- /* Push the stack for normal allocation from stack. */
- if (!asn1->accumul)
- silc_stack_push(asn1->stack1, &frame1);
-
- /* Start encoding */
- silc_stack_push(asn1->stack2, &frame2);
- ret = silc_asn1_encoder(asn1, asn1->stack1, asn1->stack2,
- type, tag, ber_class, opts, dest, 0, FALSE);
- silc_stack_pop(asn1->stack2);
-
- /* Pop the stack to free normal allocations from stack. */
- if (!asn1->accumul)
- silc_stack_pop(asn1->stack1);
-
- /* If SILC_ASN1_ALLOC flag was set, restore the stack. */
- if (stack1 && !asn1->stack1)
- asn1->stack1 = stack1;
-
- va_end(asn1->ap);
-
- return ret;
-}
+++ /dev/null
-/*
-
- silcasn1_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2006 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 SILCASN1_I_H
-#define SILCASN1_I_H
-
-#ifndef SILCASN1_H
-#error "Do not include this header directly"
-#endif
-
-/* ASN.1 context */
-struct SilcAsn1Object {
- va_list ap; /* List of ASN.1 types given as argument */
- SilcStack stack1; /* Stack for encoder */
- SilcStack stack2; /* Internal stack for encoding/decoding */
- unsigned int accumul : 1; /* Accumulate memory from stack for result */
-};
-
-/* The maximum depth for recursion in encoder and decoder. */
-#define SILC_ASN1_RECURSION_DEPTH 512
-
-/* Implementation specific special tags. Range is 0x7000 - 0x7fff. */
-#define SILC_ASN1_TAG_ANY 0x7000 /* SILC_ASN1_ANY given */
-#define SILC_ASN1_TAG_FUNC 0x7001 /* Callback encoder/decoder */
-#define SILC_ASN1_TAG_OPTS 0x7002 /* SILC_ASN1_OPTS given */
-#define SILC_ASN1_TAG_CHOICE 0x7003 /* SILC_ASN1_CHOICE given */
-#define SILC_ASN1_TAG_SEQUENCE_OF 0x7004 /* SILC_ASN1_SEQUENCE_OF given */
-#define SILC_ASN1_TAG_ANY_PRIMITIVE 0x7005 /* Pre-encoded primitive data */
-#define SILC_ASN1_TAG_SHORT_INTEGER 0x7006 /* Short integer */
-
-/* Helper macros for adding the arguments to encoder and decoder. */
-
-/* The arguments to silc_asn1_encode and silc_asn1_decode are constructed
- as follows:
-
- The first argument for type is a 32 bit integer where first 15-bits are
- reserved for the type. If the bit 16 is set then type and tag are same
- and next argument is NOT the tag number. If bit 16 is not set then
- next argument is a 32 bit tag number. This then also means that the type
- is either implicitly or explicitly tagged. The second 16-bits of the
- first 32-bits argument is reserved for options.
-
- Any argument that follow the type and optional tag number argument are
- type specific arguments.
-
- The SILC_ASN1_Ux macros set the bit 16, since the type and tag are same,
- and also options are set to zero (0).
-
- The SILC_ASN1_Tx macros does not set bit 16, but separate tag argument is
- provided. Options may or may not be zero, and they are put at the high
- 16-bits part of the first 32-bit argument.
-*/
-
-#define SILC_ASN1_U0(type) \
- SILC_ASN1_TAG_ ## type | 0x8000
-#define SILC_ASN1_U1(type, x) \
- SILC_ASN1_TAG_ ## type | 0x8000, (x)
-#define SILC_ASN1_U2(type, x, xl) \
- SILC_ASN1_TAG_ ## type | 0x8000, (x), (xl)
-
-#define SILC_ASN1_T0(type, o, t) \
- SILC_ASN1_TAG_ ## type | (o) << 16, (t)
-#define SILC_ASN1_T1(type, o, t, x) \
- SILC_ASN1_TAG_ ## type | (o) << 16, (t), (x)
-#define SILC_ASN1_T2(type, o, t, x, xl) \
- SILC_ASN1_TAG_ ## type | (o) << 16, (t), (x), (xl)
-
-/* Macro to retreive type, options and tag. The ret_type will include
- the actual type, ret_class the BER class from options, ret_opts the
- options (without the class), and ret_tag the tag. */
-#define SILC_ASN1_ARGS(asn1, ret_type, ret_tag, ret_class, ret_opts) \
- ret_type = va_arg(asn1->ap, SilcUInt32); \
- ret_tag = ret_class = ret_opts = 0; \
- if (ret_type != SILC_ASN1_END && \
- ret_type != SILC_ASN1_TAG_OPTS) { \
- if (ret_type & 0x8000) \
- ret_tag = (ret_type & 0xffff) & ~0x8000; \
- else \
- ret_tag = va_arg(asn1->ap, SilcUInt32); \
- ret_class = ret_type >> 16 & 0xf; \
- ret_opts = ret_type >> 16 & ~0xf; \
- if (ret_class) \
- ret_class--; \
- ret_type = (ret_type & 0xffff) & ~0x8000; \
- }
-
-/* Internal functions */
-
-#if defined(SILC_DEBUG)
-/* Returns string representation of a tag */
-const char *silc_asn1_tag_name(SilcAsn1Tag tag);
-#endif /* SILC_DEBUG */
-
-#ifdef SILC_DIST_INPLACE
-/* Dumps the ASN.1 data block into standard output (stdout). */
-SilcBool silc_asn1_dump(SilcAsn1 asn1, SilcBuffer src);
-#endif /* SILC_DIST_INPLACE */
-
-#endif /* SILCASN1_I_H */
+++ /dev/null
-/*
-
- silcber.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- 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
- 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.
-
-*/
-/* Basic Encoding Rules (BER) encoder and decoder. */
-
-#include "silc.h"
-#include "silcber.h"
-
-/* Encodes a BER data block into the `ber', which must already have
- sufficient space allocated. Caller can use silc_ber_encoded_len
- function to determine how much to allocate space before calling this
- function. If the `indefinite' is TRUE then the BER block will not
- include the length of the data in the BER block. */
-
-SilcBool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
- SilcBerEncoding encoding, SilcUInt32 tag,
- const unsigned char *data, SilcUInt32 data_len,
- SilcBool indefinite)
-{
- int i = 0, c;
- SilcUInt32 tmp;
-
- if (!ber)
- return FALSE;
-
- /* Check that buffer is of correct size */
- if (silc_buffer_len(ber) < silc_ber_encoded_len(tag, data_len, indefinite))
- return FALSE;
-
- /* Put the class and encoding */
- ber->data[i] = (ber_class << 6) | (encoding << 5);
-
- /* Put the tag */
- if (tag < 0x1f) {
- /* Short tag */
- ber->data[i++] |= tag;
- } else {
- /* Long tag */
- ber->data[i++] |= 0x1f;
-
- /* Save the tag in multiple octets where 7-bits in the octet is the tag
- value and bit 8 is set, except for the last octet. */
- tmp = tag;
- c = 0;
- while (tmp) {
- c++;
- tmp >>= 7;
- }
- while (c > 1)
- ber->data[i++] = 0x80 | ((tag >> (--c * 7)) & 0x7f);
- ber->data[i++] = tag & 0x7f;
- }
-
- /* Put the length of data */
- if (!indefinite) {
- if (data_len < 0x80) {
- /* Use short form for less than 128 bytes */
- ber->data[i++] = data_len;
- } else {
- /* Long form */
-
- /* Calculate the number of octets for the length field */
- tmp = data_len;
- c = 0;
- while (tmp) {
- c++;
- tmp >>= 8;
- }
- ber->data[i++] = 0x80 | c;
-
- /* Put the actual length field octets, 8-bits per octet. */
- while (c > 1)
- ber->data[i++] = (data_len >> (--c * 8)) & 0xff;
- ber->data[i++] = data_len & 0xff;
- }
- } else {
- /* In indefinite form the length of data is not present in the BER */
- ber->data[i++] = 0x80;
- }
-
- /* Put the data */
- if (data)
- memcpy(&ber->data[i], data, data_len);
-
- /* Put end-of-content octets if length is indefinite */
- if (indefinite)
- ber->data[i + data_len] = ber->data[i + data_len + 1] = 0x00;
-
- return TRUE;
-}
-
-/* Decodesa a BER data from the buffer `ber'. Returns the class,
- encoding and the tag number for the BER data into `ber_class',
- `encoding' and `tag'. A pointer to the start of the data area is
- returned into `data'. If the length of the data is available from
- the BER data the length is returned into `data_len'. If the
- `indefinite' is TRUE then the length found in `data_len' was found
- by finding end-of-contents octets from the data. The
- `identifier_len' is the length of the BER header, and the length
- of the entire BER object is `identifier_len' + `data_len'. */
-
-SilcBool silc_ber_decode(SilcBuffer ber, SilcBerClass *ber_class,
- SilcBerEncoding *encoding, SilcUInt32 *tag,
- const unsigned char **data, SilcUInt32 *data_len,
- SilcBool *indefinite, SilcUInt32 *identifier_len)
-{
- int i = 0, c;
- SilcUInt32 t;
-
- if (!ber || silc_buffer_len(ber) == 0) {
- SILC_LOG_DEBUG(("Invalid data buffer"));
- return FALSE;
- }
-
- /* Get class */
- if (ber_class)
- *ber_class = (ber->data[0] >> 6) & 0x03;
-
- /* Get encoding */
- if (encoding)
- *encoding = (ber->data[0] >> 5) & 0x01;
-
- /* Get the tag. Assume short tag, the most common case */
- t = ber->data[i++] & 0x1f;
-
- /* If the tag is over 31 then take it from next octets */
- if (t >= 0x1f) {
- if (i >= silc_buffer_len(ber)) {
- SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
- return FALSE;
- }
-
- /* The tag is in next octets in 7-bits parts, parse them out. All
- octets except the last one has bit 8 set. */
- t = 0;
- while (ber->data[i] & 0x80) {
- t <<= 7;
- t |= ber->data[i++] & 0x7f;
-
- if (i >= silc_buffer_len(ber)) {
- SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
- return FALSE;
- }
- }
-
- /* Last 7-bits part */
- t <<= 7;
- t |= ber->data[i++] & 0x7f;
- }
- if (tag)
- *tag = t;
-
- if (i >= silc_buffer_len(ber)) {
- SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
- return FALSE;
- }
-
- /* Get the data length and the actual data */
- if (data && data_len) {
- /* Assume short format for length */
- *data_len = ber->data[i++];
- if (indefinite)
- *indefinite = FALSE;
-
- /* The bit 8 is set if the length is in long format */
- if (*data_len & 0x80) {
- /* If the format is definite then this octet includes the number
- of length octets. If indefinite it is zero and data is ended
- with end-of-contents octets (two zero bytes). */
- c = *data_len & 0x7f;
- if (c) {
- if (i >= silc_buffer_len(ber)) {
- SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
- return FALSE;
- }
-
- /* Get the length from c many octects (8-bits per octet) */
- *data_len = 0;
- while (c > 0) {
- *data_len <<= 8;
- *data_len |= ber->data[i++] & 0xff;
-
- if (i >= silc_buffer_len(ber)) {
- SILC_LOG_DEBUG(("Malformed BER: Length is too long"));
- return FALSE;
- }
- c--;
- }
- } else {
- /* It is indefinite and we attempt to find out the length by
- finding the end-of-contents octets. */
- if (indefinite)
- *indefinite = TRUE;
- c = i;
- while (c + 1 < silc_buffer_len(ber)) {
- if (ber->data[c] == 0x00 && ber->data[c + 1] == 0x00)
- break;
- c += 2;
- }
- if (c >= silc_buffer_len(ber)) {
- SILC_LOG_DEBUG(("Malformed BER: could not find end-of-content"));
- return FALSE;
- }
- *data_len = c - i;
- }
- }
-
- if (*data_len > silc_buffer_len(ber) - i) {
- SILC_LOG_DEBUG(("Malformed BER: Length is too long"));
- return FALSE;
- }
-
- /* Pointer to data area */
- *data = (const unsigned char *)ber->data + i;
- }
-
- if (identifier_len)
- *identifier_len = i;
-
- return TRUE;
-}
-
-/* Calculates the length of the encoded BER data object. This utility
- function can be used to calculate how much to allocate space before
- encoding with silc_ber_encode. */
-
-SilcUInt32 silc_ber_encoded_len(SilcUInt32 tag, SilcUInt32 data_len,
- SilcBool indefinite)
-{
- SilcUInt32 len, tmp;
-
- len = 1;
- if (tag >= 0x1f) {
- while (tag) {
- len++;
- tag >>= 7;
- }
- }
-
- len++;
- if (!indefinite) {
- if (data_len >= 0x80) {
- tmp = data_len;
- while (tmp) {
- len++;
- tmp >>= 8;
- }
- }
- } else {
- len += 2;
- }
-
- return len + data_len;
-}
+++ /dev/null
-/*
-
- silcber.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2006 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* silcasn1/BER Interface
- *
- * DESCRIPTION
- *
- * The Basic Encoding Rules (BER) is the data encoding format for the
- * ASN.1. This interface provides routines for encoding and decoding
- * arbitraty BER data blocks. Naturally, this interface can be used
- * to encode and decode DER blocks as well. These routines does not
- * allocate any memory and have been optimized for general ASN.1 usage.
- *
- * References: ITU-T X.690
- * http://www.itu.int/ITU-T/studygroups/com17/languages/X690_0702.pdf
- *
- ***/
-
-#ifndef SILCBER_H
-#define SILCBER_H
-
-/****d* silcasn1/SilcBerAPI/SilcBerClass
- *
- * NAME
- *
- * typedef enum { ... } SilcBerClass;
- *
- * DESCRIPTION
- *
- * Defines the BER classes.
- *
- */
-typedef enum {
- SILC_BER_CLASS_UNIVERSAL = 0x00, /* Universal */
- SILC_BER_CLASS_APPLICATION = 0x01, /* Application */
- SILC_BER_CLASS_CONTEXT = 0x02, /* Context-specific */
- SILC_BER_CLASS_PRIVATE = 0x03, /* Private */
-} SilcBerClass;
-/***/
-
-/****d* silcasn1/SilcBerAPI/SilcBerEncoding
- *
- * NAME
- *
- * typedef enum { ... } SilcBerEncoding;
- *
- * DESCRIPTION
- *
- * Defines the BER encoding type.
- *
- */
-typedef enum {
- SILC_BER_ENC_PRIMITIVE = 0x00,
- SILC_BER_ENC_CONSTRUCTED = 0x01,
-} SilcBerEncoding;
-/***/
-
-/****f* silcasn1/SilcBerAPI/silc_ber_encode
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
- * SilcBerEncoding encoding, SilcUInt32 tag,
- * const unsigned char *data, SilcUInt32 data_len,
- * SilcBool indefinite);
- *
- * DESCRIPTION
- *
- * Encodes a BER data block into the `ber', which must already have
- * sufficient space allocated. Caller can use silc_ber_encoded_len
- * function to determine how much to allocate space before calling this
- * function. If the `indefinite' is TRUE then the BER block will not
- * include the length of the data in the BER block.
- *
- ***/
-SilcBool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
- SilcBerEncoding encoding, SilcUInt32 tag,
- const unsigned char *data, SilcUInt32 data_len,
- SilcBool indefinite);
-
-/****f* silcasn1/SilcBerAPI/silc_ber_decode
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_ber_decode(SilcBuffer ber, SilcBerClass *ber_class,
- * SilcBerEncoding *encoding, SilcUInt32 *tag,
- * const unsigned char **data, SilcUInt32 *data_len,
- * SilcBool *indefinite, SilcUInt32 *identifier_len);
- *
- * DESCRIPTION
- *
- * Decodesa a BER data from the buffer `ber'. Returns the class,
- * encoding and the tag number for the BER data into `ber_class',
- * `encoding' and `tag'. A pointer to the start of the data area is
- * returned into `data'. If the length of the data is available from
- * the BER data the length is returned into `data_len'. If the
- * `indefinite' is TRUE then the length found in `data_len' was found
- * by finding end-of-contents octets from the BER data. The
- * `identifier_len' is the length of the BER header, and the length
- * of the entire BER object is `identifier_len' + `data_len'.
- *
- ***/
-SilcBool silc_ber_decode(SilcBuffer ber, SilcBerClass *ber_class,
- SilcBerEncoding *encoding, SilcUInt32 *tag,
- const unsigned char **data, SilcUInt32 *data_len,
- SilcBool *indefinite, SilcUInt32 *identifier_len);
-
-/****f* silcasn1/SilcBerAPI/silc_ber_encoded_len
- *
- * SYNOPSIS
- *
- * SilcUInt32 silc_ber_encoded_len(SilcUInt32 tag, SilcUInt32 data_len,
- * SilcBool indefinite);
- *
- * DESCRIPTION
- *
- * Calculates the length of the encoded BER data object. This utility
- * function can be used to calculate how much to allocate space before
- * encoding with silc_ber_encode.
- *
- ***/
-SilcUInt32 silc_ber_encoded_len(SilcUInt32 tag, SilcUInt32 data_len,
- SilcBool indefinite);
-
-#endif /* SILCBER_H */
+++ /dev/null
-#
-# Makefile.am
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2003 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_silcasn1
-
-test_silcasn1_SOURCES = test_silcasn1.c
-
-LIBS = $(SILC_COMMON_LIBS)
-LDADD = -L.. -L../.. -lsilc -lsilcasn1
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-#include "silc.h"
-
-/*
-silc_asn1_encode(asn1, node,
- SILC_ASN1_BOOLEAN(SilcBool),
- SILC_ASN1_END);
-silc_asn1_encode(asn1, dest,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_T(0, 33, node),
- SILC_ASN1_BOOLEAN_T(0, 4, boolv),
- SILC_ASN1_BOOLEAN(SilcBool),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END);
-
- FATAL ERROR: Adding primitive node with implicit tagging is not possible.
- The node either must be constructed (SEQUENCE or SET), or the tagging
- must be explicit (in which case end result is same).
-*/
-
-
-/*
-silc_asn1_encode(asn1, node,
- SILC_ASN1_BOOLEAN(SilcBool),
- SILC_ASN1_END);
-silc_asn1_encode(asn1, dest,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_T(SILC_ASN1_EXPLICIT, 33, node),
- SILC_ASN1_BOOLEAN_T(0, 4, boolv),
- SILC_ASN1_BOOLEAN(SilcBool),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END);
-
- CORRECT: the tagging is now explicit. Also note that tagging primitive
- node explicitly is analougous of having a constructed node and tagging
- that implicitly: the end result is same.
-
-*/
-
-
-int main(int argc, char **argv)
-{
- SilcBufferStruct node, node2;
- SilcAsn1 asn1;
- SilcBool success = FALSE;
- SilcBool val = TRUE;
- int i;
- unsigned char *str;
- SilcUInt32 str_len, tmpint;
- char tmp[32];
- SilcRng rng;
- SilcMPInt mpint, mpint2;
-
- memset(&node, 0, sizeof(node));
- memset(&node2, 0, sizeof(node2));
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*asn1*,*ber*");
- }
-
- silc_hash_register_default();
- rng = silc_rng_alloc();
- silc_rng_init(rng);
-
- SILC_LOG_DEBUG(("Allocating ASN.1 context"));
- asn1 = silc_asn1_alloc();
- if (!asn1)
- goto out;
-
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 1"));
- val = 1;
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9),
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT |
- SILC_ASN1_INDEFINITE, 0),
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 1"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9),
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT |
- SILC_ASN1_INDEFINITE, 0),
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
-
-#if 1
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 1"));
- val = 0;
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9),
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT |
- SILC_ASN1_INDEFINITE, 0),
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 1"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9),
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT |
- SILC_ASN1_INDEFINITE, 0),
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 2"));
- val = 1;
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9),
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_INDEFINITE, 0),
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 2"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9),
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_INDEFINITE, 0),
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 3"));
- val = 0;
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 3"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 4"));
- val = 1;
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE |
- SILC_ASN1_EXPLICIT, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 4"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE |
- SILC_ASN1_EXPLICIT, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 5"));
- success =
- silc_asn1_encode(asn1, &node2,
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END);
- SILC_LOG_DEBUG(("Encoding success"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY(&node2),
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- memset(&node2, 0, sizeof(node2));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 5"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY(&node2),
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- success =
- silc_asn1_decode(asn1, &node2,
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- memset(&node2, 0, sizeof(node2));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree (ANY_PRIMITIVE)"));
- memset(tmp, 0, sizeof(tmp));
- tmp[0] = 0xff;
- silc_buffer_set(&node2, tmp, 1);
- SILC_LOG_DEBUG(("Encoding success"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
- &node2),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- memset(&node2, 0, sizeof(node2));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree (ANY_PRIMITIVE)"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
- &node2),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Boolean val %d", node2.data[0]));
- if (node2.data[0] != 0xff) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree (ANY_PRIMITIVE)"));
- memset(tmp, 0, sizeof(tmp));
- tmp[0] = 0xff;
- silc_buffer_set(&node2, tmp, 1);
- SILC_LOG_DEBUG(("Encoding success"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
- &node2),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- memset(&node2, 0, sizeof(node2));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree (ANY_PRIMITIVE)"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree (ANY_PRIMITIVE)"));
- memset(tmp, 0, sizeof(tmp));
- tmp[0] = 0xff;
- silc_buffer_set(&node2, tmp, 1);
- SILC_LOG_DEBUG(("Encoding success"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- memset(&node2, 0, sizeof(node2));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree (ANY_PRIMITIVE)"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_BOOLEAN,
- &node2),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Boolean val %d", node2.data[0]));
- if (node2.data[0] != 0xff) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- memset(&node2, 0, sizeof(node2));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 6"));
- success =
- silc_asn1_encode(asn1, &node2,
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END);
- SILC_LOG_DEBUG(("Encoding success"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_T(SILC_ASN1_EXPLICIT, 33, &node2),
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- memset(&node2, 0, sizeof(node2));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 6"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_T(SILC_ASN1_EXPLICIT, 33, &node2),
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- success =
- silc_asn1_decode(asn1, &node2,
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- memset(&node2, 0, sizeof(node2));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 7"));
- val = 0;
- success =
- silc_asn1_encode(asn1, &node2,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END, SILC_ASN1_END);
- SILC_LOG_DEBUG(("Encoding success"));
- val = 1;
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_T(0, 11, &node2),
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- memset(&node2, 0, sizeof(node2));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 7"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_ANY_T(0, 11, &node2), /* NOTE: tag */
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- success =
- silc_asn1_decode(asn1, &node2,
- SILC_ASN1_SEQUENCE_T(0, 11), /* NOTE: using implicit
- tag! */
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- memset(&node2, 0, sizeof(node2));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 8"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_IMPLICIT, 9999, val),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 8"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 9999, &val),
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- memset(&node, 0, sizeof(node));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 9"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 4, val),
- SILC_ASN1_BOOLEAN(val),
- SILC_ASN1_END,
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 99, val),
- SILC_ASN1_BOOLEAN_T(0, 100, val),
- SILC_ASN1_END,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_NULL,
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 0, val),
- SILC_ASN1_OCTET_STRING("foobar", 6),
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE, 43, val),
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_APP |
- SILC_ASN1_EXPLICIT, 1, val),
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 9"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE_T(0, 9),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_BOOLEAN_T(0, 4, &val),
- SILC_ASN1_BOOLEAN(&val),
- SILC_ASN1_END,
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 99, &val),
- SILC_ASN1_BOOLEAN_T(0, 100, &val),
- SILC_ASN1_END,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_NULL,
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 0, &val),
- SILC_ASN1_OCTET_STRING(&str, &str_len),
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE, 43, &val),
- SILC_ASN1_BOOLEAN_T(SILC_ASN1_APP |
- SILC_ASN1_EXPLICIT, 1, &val),
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("Boolean val %d", val));
- SILC_LOG_DEBUG(("Ooctet-string %s, len %d", str, str_len));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 10 (INTEGER)"));
- str = silc_rng_get_rn_data(rng, 256);
- silc_mp_init(&mpint);
- silc_mp_init(&mpint2);
- silc_mp_bin2mp(str, 256, &mpint);
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_INT(&mpint),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 10 (INTEGER)"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_INT(&mpint2),
- SILC_ASN1_END);
- if (silc_mp_cmp(&mpint, &mpint2) != 0) {
- SILC_LOG_DEBUG(("INTEGER MISMATCH"));
- goto out;
- }
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 11 (OID)"));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
- SILC_ASN1_OID("1.2.840.113549"),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 11 (OID)"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
- SILC_ASN1_OID(&str),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Decoding success"));
- SILC_LOG_DEBUG(("OID %s", str));
- printf("\n");
-
-
- memset(&node, 0, sizeof(node));
- SILC_LOG_DEBUG(("Encoding ASN.1 tree 12 (SHORT INTEGER)"));
- str_len = 198761;
- tmpint = 0;
- SILC_LOG_DEBUG(("Short integer: %d", str_len));
- SILC_LOG_DEBUG(("Short integer: %d", tmpint));
- success =
- silc_asn1_encode(asn1, &node,
- SILC_ASN1_SHORT_INT(str_len),
- SILC_ASN1_SHORT_INT_T(SILC_ASN1_IMPLICIT, 100, tmpint),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Encoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Encoding success"));
- SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
- SILC_LOG_DEBUG(("Decoding ASN.1 tree 12 (SHORT INTEGER)"));
- success =
- silc_asn1_decode(asn1, &node,
- SILC_ASN1_SHORT_INT(&str_len),
- SILC_ASN1_SHORT_INT_T(SILC_ASN1_IMPLICIT, 100, &tmpint),
- SILC_ASN1_END);
- if (!success) {
- SILC_LOG_DEBUG(("Decoding failed"));
- goto out;
- }
- SILC_LOG_DEBUG(("Short integer: %d", str_len));
- SILC_LOG_DEBUG(("Short integer: %d", tmpint));
- SILC_LOG_DEBUG(("Decoding success"));
- printf("\n");
-
-#endif /* 1 */
- silc_asn1_free(asn1);
-
- success = TRUE;
- out:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
Name: @PACKAGE@ (client library)
Description: SILC Client Library
Version: @VERSION@
+Conflicts: libsilc <= 0.9.12
Requires: silc = @VERSION@
Libs: -L${libdir} -lsilcclient @LIBS@
Cflags: -I${includedir}
@LINK=notifyargs.html:Arguments for <b>notify</b> Client Operation
@LINK=silcclient_unicode.html:Unicode and UTF-8 Strings in Client Library
@LINK=silcclient.html:Client Library Interface Reference
-@LINK=silcclient_entry.html:Client Entry Interface Reference
-->
<big><b>SILC Client Library</b></big>
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2000 - 2007 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
noinst_LTLIBRARIES = libsilcclient.la
-libsilcclient_la_SOURCES = \
- client.c \
- client_entry.c \
- client_prvmsg.c \
- client_channel.c \
- client_connect.c \
- client_register.c \
- client_notify.c \
- client_attrs.c \
- client_keyagr.c \
- client_listener.c \
- client_ftp.c \
- command.c \
- command_reply.c
+libsilcclient_la_SOURCES = \
+ client.c \
+ client_keyagr.c \
+ client_notify.c \
+ client_prvmsg.c \
+ client_channel.c \
+ client_ftp.c \
+ client_resume.c \
+ client_attrs.c \
+ command.c \
+ command_reply.c \
+ idlist.c \
+ protocol.c
#ifdef SILC_DIST_TOOLKIT
-include_HEADERS= \
- client.h \
- silcclient.h \
- silcclient_entry.h
+include_HEADERS= \
+ client.h \
+ command.h \
+ command_reply.h \
+ idlist.h \
+ protocol.h \
+ silcclient.h
SILC_EXTRA_DIST = client_ops_example.c
#endif SILC_DIST_TOOLKIT
-EXTRA_DIST = *.h tests $(SILC_EXTRA_DIST)
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-During client library implementation, few things to keep in mind.
-
-Threads and locking in client library
-
- The client library is multithreaded in so that the actual SilcClient
- runs in one main thread (may be application main thread or its created
- thread for the client), and each connection to a remote host runs in
- an own thread. There are no other threads in client library. If there
- is only one connection in the client, then most likely there is only
- one thread in addition of main thread.
-
- The SilcClient context must be protected with lock (client->internal->lock),
- because it may be accessed from connection threads and by application.
- It is guaranteed that the client main thread never access the connection
- thread, and it is guaranteed that no other connection thread access
- another connection thread. Even still, the SilcClientConnection has
- a lock (conn->internal->lock) because it may be accessed by application.
-
- Practically everything in the client is executed in the connection thread.
- Receiving packets, commands, notifys, etc all happen in connection thread.
- It is not possible to receive packets in two different threads that would
- be destined to one specific connection thread. But, because packets and
- commands may be sent from application thread the connection lock is
- used to protect shared data in the SilcClientConnection. It is, however,
- guaranteed that the main client thread, or other connection thread will
- not send any packets or commands to another connection. When remembered
- this makes programming easier. Everything happens in one thread that
- has something to do with the connection. When packet is received and
- it is processed asynchronously, it is always guaranteed that it is
- processed in that same thread, even if it is processed asynchronously.
- No other thread will process it. If it is processed synchronously, no
- other packet may arrive at the same time, not for that connection.
- But it is possible that while we are processing incoming command reply,
- application sends another command from application thread. Because of
- this, the lock exist in the connection context.
-
-
-Using locks
-
- Use locking only if necessary. For performance reasons SILC Atomic
- Operations API should be preferred if it can be used to achieve what
- needs to be achieved. All reference counters must be atomic integers
- and locking must not be used with them.
-
-
-Using FSM
-
- The client library internals are to be rewritten with SILC FSM and all
- major operations should be implemented as FSM.
-
- Always return SILC_FSM_CONTINUE if you need to move to next state
- synchronously. Use SILC_FSM_YIELD if you are in FSM thread and
- peformance is not an issue, but only if there really are other FSM
- threads that need execution time also.
-
-
-When to use FSM event signalling?
-
- FSM event signalling should be used only when multiple threads
- (FSM threads) may be waiting for something to happen. If only one thread
- is waiting for something it should merely return SILC_FSM_WAIT and when
- that something happens it should use silc_fsm_continue or
- silc_fsm_continue_sync to continue in the waiting thread. OTOH, if
- multiple threads are waiting SILC_FSM_EVENT_SIGNAL is the only way to
- deliver the signal. Always remember that posting is signal is not
- donbe synchronously (it won't be delivered immediately).
-
- OTOH, if there is only one thread waiting for somtehing to happen but
- there can be multiple threads signalling that something has happened
- only way to do this is to use event signalling.
-
- Event signals should be pre-allocated SilcFSMEventStruct structures
- and for signalling use they are always initialized as:
-
- silc_fsm_event_init(&event, fsm);
-
- The call cannot fail. Events need not be uninitialized and the same
- context may be reused.
-
-Finishing threads when closing connection
-
- When closing SilcClientConnection all threads must first be finished
- before the connection machine is finished. This is done by finishing
- all running command threads. That will also finish all waiting packet
- and notify threads as they are always waiting for a command. If any
- thread is waiting for something else than a command (such as event
- threads) they must be explicitly finished. The threads are finished by
- continuing them synchronously. The threads will detect that we are
- disconnected (see below). SILC_FSM_YIELD must be returned in
- st_close() as that gives the FSM scheduler time to finish the threads
- first. After that the machine can be finished.
-
- Also, any thread that runs in SilcClientConnection machine must always
- after returning from wait state to check if we are disconnected by doing
-
- if (conn->internal->disconnected) {
- xxx;
- return SILC_FSM_FINISH;
- }
-
- If disconnected the thread must finish immediately by returning
- SILC_FSM_FINISH.
-
-Entry locking
-
- All entires have a read/write lock. It is used to protect the entries
- when library updates them at the same time application is reading data
- from the entries. An API for application to read-lock the entires
- exist. Library only needs to use write-lock. Using read-lock is not
- necessary inside library because all connection related stuff, including
- updating connection related entries are done in one thread. When library
- is reading data from the entries it cannot be updating them at the same
- time. Hence, using read-lock inside library is not necessary.
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
+/* Static task callback prototypes */
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
+SILC_TASK_CALLBACK(silc_client_rekey_final);
+
+static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
+ void *context);
+static void silc_client_packet_parse_type(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_resolve_auth_method(bool success,
+ SilcProtocolAuthMeth auth_meth,
+ const unsigned char *auth_data,
+ SilcUInt32 auth_data_len, void *context);
+/* Allocates new client object. This has to be done before client may
+ work. After calling this one must call silc_client_init to initialize
+ the client. The `application' is application specific user data pointer
+ and caller must free it. */
-/************************ Static utility functions **************************/
-
-/* Connection machine FSM destructor. This will finish the thread where
- the machine was running and deletes the connection context. */
-
-static void silc_client_connection_destructor(SilcFSM fsm,
- void *fsm_context,
- void *destructor_context)
+SilcClient silc_client_alloc(SilcClientOperations *ops,
+ SilcClientParams *params,
+ void *application,
+ const char *version_string)
{
- SilcClientConnection conn = fsm_context;
- SilcFSMThread thread = destructor_context;
+ SilcClient new_client;
- SILC_LOG_DEBUG(("Connection %p finished", conn));
+ new_client = silc_calloc(1, sizeof(*new_client));
+ new_client->application = application;
- /* Delete connection */
- silc_client_del_connection(conn->client, conn);
+ new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
+ new_client->internal->ops = ops;
+ new_client->internal->params =
+ silc_calloc(1, sizeof(*new_client->internal->params));
+ if (!version_string)
+ version_string = silc_version_string;
+ new_client->internal->silc_client_version = strdup(version_string);
- /* Finish the thread were this machine was running */
- silc_fsm_finish(thread);
-}
+ if (params)
+ memcpy(new_client->internal->params, params, sizeof(*params));
-/* Connection thread FSM destructor. This was the thread where the connection
- machine was running (may be real thread). From here we notify client
- that the connection thread has finished. */
+ if (!new_client->internal->params->task_max)
+ new_client->internal->params->task_max = 200;
-static void silc_client_connection_finished(SilcFSMThread fsm,
- void *fsm_context,
- void *destructor_context)
-{
- SilcClient client = silc_fsm_get_state_context(fsm);
+ if (!new_client->internal->params->rekey_secs)
+ new_client->internal->params->rekey_secs = 3600;
- /* Signal client that we have finished */
- silc_atomic_sub_int16(&client->internal->conns, 1);
- client->internal->connection_closed = TRUE;
- SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
+ if (!new_client->internal->params->connauth_request_secs)
+ new_client->internal->params->connauth_request_secs = 2;
- silc_fsm_free(fsm);
+ new_client->internal->params->
+ nickname_format[sizeof(new_client->internal->
+ params->nickname_format) - 1] = 0;
+
+ return new_client;
}
-/* Packet FSM thread destructor */
+/* Frees client object and its internals. */
-static void silc_client_packet_destructor(SilcFSMThread thread,
- void *thread_context,
- void *destructor_context)
+void silc_client_free(SilcClient client)
{
- SilcClientConnection conn = thread_context;
+ if (client) {
+ if (client->rng)
+ silc_rng_free(client->rng);
+
+ if (!client->internal->params->dont_register_crypto_library) {
+ silc_cipher_unregister_all();
+ silc_pkcs_unregister_all();
+ silc_hash_unregister_all();
+ silc_hmac_unregister_all();
+ }
- /* Add thread back to thread pool */
- silc_list_add(conn->internal->thread_pool, thread);
- if (silc_list_count(conn->internal->thread_pool) == 1)
- silc_list_start(conn->internal->thread_pool);
+ silc_hash_free(client->md5hash);
+ silc_hash_free(client->sha1hash);
+ silc_hmac_free(client->internal->md5hmac);
+ silc_hmac_free(client->internal->sha1hmac);
+ silc_cipher_free(client->internal->none_cipher);
+ silc_free(client->internal->params);
+ silc_free(client->internal->silc_client_version);
+ silc_free(client->internal);
+ silc_free(client);
+ }
}
-/* Packet engine callback to receive a packet */
+/* Initializes the client. This makes all the necessary steps to make
+ the client ready to be run. One must call silc_client_run to run the
+ client. Returns FALSE if error occured, TRUE otherwise. */
-static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context)
+bool silc_client_init(SilcClient client)
{
- SilcClientConnection conn = stream_context;
- SilcFSMThread thread;
+ SILC_LOG_DEBUG(("Initializing client"));
- /* 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_DONE:
- case SILC_PACKET_CONNECTION_AUTH:
+ assert(client);
+ assert(client->username);
+ assert(client->hostname);
+ assert(client->realname);
+
+ /* Validate essential strings */
+ if (client->nickname)
+ if (!silc_identifier_verify(client->nickname, strlen(client->nickname),
+ SILC_STRING_UTF8, 128)) {
+ SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname));
+ return FALSE;
+ }
+ if (!silc_identifier_verify(client->username, strlen(client->username),
+ SILC_STRING_UTF8, 128)) {
+ SILC_LOG_ERROR(("Malformed username '%s'", client->username));
+ return FALSE;
+ }
+ if (!silc_identifier_verify(client->hostname, strlen(client->hostname),
+ SILC_STRING_UTF8, 256)) {
+ SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname));
+ return FALSE;
+ }
+ if (!silc_utf8_valid(client->realname, strlen(client->realname))) {
+ SILC_LOG_ERROR(("Malformed realname '%s'", client->realname));
return FALSE;
- break;
}
- /* Get packet processing thread */
- thread = silc_list_get(conn->internal->thread_pool);
- if (!thread) {
- thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
- silc_client_packet_destructor, NULL, FALSE);
- if (!thread)
- return FALSE;
- } else {
- silc_list_del(conn->internal->thread_pool, thread);
- silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
- silc_client_packet_destructor, NULL, FALSE);
+ if (!client->internal->params->dont_register_crypto_library) {
+ /* Initialize the crypto library. If application has done this already
+ this has no effect. Also, we will not be overriding something
+ application might have registered earlier. */
+ silc_cipher_register_default();
+ silc_pkcs_register_default();
+ silc_hash_register_default();
+ silc_hmac_register_default();
}
- /* Process packet in thread */
- silc_fsm_set_state_context(thread, packet);
- silc_fsm_start_sync(thread, silc_client_connection_st_packet);
+ /* Initialize hash functions for client to use */
+ silc_hash_alloc("md5", &client->md5hash);
+ silc_hash_alloc("sha1", &client->sha1hash);
+
+ /* Initialize none cipher */
+ silc_cipher_alloc("none", &client->internal->none_cipher);
+
+ /* Initialize random number generator */
+ client->rng = silc_rng_alloc();
+ silc_rng_init(client->rng);
+ silc_rng_global_init(client->rng);
+
+ /* Register protocols */
+ silc_client_protocols_register();
+
+ /* Initialize the scheduler */
+ client->schedule =
+ silc_schedule_init(client->internal->params->task_max ?
+ client->internal->params->task_max : 200, client);
+ if (!client->schedule)
+ return FALSE;
+
+ /* Register commands */
+ silc_client_commands_register(client);
return TRUE;
}
-/* Packet engine callback to indicate end of stream */
+/* Stops the client. This is called to stop the client and thus to stop
+ the program. */
-static void silc_client_packet_eos(SilcPacketEngine engine,
- SilcPacketStream stream,
- void *callback_context,
- void *stream_context)
+void silc_client_stop(SilcClient client)
{
- SilcClientConnection conn = stream_context;
+ SILC_LOG_DEBUG(("Stopping client"));
- SILC_LOG_DEBUG(("Remote disconnected connection"));
+ silc_schedule_stop(client->schedule);
+ silc_schedule_uninit(client->schedule);
- /* Signal to close connection */
- conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
+ silc_client_protocols_unregister();
+ silc_client_commands_unregister(client);
+
+ SILC_LOG_DEBUG(("Client stopped"));
}
-/* Packet engine callback to indicate error */
+/* Runs the client. This starts the scheduler from the utility library.
+ When this functions returns the execution of the appliation is over. */
-static void silc_client_packet_error(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacketError error,
- void *callback_context,
- void *stream_context)
+void silc_client_run(SilcClient client)
{
- /* Nothing */
-}
+ SILC_LOG_DEBUG(("Running client"));
-/* Packet stream callbacks */
-static SilcPacketCallbacks silc_client_stream_cbs =
-{
- silc_client_packet_receive,
- silc_client_packet_eos,
- silc_client_packet_error
-};
+ assert(client);
+ assert(client->pkcs);
+ assert(client->public_key);
+ assert(client->private_key);
+
+ /* Start the scheduler, the heart of the SILC client. When this returns
+ the program will be terminated. */
+ silc_schedule(client->schedule);
+}
-/* FSM destructor */
+/* Runs the client and returns immeadiately. This function is used when
+ the SILC Client object indicated by the `client' is run under some
+ other scheduler, or event loop or main loop. On GUI applications,
+ for example this may be desired to use to run the client under the
+ GUI application's main loop. Typically the GUI application would
+ register an idle task that calls this function multiple times in
+ a second to quickly process the SILC specific data. */
-void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
+void silc_client_run_one(SilcClient client)
{
- silc_fsm_free(fsm);
+ /* Run the scheduler once. */
+ silc_schedule_one(client->schedule, 0);
}
-/* Connect abort operation */
+/* Allocates and adds new connection to the client. This adds the allocated
+ connection to the connection table and returns a pointer to it. A client
+ can have multiple connections to multiple servers. Every connection must
+ be added to the client using this function. User data `context' may
+ be sent as argument. This function is normally used only if the
+ application performed the connecting outside the library. The library
+ however may use this internally. */
-static void silc_client_connect_abort(SilcAsyncOperation op, void *context)
+SilcClientConnection
+silc_client_add_connection(SilcClient client,
+ SilcClientConnectionParams *params,
+ char *hostname, int port, void *context)
{
- SilcClientConnection conn = context;
-
- SILC_LOG_DEBUG(("Connection %p aborted by application", conn));
+ SilcClientConnection conn;
+ int i;
- /* Connection callback will not be called after user aborted connecting */
- conn->callback = NULL;
- conn->internal->cop = NULL;
+ SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
- /* Signal to close connection */
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
+ conn = silc_calloc(1, sizeof(*conn));
+ conn->internal = silc_calloc(1, sizeof(*conn->internal));
- /* If user aborts before connection machine is even up yet, then don't
- send signal yet. It will process this event when it comes up. */
- if (silc_fsm_is_started(&conn->internal->fsm))
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
+ /* Initialize ID caches */
+ conn->client = client;
+ conn->remote_host = strdup(hostname);
+ conn->remote_port = port;
+ conn->context = context;
+ conn->internal->client_cache =
+ silc_idcache_alloc(0, SILC_ID_CLIENT, NULL, NULL, FALSE, TRUE);
+ conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL,
+ NULL, FALSE, TRUE);
+ conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL,
+ NULL, FALSE, TRUE);
+ conn->internal->pending_commands = silc_dlist_init();
+ conn->internal->ftp_sessions = silc_dlist_init();
+
+ if (params) {
+ if (params->detach_data)
+ conn->internal->params.detach_data =
+ silc_memdup(params->detach_data,
+ params->detach_data_len);
+ conn->internal->params.detach_data_len = params->detach_data_len;
}
-}
-/************************** Connection's machine ****************************/
+ /* Add the connection to connections table */
+ for (i = 0; i < client->internal->conns_count; i++)
+ if (client->internal->conns && !client->internal->conns[i]) {
+ client->internal->conns[i] = conn;
+ return conn;
+ }
-/* Start the connection's state machine. If threads are in use the machine
- is always executed in a real thread. */
+ client->internal->conns =
+ silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
+ * (client->internal->conns_count + 1));
+ client->internal->conns[client->internal->conns_count] = conn;
+ client->internal->conns_count++;
-SILC_FSM_STATE(silc_client_connection_st_start)
-{
- SilcClientConnection conn = fsm_context;
- SilcFSM connfsm;
-
- /* Take scheduler for connection */
- conn->internal->schedule = silc_fsm_get_schedule(fsm);
-
- /*** Run connection machine */
- connfsm = &conn->internal->fsm;
- silc_fsm_init(connfsm, conn, silc_client_connection_destructor,
- fsm, conn->internal->schedule);
- silc_fsm_event_init(&conn->internal->wait_event, connfsm);
- silc_fsm_start_sync(connfsm, silc_client_connection_st_run);
-
- /* Schedule any events possibly set in initialization */
- if (conn->internal->disconnected)
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- if (conn->internal->connect)
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- if (conn->internal->key_exchange)
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
-
- /* Wait until this thread is terminated from the machine destructor */
- return SILC_FSM_WAIT;
+ return conn;
}
-/* Connection machine main state. This handles various connection related
- events, but not packet processing. It's done in dedicated packet
- processing FSM thread. */
+/* Removes connection from client. Frees all memory. */
-SILC_FSM_STATE(silc_client_connection_st_run)
+void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
{
- SilcClientConnection conn = fsm_context;
- SilcFSMThread thread;
+ int i;
+
+ for (i = 0; i < client->internal->conns_count; i++)
+ if (client->internal->conns[i] == conn) {
+ /* Free all cache entries */
+ SilcIDCacheList list;
+ SilcIDCacheEntry entry;
+ SilcClientCommandPending *r;
+ bool ret;
+
+ if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ silc_client_del_client(client, conn, entry->context);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+ }
- /* Wait for events */
- SILC_FSM_EVENT_WAIT(&conn->internal->wait_event);
+ if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ silc_client_del_channel(client, conn, entry->context);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+ }
- /* Process events */
- thread = &conn->internal->event_thread;
+ if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ silc_client_del_server(client, conn, entry->context);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+ }
- if (conn->internal->disconnected) {
- /** Event: disconnected */
- SILC_LOG_DEBUG(("Event: disconnected"));
- silc_fsm_next(fsm, silc_client_connection_st_close);
- return SILC_FSM_YIELD;
- }
+ /* Clear ID caches */
+ if (conn->internal->client_cache)
+ silc_idcache_free(conn->internal->client_cache);
+ if (conn->internal->channel_cache)
+ silc_idcache_free(conn->internal->channel_cache);
+ if (conn->internal->server_cache)
+ silc_idcache_free(conn->internal->server_cache);
+
+ /* Free data (my ID is freed in above silc_client_del_client).
+ conn->nickname is freed when freeing the local_entry->nickname. */
+ silc_free(conn->remote_host);
+ silc_free(conn->local_id_data);
+ if (conn->internal->send_key)
+ silc_cipher_free(conn->internal->send_key);
+ if (conn->internal->receive_key)
+ silc_cipher_free(conn->internal->receive_key);
+ if (conn->internal->hmac_send)
+ silc_hmac_free(conn->internal->hmac_send);
+ if (conn->internal->hmac_receive)
+ silc_hmac_free(conn->internal->hmac_receive);
+ silc_free(conn->internal->rekey);
+
+ if (conn->internal->active_session) {
+ if (conn->sock)
+ conn->sock->user_data = NULL;
+ silc_client_ftp_session_free(conn->internal->active_session);
+ conn->internal->active_session = NULL;
+ }
- if (conn->internal->connect) {
- SILC_LOG_DEBUG(("Event: connect"));
- conn->internal->connect = FALSE;
- SILC_ASSERT(silc_fsm_is_started(thread) == FALSE);
+ silc_client_ftp_free_sessions(client, conn);
- /*** Event: connect */
- silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
- NULL, NULL, FALSE);
- silc_fsm_start_sync(thread, silc_client_st_connect);
- return SILC_FSM_CONTINUE;
- }
+ if (conn->internal->pending_commands) {
+ silc_dlist_start(conn->internal->pending_commands);
+ while ((r = silc_dlist_get(conn->internal->pending_commands))
+ != SILC_LIST_END)
+ silc_dlist_del(conn->internal->pending_commands, r);
+ silc_dlist_uninit(conn->internal->pending_commands);
+ }
- if (conn->internal->key_exchange) {
- SILC_LOG_DEBUG(("Event: key exchange"));
- conn->internal->key_exchange = FALSE;
- SILC_ASSERT(silc_fsm_is_started(thread) == FALSE);
+ silc_free(conn->internal);
+ memset(conn, 0, sizeof(*conn));
+ silc_free(conn);
- /*** Event: key exchange */
- silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
- NULL, NULL, FALSE);
- silc_fsm_start_sync(thread, silc_client_st_connect_set_stream);
- return SILC_FSM_CONTINUE;
- }
+ client->internal->conns[i] = NULL;
+ }
+}
- if (conn->internal->rekeying) {
- SILC_LOG_DEBUG(("Event: rekey"));
- conn->internal->rekeying = FALSE;
- SILC_ASSERT(silc_fsm_is_started(thread) == FALSE);
+/* Adds listener socket to the listener sockets table. This function is
+ used to add socket objects that are listeners to the client. This should
+ not be used to add other connection objects. */
- /*** Event: rekey */
- silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
- NULL, NULL, FALSE);
- silc_fsm_start_sync(thread, silc_client_st_rekey);
- return SILC_FSM_CONTINUE;
+void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
+{
+ int i;
+
+ if (!client->internal->sockets) {
+ client->internal->sockets =
+ silc_calloc(1, sizeof(*client->internal->sockets));
+ client->internal->sockets[0] = silc_socket_dup(sock);
+ client->internal->sockets_count = 1;
+ return;
+ }
+
+ for (i = 0; i < client->internal->sockets_count; i++) {
+ if (client->internal->sockets[i] == NULL) {
+ client->internal->sockets[i] = silc_socket_dup(sock);
+ return;
+ }
}
- /* NOT REACHED */
- SILC_ASSERT(FALSE);
- return SILC_FSM_CONTINUE;
+ client->internal->sockets =
+ silc_realloc(client->internal->sockets,
+ sizeof(*client->internal->sockets) *
+ (client->internal->sockets_count + 1));
+ client->internal->sockets[client->internal->sockets_count] =
+ silc_socket_dup(sock);
+ client->internal->sockets_count++;
}
-/* Packet processor thread. Each incoming packet is processed in FSM
- thread in this state. The thread is run in the connection machine. */
+/* Deletes listener socket from the listener sockets table. */
-SILC_FSM_STATE(silc_client_connection_st_packet)
+void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
{
- SilcClientConnection conn = fsm_context;
- SilcPacket packet = state_context;
+ int i;
- SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
+ if (!client->internal->sockets)
+ return;
- switch (packet->type) {
+ for (i = 0; i < client->internal->sockets_count; i++) {
+ if (client->internal->sockets[i] == sock) {
+ silc_socket_free(sock);
+ client->internal->sockets[i] = NULL;
+ return;
+ }
+ }
+}
- case SILC_PACKET_PRIVATE_MESSAGE:
- /** Private message */
- silc_fsm_next(fsm, silc_client_private_message);
- break;
+static int
+silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
+{
+ int sock;
+
+ /* XXX In the future we should give up this non-blocking connect all
+ together and use threads instead. */
+ /* Create connection to server asynchronously */
+ sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
+ if (sock < 0)
+ return -1;
+
+ /* Register task that will receive the async connect and will
+ read the result. */
+ ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
+ silc_client_connect_to_server_start,
+ (void *)ctx, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+ silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
+ FALSE);
+
+ ctx->sock = sock;
+
+ return sock;
+}
- case SILC_PACKET_CHANNEL_MESSAGE:
- /** Channel message */
- silc_fsm_next(fsm, silc_client_channel_message);
- break;
+/* Connects to remote server. This is the main routine used to connect
+ to SILC server. Returns -1 on error and the created socket otherwise.
+ The `context' is user context that is saved into the SilcClientConnection
+ that is created after the connection is created. Note that application
+ may handle the connecting process outside the library. If this is the
+ case then this function is not used at all. When the connecting is
+ done the `connect' client operation is called. */
+
+int silc_client_connect_to_server(SilcClient client,
+ SilcClientConnectionParams *params,
+ int port, char *host, void *context)
+{
+ SilcClientInternalConnectContext *ctx;
+ SilcClientConnection conn;
+ int sock;
- case SILC_PACKET_FTP:
- /* File transfer packet */
- silc_fsm_next(fsm, silc_client_ftp);
- break;
+ SILC_LOG_DEBUG(("Connecting to port %d of server %s",
+ port, host));
- case SILC_PACKET_CHANNEL_KEY:
- /** Channel key */
- silc_fsm_next(fsm, silc_client_channel_key);
- break;
+ conn = silc_client_add_connection(client, params, host, port, context);
- case SILC_PACKET_COMMAND_REPLY:
- /** Command reply */
- silc_fsm_next(fsm, silc_client_command_reply);
- break;
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of server %s", port, host);
+
+ /* Allocate internal context for connection process. This is
+ needed as we are doing async connecting. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->conn = conn;
+ ctx->host = strdup(host);
+ ctx->port = port ? port : 706;
+ ctx->tries = 0;
+
+ /* Do the actual connecting process */
+ sock = silc_client_connect_to_server_internal(ctx);
+ if (sock == -1)
+ silc_client_del_connection(client, conn);
+ return sock;
+}
- case SILC_PACKET_NOTIFY:
- /** Notify */
- silc_fsm_next(fsm, silc_client_notify);
- break;
+/* Socket hostname and IP lookup callback that is called before actually
+ starting the key exchange. The lookup is called from the function
+ silc_client_start_key_exchange. */
- case SILC_PACKET_PRIVATE_MESSAGE_KEY:
- /* Private message key indicator */
- silc_fsm_next(fsm, silc_client_private_message_key);
- break;
+static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
+ void *context)
+{
+ SilcClientConnection conn = (SilcClientConnection)context;
+ SilcClient client = conn->client;
+ SilcProtocol protocol;
+ SilcClientKEInternalContext *proto_ctx;
- case SILC_PACKET_DISCONNECT:
- /** Disconnect */
- silc_fsm_next(fsm, silc_client_disconnect);
- break;
+ SILC_LOG_DEBUG(("Start"));
- case SILC_PACKET_ERROR:
- /* Error by server */
- silc_fsm_next(fsm, silc_client_error);
- break;
+ if (conn->sock->hostname) {
+ silc_free(conn->remote_host);
+ conn->remote_host = strdup(conn->sock->hostname);
+ } else {
+ conn->sock->hostname = strdup(conn->remote_host);
+ }
+ if (!conn->sock->ip)
+ conn->sock->ip = strdup(conn->sock->hostname);
+ conn->sock->port = conn->remote_port;
+
+ /* Allocate internal Key Exchange context. This is sent to the
+ protocol as context. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = silc_socket_dup(conn->sock);
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = FALSE;
+ proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
+
+ /* Perform key exchange protocol. silc_client_connect_to_server_final
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &protocol, (void *)proto_ctx,
+ silc_client_connect_to_server_second);
+ if (!protocol) {
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Error: Could not start key exchange protocol");
+ silc_net_close_connection(conn->sock->sock);
+ client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
+ return;
+ }
+ conn->sock->protocol = protocol;
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it will
+ be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)client;
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
+
+ /* Execute the protocol */
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+}
- case SILC_PACKET_KEY_AGREEMENT:
- /** Key agreement */
- silc_fsm_next(fsm, silc_client_key_agreement);
- break;
+/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
+ key material between client and server. This function can be called
+ directly if application is performing its own connecting and does not
+ use the connecting provided by this library. This function is normally
+ used only if the application performed the connecting outside the library.
+ The library however may use this internally. */
- case SILC_PACKET_COMMAND:
- /** Command packet */
- silc_fsm_next(fsm, silc_client_command);
- break;
+void silc_client_start_key_exchange(SilcClient client,
+ SilcClientConnection conn,
+ int fd)
+{
+ assert(client->pkcs);
+ assert(client->public_key);
+ assert(client->private_key);
- case SILC_PACKET_NEW_ID:
- /** New ID */
- silc_fsm_next(fsm, silc_client_new_id);
- break;
+ /* Allocate new socket connection object */
+ silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
- case SILC_PACKET_CONNECTION_AUTH_REQUEST:
- /** Connection auth resolve reply */
- silc_fsm_next(fsm, silc_client_connect_auth_request);
- break;
+ /* Sometimes when doing quick reconnects the new socket may be same as
+ the old one and there might be pending stuff for the old socket.
+ If new one is same then those pending sutff might cause problems.
+ Make sure they do not do that. */
+ silc_schedule_task_del_by_fd(client->schedule, fd);
- case SILC_PACKET_REKEY:
- /* Signal to start rekey */
- conn->internal->rekey_responder = TRUE;
- conn->internal->rekeying = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
+ conn->nickname = (client->nickname ? strdup(client->nickname) :
+ strdup(client->username));
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- break;
+ /* Resolve the remote hostname and IP address for our socket connection */
+ silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
+ conn, client->schedule);
+}
- default:
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- break;
- }
+/* Callback called when error has occurred during connecting (KE) to
+ the server. The `connect' client operation will be called. */
- return SILC_FSM_CONTINUE;
+SILC_TASK_CALLBACK(silc_client_connect_failure)
+{
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ client->internal->ops->connected(client, ctx->sock->user_data,
+ SILC_CLIENT_CONN_ERROR_KE);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ silc_free(ctx);
}
-/* Disconnection event to close remote connection. We close the connection
- and finish the connection machine in this state. The connection context
- is deleted in the machine destructor. The connection callback is called
- in this state if it is set. */
+/* Callback called when error has occurred during connecting (auth) to
+ the server. The `connect' client operation will be called. */
-SILC_FSM_STATE(silc_client_connection_st_close)
+SILC_TASK_CALLBACK(silc_client_connect_failure_auth)
{
- SilcClientConnection conn = fsm_context;
- SilcClientCommandContext cmd;
-
- /* Finish running command threads. This will also finish waiting packet
- thread, as they are always waiting for some command. If any thread is
- waiting something else than command, they must be finished explicitly. */
- if (silc_list_count(conn->internal->pending_commands)) {
- SILC_LOG_DEBUG(("Finish pending commands"));
- silc_list_start(conn->internal->pending_commands);
- while ((cmd = silc_list_get(conn->internal->pending_commands))) {
- if (silc_fsm_is_started(&cmd->thread)) {
- cmd->verbose = FALSE;
- silc_fsm_continue_sync(&cmd->thread);
- }
- }
+ SilcClientConnAuthInternalContext *ctx =
+ (SilcClientConnAuthInternalContext *)context;
+ SilcClient client = (SilcClient)ctx->client;
- /* Give threads time to finish */
- return SILC_FSM_YIELD;
- }
+ client->internal->ops->connected(client, ctx->sock->user_data, ctx->status);
+ silc_free(ctx);
+}
- /* Abort ongoing event */
- if (conn->internal->op) {
- SILC_LOG_DEBUG(("Abort event"));
- silc_async_abort(conn->internal->op, NULL, NULL);
- conn->internal->op = NULL;
- }
+/* Start of the connection to the remote server. This is called after
+ succesful TCP/IP connection has been established to the remote host. */
- /* If event thread is running, finish it. */
- if (silc_fsm_is_started(&conn->internal->event_thread)) {
- SILC_LOG_DEBUG(("Finish event thread"));
- silc_fsm_continue_sync(&conn->internal->event_thread);
- return SILC_FSM_YIELD;
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
+{
+ SilcClientInternalConnectContext *ctx =
+ (SilcClientInternalConnectContext *)context;
+ SilcClient client = ctx->client;
+ SilcClientConnection conn = ctx->conn;
+ int opt, opt_len = sizeof(opt);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Check the socket status as it might be in error */
+ silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
+ if (opt != 0) {
+ if (ctx->tries < 2) {
+ /* Connection failed but lets try again */
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of server %s resumed",
+ ctx->port, ctx->host);
+
+ /* Unregister old connection try */
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_net_close_connection(fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+
+ /* Try again */
+ silc_client_connect_to_server_internal(ctx);
+ ctx->tries++;
+ } else {
+ /* Connection failed and we won't try anymore */
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_net_close_connection(fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+ silc_free(ctx);
+
+ /* Notify application of failure */
+ client->internal->ops->connected(client, conn,
+ SILC_CLIENT_CONN_ERROR_TIMEOUT);
+ }
+ return;
}
- /* Call the connection callback */
- if (conn->callback)
- conn->callback(conn->client, conn, conn->internal->status,
- conn->internal->error, conn->internal->disconnect_message,
- conn->callback_context);
- silc_free(conn->internal->disconnect_message);
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+ silc_free(ctx);
- SILC_LOG_DEBUG(("Closing remote connection"));
+ silc_client_start_key_exchange(client, conn, fd);
+}
+
+/* Second part of the connecting to the server. This executed
+ authentication protocol. */
- /* Close connection. */
- if (conn->stream)
- silc_packet_stream_destroy(conn->stream);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcSocketConnection sock = NULL;
+ SilcClientConnAuthInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ SILC_LOG_DEBUG(("Error during KE protocol"));
+ silc_protocol_free(protocol);
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ ctx->sock->protocol = NULL;
+ silc_socket_free(ctx->sock);
+
+ /* Notify application of failure */
+ silc_schedule_task_add(client->schedule, ctx->sock->sock,
+ silc_client_connect_failure, ctx,
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ return;
+ }
- SILC_LOG_DEBUG(("Finishing connection machine"));
- return SILC_FSM_FINISH;
+ /* We now have the key material as the result of the key exchange
+ protocol. Take the key material into use. Free the raw key material
+ as soon as we've set them into use. */
+ silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
+ ctx->ske->prop->cipher,
+ ctx->ske->prop->pkcs,
+ ctx->ske->prop->hash,
+ ctx->ske->prop->hmac,
+ ctx->ske->prop->group,
+ ctx->responder);
+ silc_ske_free_key_material(ctx->keymat);
+
+ /* Allocate internal context for the authentication protocol. This
+ is sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = sock = ctx->sock;
+ proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
+ proto_ctx->dest_id_type = ctx->dest_id_type;
+ proto_ctx->dest_id = ctx->dest_id;
+
+ /* Free old protocol as it is finished now */
+ silc_protocol_free(protocol);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ ctx->packet = NULL;
+ silc_free(ctx);
+ sock->protocol = NULL;
+
+ /* Resolve the authentication method to be used in this connection. The
+ completion callback is called after the application has resolved
+ the authentication method. */
+ client->internal->ops->get_auth_method(client, sock->user_data,
+ sock->hostname,
+ sock->port,
+ silc_client_resolve_auth_method,
+ proto_ctx);
}
-/* Received error packet from server. Send it to application. */
+/* Authentication method resolving callback. Application calls this function
+ after we've called the client->internal->ops->get_auth_method
+ client operation to resolve the authentication method. We will continue
+ the executiong of the protocol in this function. */
-SILC_FSM_STATE(silc_client_error)
+void silc_client_resolve_auth_method(bool success,
+ SilcProtocolAuthMeth auth_meth,
+ const unsigned char *auth_data,
+ SilcUInt32 auth_data_len, void *context)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
- char *msg;
+ SilcClientConnAuthInternalContext *proto_ctx =
+ (SilcClientConnAuthInternalContext *)context;
+ SilcClient client = (SilcClient)proto_ctx->client;
+
+ if (!success)
+ auth_meth = SILC_AUTH_NONE;
+
+ proto_ctx->auth_meth = auth_meth;
+
+ if (success && auth_data && auth_data_len) {
+
+ /* Passphrase must be UTF-8 encoded, if it isn't encode it */
+ if (auth_meth == SILC_AUTH_PASSWORD &&
+ !silc_utf8_valid(auth_data, auth_data_len)) {
+ int payload_len = 0;
+ unsigned char *autf8 = NULL;
+ payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
+ SILC_STRING_ASCII);
+ autf8 = silc_calloc(payload_len, sizeof(*autf8));
+ auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
+ SILC_STRING_ASCII, autf8, payload_len);
+ auth_data = autf8;
+ }
- msg = silc_memdup(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer));
- if (msg)
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, msg);
+ proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
+ proto_ctx->auth_data_len = auth_data_len;
+ }
- silc_free(msg);
- silc_packet_free(packet);
+ /* Allocate the authenteication protocol and execute it. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+ &proto_ctx->sock->protocol, (void *)proto_ctx,
+ silc_client_connect_to_server_final);
- return SILC_FSM_FINISH;
+ /* Execute the protocol */
+ silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
}
-/* Received disconnect packet from server. We close the connection and
- send the disconnect message to application. */
+/* Finalizes the connection to the remote SILC server. This is called
+ after authentication protocol has been completed. This send our
+ user information to the server to receive our client ID from
+ server. */
-SILC_FSM_STATE(silc_client_disconnect)
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
{
- SilcClientConnection conn = fsm_context;
- SilcPacket packet = state_context;
- SilcStatus status;
- char *message = NULL;
-
- SILC_LOG_DEBUG(("Server disconnected"));
-
- if (silc_buffer_len(&packet->buffer) < 1) {
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientConnAuthInternalContext *ctx =
+ (SilcClientConnAuthInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcBuffer packet;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ SILC_LOG_DEBUG(("Error during authentication protocol"));
+ ctx->status = SILC_CLIENT_CONN_ERROR_AUTH;
+ goto err;
}
- status = (SilcStatus)packet->buffer.data[0];
+ if (conn->internal->params.detach_data) {
+ /* Send RESUME_CLIENT packet to the server, which is used to resume
+ old detached session back. */
+ SilcBuffer auth;
+ SilcClientID *old_client_id;
+ unsigned char *old_id;
+ SilcUInt16 old_id_len;
+
+ if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len)) {
+ ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
+ goto err;
+ }
- silc_buffer_pull(&packet->buffer, 1);
- if (silc_buffer_len(&packet->buffer) > 1 &&
- silc_utf8_valid(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer)))
- message = silc_memdup(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer));
+ old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
+ if (!old_client_id) {
+ silc_free(old_id);
+ ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
+ goto err;
+ }
- /* Call connection callback */
- conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
- conn->internal->error = status;
- conn->internal->disconnect_message = message;
+ /* Generate authentication data that server will verify */
+ auth = silc_auth_public_key_auth_generate(client->public_key,
+ client->private_key,
+ client->rng,
+ conn->internal->hash,
+ old_client_id, SILC_ID_CLIENT);
+ if (!auth) {
+ silc_free(old_client_id);
+ silc_free(old_id);
+ ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
+ goto err;
+ }
- /* Signal to close connection */
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
+ packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(old_id_len),
+ SILC_STR_UI_XNSTRING(old_id, old_id_len),
+ SILC_STR_UI_XNSTRING(auth->data, auth->len),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ silc_buffer_free(auth);
+ silc_free(old_client_id);
+ silc_free(old_id);
+ } else {
+ /* Send NEW_CLIENT packet to the server. We will become registered
+ to the SILC network after sending this packet and we will receive
+ client ID from the server. */
+ packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
+ strlen(client->realname));
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(strlen(client->username)),
+ SILC_STR_UI_XNSTRING(client->username,
+ strlen(client->username)),
+ SILC_STR_UI_SHORT(strlen(client->realname)),
+ SILC_STR_UI_XNSTRING(client->realname,
+ strlen(client->realname)),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
}
- silc_packet_free(packet);
-
- return SILC_FSM_FINISH;
+ /* Save remote ID. */
+ conn->remote_id = ctx->dest_id;
+ conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
+ conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
+
+ /* Register re-key timeout */
+ conn->internal->rekey->timeout = client->internal->params->rekey_secs;
+ conn->internal->rekey->context = (void *)client;
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
+ silc_client_rekey_callback,
+ (void *)conn->sock, conn->internal->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ silc_protocol_free(protocol);
+ silc_free(ctx->auth_data);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_socket_free(ctx->sock);
+ silc_free(ctx);
+ conn->sock->protocol = NULL;
+ return;
+
+ err:
+ silc_protocol_free(protocol);
+ silc_free(ctx->auth_data);
+ silc_free(ctx->dest_id);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ conn->sock->protocol = NULL;
+ silc_socket_free(ctx->sock);
+
+ /* Notify application of failure */
+ silc_schedule_task_add(client->schedule, ctx->sock->sock,
+ silc_client_connect_failure_auth, ctx,
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
-/*************************** Main client machine ****************************/
+/* Internal routine that sends packet or marks packet to be sent. This
+ is used directly only in special cases. Normal cases should use
+ silc_server_packet_send. Returns < 0 on error. */
+
+int silc_client_packet_send_real(SilcClient client,
+ SilcSocketConnection sock,
+ bool force_send)
+{
+ int ret;
+
+ /* If rekey protocol is active we must assure that all packets are
+ sent through packet queue. */
+ if (SILC_CLIENT_IS_REKEY(sock))
+ force_send = FALSE;
+
+ /* If outbound data is already pending do not force send */
+ if (SILC_IS_OUTBUF_PENDING(sock))
+ force_send = FALSE;
+
+ /* Send the packet */
+ ret = silc_packet_send(sock, force_send);
+ if (ret != -2)
+ return ret;
+
+ /* Mark that there is some outgoing data available for this connection.
+ This call sets the connection both for input and output (the input
+ is set always and this call keeps the input setting, actually).
+ Actual data sending is performed by silc_client_packet_process. */
+ SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
+
+ /* Mark to socket that data is pending in outgoing buffer. This flag
+ is needed if new data is added to the buffer before the earlier
+ put data is sent to the network. */
+ SILC_SET_OUTBUF_PENDING(sock);
+
+ return 0;
+}
-/* The client's main state where we wait for various events */
+/* Packet processing callback. This is used to send and receive packets
+ from network. This is generic task. */
-SILC_FSM_STATE(silc_client_st_run)
+SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
{
- SilcClient client = fsm_context;
+ SilcClient client = (SilcClient)context;
+ SilcSocketConnection sock = NULL;
+ SilcClientConnection conn;
+ int ret;
+
+ SILC_LOG_DEBUG(("Processing packet"));
+
+ SILC_CLIENT_GET_SOCK(client, fd, sock);
+ if (sock == NULL)
+ return;
+
+ conn = (SilcClientConnection)sock->user_data;
+
+ /* Packet sending */
+ if (type == SILC_TASK_WRITE) {
+ /* Do not send data to disconnected connection */
+ if (SILC_IS_DISCONNECTED(sock))
+ return;
+
+ ret = silc_packet_send(sock, TRUE);
+
+ /* If returned -2 could not write to connection now, will do
+ it later. */
+ if (ret == -2)
+ return;
- /* Wait for events */
- SILC_FSM_EVENT_WAIT(&client->internal->wait_event);
+ /* Error */
+ if (ret == -1)
+ return;
- /* Process events */
+ /* The packet has been sent and now it is time to set the connection
+ back to only for input. When there is again some outgoing data
+ available for this connection it will be set for output as well.
+ This call clears the output setting and sets it only for input. */
+ SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
+ SILC_UNSET_OUTBUF_PENDING(sock);
- if (client->internal->run_callback && client->internal->running) {
- /* Call running callbcak back to application */
- SILC_LOG_DEBUG(("We are up, call running callback"));
- client->internal->run_callback = FALSE;
- client->internal->running(client, client->internal->running_context);
- return SILC_FSM_CONTINUE;
+ silc_buffer_clear(sock->outbuf);
+ return;
}
- if (client->internal->connection_closed) {
- /* A connection finished */
- SILC_LOG_DEBUG(("Event: connection closed"));
- client->internal->connection_closed = FALSE;
- if (silc_atomic_get_int16(&client->internal->conns) == 0 &&
- client->internal->stop)
- SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
- return SILC_FSM_CONTINUE;
+ /* Packet receiving */
+ if (type == SILC_TASK_READ) {
+ /* Read data from network */
+ ret = silc_packet_receive(sock);
+ if (ret < 0)
+ return;
+
+ /* EOF */
+ if (ret == 0) {
+ SILC_LOG_DEBUG(("Read EOF"));
+
+ /* If connection is disconnecting already we will finally
+ close the connection */
+ if (SILC_IS_DISCONNECTING(sock)) {
+ if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
+ client->internal->ops->disconnected(client, conn, 0, NULL);
+ silc_client_close_connection_real(client, sock, conn);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
+ if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
+ client->internal->ops->disconnected(client, conn, 0, NULL);
+ silc_client_close_connection_real(client, sock, conn);
+ return;
+ }
+
+ /* Process the packet. This will call the parser that will then
+ decrypt and parse the packet. */
+ if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
+ silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
+ conn->internal->hmac_receive,
+ conn->internal->psn_receive,
+ silc_client_packet_parse, client);
+ else
+ silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
+ silc_client_packet_parse, client);
+ }
+}
+
+/* Parser callback called by silc_packet_receive_process. Thie merely
+ registers timeout that will handle the actual parsing when appropriate. */
+
+static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
+ void *context)
+{
+ SilcClient client = (SilcClient)context;
+ SilcSocketConnection sock = parser_context->sock;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcPacketContext *packet = parser_context->packet;
+ SilcPacketType ret;
+
+ if (conn && conn->internal->hmac_receive && conn->sock == sock)
+ conn->internal->psn_receive = parser_context->packet->sequence + 1;
+
+ /* Parse the packet immediately */
+ if (parser_context->normal)
+ ret = silc_packet_parse(packet, conn->internal->receive_key);
+ else
+ ret = silc_packet_parse_special(packet, conn->internal->receive_key);
+
+ if (ret == SILC_PACKET_NONE) {
+ silc_packet_context_free(packet);
+ silc_free(parser_context);
+ return FALSE;
}
- if (client->internal->stop) {
- /* Stop client libarry. If we have running connections, wait until
- they finish first. */
- SILC_LOG_DEBUG(("Event: stop"));
- if (silc_atomic_get_int16(&client->internal->conns) == 0)
- silc_fsm_next(fsm, silc_client_st_stop);
- return SILC_FSM_CONTINUE;
+ /* If protocol for this connection is key exchange or rekey then we'll
+ process all packets synchronously, since there might be packets in
+ queue that we are not able to decrypt without first processing the
+ packets before them. */
+ if (sock->protocol && sock->protocol->protocol &&
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
+
+ /* Parse the incoming packet type */
+ silc_client_packet_parse_type(client, sock, packet);
+
+ /* Reprocess the buffer since we'll return FALSE. This is because
+ the `conn->internal->receive_key' might have become valid by processing
+ the previous packet */
+ if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
+ silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
+ conn->internal->hmac_receive,
+ conn->internal->psn_receive,
+ silc_client_packet_parse, client);
+ else
+ silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
+ silc_client_packet_parse, client);
+
+ silc_packet_context_free(packet);
+ silc_free(parser_context);
+
+ return FALSE;
}
- /* NOT REACHED */
- SILC_ASSERT(FALSE);
- return SILC_FSM_CONTINUE;
+ /* Parse the incoming packet type */
+ silc_client_packet_parse_type(client, sock, packet);
+ silc_packet_context_free(packet);
+ silc_free(parser_context);
+ return TRUE;
}
-/* Stop event. Stops the client library. */
+/* Parses the packet type and calls what ever routines the packet type
+ requires. This is done for all incoming packets. */
-SILC_FSM_STATE(silc_client_st_stop)
+void silc_client_packet_parse_type(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClient client = fsm_context;
+ SilcBuffer buffer = packet->buffer;
+ SilcPacketType type = packet->type;
- SILC_LOG_DEBUG(("Client stopped"));
+ SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
- /* Stop scheduler */
- silc_schedule_stop(client->schedule);
- silc_client_commands_unregister(client);
+ /* Parse the packet type */
+ switch(type) {
- /* Call stopped callback to application */
- if (client->internal->running)
- client->internal->running(client, client->internal->running_context);
+ case SILC_PACKET_DISCONNECT:
+ silc_client_disconnected_by_server(client, sock, buffer);
+ break;
- return SILC_FSM_FINISH;
-}
+ case SILC_PACKET_SUCCESS:
+ /*
+ * Success received for something. For now we can have only
+ * one protocol for connection executing at once hence this
+ * success message is for whatever protocol is executing currently.
+ */
+ if (sock->protocol)
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ break;
-/******************************* Private API ********************************/
+ case SILC_PACKET_FAILURE:
+ /*
+ * Failure received for some protocol. Set the protocol state to
+ * error and call the protocol callback. This fill cause error on
+ * protocol and it will call the final callback.
+ */
+ silc_client_process_failure(client, sock, packet);
+ break;
-/* Adds new connection. Creates the connection context and returns it. */
+ case SILC_PACKET_REJECT:
+ break;
-SilcClientConnection
-silc_client_add_connection(SilcClient client,
- SilcConnectionType conn_type,
- SilcBool connect,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *remote_host, int port,
- SilcClientConnectCallback callback,
- void *context)
-{
- SilcClientConnection conn;
- SilcFSMThread thread;
+ case SILC_PACKET_NOTIFY:
+ /*
+ * Received notify message
+ */
+ silc_client_notify_by_server(client, sock, packet);
+ break;
- if (!callback)
- return NULL;
+ case SILC_PACKET_ERROR:
+ /*
+ * Received error message
+ */
+ silc_client_error_by_server(client, sock, buffer);
+ break;
- SILC_LOG_DEBUG(("Adding new connection to %s:%d", remote_host, port));
+ case SILC_PACKET_CHANNEL_MESSAGE:
+ /*
+ * Received message to (from, actually) a channel
+ */
+ silc_client_channel_message(client, sock, packet);
+ break;
- conn = silc_calloc(1, sizeof(*conn));
- if (!conn)
- return NULL;
+ case SILC_PACKET_CHANNEL_KEY:
+ /*
+ * Received key for a channel. By receiving this key the client will be
+ * able to talk to the channel it has just joined. This can also be
+ * a new key for existing channel as keys expire peridiocally.
+ */
+ silc_client_receive_channel_key(client, sock, buffer);
+ break;
- conn->client = client;
- conn->public_key = public_key;
- conn->private_key = private_key;
- conn->remote_host = strdup(remote_host);
- conn->remote_port = port ? port : 706;
- conn->type = conn_type;
- conn->callback = callback;
- conn->callback_context = context;
+ case SILC_PACKET_PRIVATE_MESSAGE:
+ /*
+ * Received private message
+ */
+ silc_client_private_message(client, sock, packet);
+ break;
- conn->internal = silc_calloc(1, sizeof(*conn->internal));
- if (!conn->internal) {
- silc_free(conn);
- return NULL;
- }
- conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
- silc_mutex_alloc(&conn->internal->lock);
- silc_atomic_init16(&conn->internal->cmd_ident, 0);
-
- if (!silc_hash_alloc("sha1", &conn->internal->sha1hash)) {
- silc_free(conn);
- silc_free(conn->internal);
- return NULL;
- }
+ case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+ /*
+ * Received private message key indicator
+ */
+ silc_client_private_message_key(client, sock, packet);
+ break;
- /* Set parameters */
- if (params)
- conn->internal->params = *params;
- if (!conn->internal->params.rekey_secs)
- conn->internal->params.rekey_secs = 3600;
-#ifndef SILC_DIST_INPLACE
- if (conn->internal->params.rekey_secs < 300)
- conn->internal->params.rekey_secs = 300;
-#endif /* SILC_DIST_INPLACE */
-
- conn->internal->verbose = TRUE;
- silc_list_init(conn->internal->pending_commands,
- struct SilcClientCommandContextStruct, next);
- silc_list_init(conn->internal->thread_pool, SilcFSMThreadStruct, next);
-
- /* Allocate client, channel and serve caches */
- if (conn_type != SILC_CONN_CLIENT) {
- conn->internal->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
- NULL, NULL);
- conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL,
- NULL, NULL);
- conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER,
- NULL, NULL);
- if (!conn->internal->client_cache || !conn->internal->channel_cache ||
- !conn->internal->server_cache) {
- silc_client_del_connection(client, conn);
- return NULL;
- }
- }
+ case SILC_PACKET_COMMAND:
+ /*
+ * Received command packet, a special case since normally client
+ * does not receive commands.
+ */
+ silc_client_command_process(client, sock, packet);
+ break;
- if (connect) {
- /* Initialize our async operation so that application may abort us
- while we're connecting. */
- conn->internal->cop = silc_async_alloc(silc_client_connect_abort,
- NULL, conn);
- if (!conn->internal->cop) {
- silc_client_del_connection(client, conn);
- return NULL;
+ case SILC_PACKET_COMMAND_REPLY:
+ /*
+ * Recived reply for a command
+ */
+ silc_client_command_reply_process(client, sock, packet);
+ break;
+
+ case SILC_PACKET_KEY_EXCHANGE:
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
+
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
+ "protocol active, packet dropped."));
}
- }
+ break;
- /* Run the connection state machine. If threads are in use the connection
- machine is always run in a real thread. */
- thread = silc_fsm_thread_alloc(&client->internal->fsm, conn,
- silc_client_connection_finished, NULL,
- client->internal->params->threads);
- if (!thread) {
- silc_client_del_connection(client, conn);
- return NULL;
- }
- silc_fsm_set_state_context(thread, client);
- silc_fsm_start(thread, silc_client_connection_st_start);
+ case SILC_PACKET_KEY_EXCHANGE_1:
+ if (sock->protocol && sock->protocol->protocol &&
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
- SILC_LOG_DEBUG(("New connection %p", conn));
- silc_atomic_add_int16(&client->internal->conns, 1);
+ if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)sock->protocol->context;
- return conn;
-}
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
-/* Deletes connection. This is always called from the connection machine
- destructor. Do not call this directly other places. */
+ proto_ctx->packet = silc_packet_context_dup(packet);
-void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
-{
- SilcList list;
- SilcIDCacheEntry entry;
- SilcFSMThread thread;
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ } else {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
- SILC_LOG_DEBUG(("Freeing connection %p", conn));
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
- silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
- /* Free all cache entries */
- if (conn->internal->server_cache) {
- if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
- silc_list_start(list);
- while ((entry = silc_list_get(list)))
- silc_client_del_server(client, conn, entry->context);
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ }
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
+ "protocol active, packet dropped."));
}
- }
- if (conn->internal->channel_cache) {
- if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
- silc_list_start(list);
- while ((entry = silc_list_get(list))) {
- silc_client_empty_channel(client, conn, entry->context);
- silc_client_del_channel(client, conn, entry->context);
+ break;
+
+ case SILC_PACKET_KEY_EXCHANGE_2:
+ if (sock->protocol && sock->protocol->protocol &&
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
+
+ if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ } else {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+ if (proto_ctx->dest_id)
+ silc_free(proto_ctx->dest_id);
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
+
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
}
+ } else {
+ SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
+ "protocol active, packet dropped."));
}
- }
- if (conn->internal->client_cache) {
- if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
- silc_list_start(list);
- while ((entry = silc_list_get(list)))
- silc_client_del_client(client, conn, entry->context);
+ break;
+
+ case SILC_PACKET_NEW_ID:
+ {
+ /*
+ * Received new ID from server. This packet is received at
+ * the connection to the server. New ID is also received when
+ * user changes nickname but in that case the new ID is received
+ * as command reply and not as this packet type.
+ */
+ SilcIDPayload idp;
+
+ idp = silc_id_payload_parse(buffer->data, buffer->len);
+ if (!idp)
+ break;
+ if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
+ break;
+
+ silc_client_receive_new_id(client, sock, idp);
+ silc_id_payload_free(idp);
+ break;
}
- }
- /* Free ID caches */
- if (conn->internal->client_cache)
- silc_idcache_free(conn->internal->client_cache);
- if (conn->internal->channel_cache)
- silc_idcache_free(conn->internal->channel_cache);
- if (conn->internal->server_cache)
- silc_idcache_free(conn->internal->server_cache);
-
- /* Free thread pool */
- silc_list_start(conn->internal->thread_pool);
- while ((thread = silc_list_get(conn->internal->thread_pool)))
- silc_fsm_free(thread);
-
- silc_free(conn->remote_host);
- silc_buffer_free(conn->internal->local_idp);
- silc_buffer_free(conn->internal->remote_idp);
- silc_mutex_free(conn->internal->lock);
- if (conn->internal->hash)
- silc_hash_free(conn->internal->hash);
- if (conn->internal->sha1hash)
- silc_hash_free(conn->internal->sha1hash);
- silc_atomic_uninit16(&conn->internal->cmd_ident);
- silc_free(conn->internal->away_message);
- if (conn->internal->rekey)
- silc_ske_free_rekey_material(conn->internal->rekey);
- if (conn->internal->cop)
- silc_async_free(conn->internal->cop);
-
- silc_free(conn->internal);
- memset(conn, 'F', sizeof(*conn));
- silc_free(conn);
-}
+ case SILC_PACKET_HEARTBEAT:
+ /*
+ * Received heartbeat packet
+ */
+ SILC_LOG_DEBUG(("Heartbeat packet"));
+ break;
+
+ case SILC_PACKET_KEY_AGREEMENT:
+ /*
+ * Received key agreement packet
+ */
+ SILC_LOG_DEBUG(("Key agreement packet"));
+ silc_client_key_agreement(client, sock, packet);
+ break;
-/******************************* Client API *********************************/
+ case SILC_PACKET_REKEY:
+ SILC_LOG_DEBUG(("Re-key packet"));
+ /* We ignore this for now */
+ break;
-/* Connects to remote server. This is the main routine used to connect
- to remote SILC server. Performs key exchange also. Returns the
- connection context to the connection callback. */
+ case SILC_PACKET_REKEY_DONE:
+ SILC_LOG_DEBUG(("Re-key done packet"));
+
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+
+ /* Let the protocol handle the packet */
+ if (proto_ctx->responder == FALSE)
+ silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ else
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->schedule,
+ 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
+ "protocol active, packet dropped."));
+ }
+ break;
-SilcAsyncOperation
-silc_client_connect_to_server(SilcClient client,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *remote_host, int port,
- SilcClientConnectCallback callback,
- void *context)
+ case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+ /*
+ * Reveived reply to our connection authentication method request
+ * packet. This is used to resolve the authentication method for the
+ * current session from the server if the client does not know it.
+ */
+ silc_client_connection_auth_request(client, sock, packet);
+ break;
+
+ case SILC_PACKET_FTP:
+ /* Received file transfer packet. */
+ silc_client_ftp(client, sock, packet);
+ break;
+
+ default:
+ SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
+ break;
+ }
+}
+
+/* Sends packet. This doesn't actually send the packet instead it assembles
+ it and marks it to be sent. However, if force_send is TRUE the packet
+ is sent immediately. if dst_id, cipher and hmac are NULL those parameters
+ will be derived from sock argument. Otherwise the valid arguments sent
+ are used. */
+
+void silc_client_packet_send(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send)
{
- SilcClientConnection conn;
+ SilcPacketContext packetdata;
+ const SilcBufferStruct packet;
+ int block_len;
+ SilcUInt32 sequence = 0;
+
+ if (!sock)
+ return;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
- SILC_LOG_DEBUG(("Connecting to server"));
+ /* Get data used in the packet sending, keys and stuff */
+ if ((!cipher || !hmac || !dst_id) && sock->user_data) {
+ if (!cipher && ((SilcClientConnection)sock->user_data)->internal->send_key)
+ cipher = ((SilcClientConnection)sock->user_data)->internal->send_key;
- if (!client || !remote_host)
- return NULL;
+ if (!hmac && ((SilcClientConnection)sock->user_data)->internal->hmac_send)
+ hmac = ((SilcClientConnection)sock->user_data)->internal->hmac_send;
- /* Add new connection */
- conn = silc_client_add_connection(client, SILC_CONN_SERVER, TRUE, params,
- public_key, private_key, remote_host,
- port, callback, context);
- if (!conn) {
- callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
- return NULL;
+ if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
+ dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
+ dst_id_type = SILC_ID_SERVER;
+ }
+
+ if (hmac)
+ sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++;
+
+ /* Check for mandatory rekey */
+ if (sequence == SILC_CLIENT_REKEY_THRESHOLD)
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_rekey_callback, sock, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of server %s",
- port, remote_host);
+ block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+
+ /* Set the packet context pointers */
+ packetdata.flags = 0;
+ packetdata.type = type;
+ if (sock->user_data &&
+ ((SilcClientConnection)sock->user_data)->local_id_data) {
+ packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
+ packetdata.src_id_len =
+ silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
+ SILC_ID_CLIENT);
+ } else {
+ packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+ packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+ }
+ packetdata.src_id_type = SILC_ID_CLIENT;
+ if (dst_id) {
+ packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
+ packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
+ packetdata.dst_id_type = dst_id_type;
+ } else {
+ packetdata.dst_id = NULL;
+ packetdata.dst_id_len = 0;
+ packetdata.dst_id_type = SILC_ID_NONE;
+ }
+ data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ if (type == SILC_PACKET_CONNECTION_AUTH)
+ SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen);
+ else
+ SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
+
+ /* Create the outgoing packet */
+ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
+ data, data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Error assembling packet"));
+ return;
+ }
+
+ /* Encrypt the packet */
+ if (cipher)
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
+ packet.len);
+
+ SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
+ packet.data, packet.len);
- /* Signal connection machine to start connecting */
- conn->internal->connect = TRUE;
- return conn->internal->cop;
+ /* Now actually send the packet */
+ silc_client_packet_send_real(client, sock, force_send);
}
-/* Connects to remote client. Performs key exchange also. Returns the
- connection context to the connection callback. */
-
-SilcAsyncOperation
-silc_client_connect_to_client(SilcClient client,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *remote_host, int port,
- SilcClientConnectCallback callback,
- void *context)
+/* Packet sending routine for application. This is the only routine that
+ is provided for application to send SILC packets. */
+
+bool silc_client_send_packet(SilcClient client,
+ SilcClientConnection conn,
+ SilcPacketType type,
+ const unsigned char *data,
+ SilcUInt32 data_len)
{
- SilcClientConnection conn;
- SILC_LOG_DEBUG(("Connecting to client"));
+ assert(client);
+ if (!conn)
+ return FALSE;
+
+ silc_client_packet_send(client, conn->sock, type, NULL, 0, NULL, NULL,
+ (unsigned char *)data, data_len, TRUE);
+ return TRUE;
+}
- if (!client || !remote_host)
- return NULL;
+void silc_client_packet_queue_purge(SilcClient client,
+ SilcSocketConnection sock)
+{
+ if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
+ !(SILC_IS_DISCONNECTED(sock))) {
+ int ret;
+
+ ret = silc_packet_send(sock, TRUE);
+ if (ret == -2) {
+ if (sock->outbuf && sock->outbuf->len > 0) {
+ /* Couldn't send all data, put the queue back up, we'll send
+ rest later. */
+ SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
+ SILC_SET_OUTBUF_PENDING(sock);
+ return;
+ }
+ }
- if (params)
- params->no_authentication = TRUE;
-
- /* Add new connection */
- conn = silc_client_add_connection(client, SILC_CONN_CLIENT, TRUE, params,
- public_key, private_key, remote_host,
- port, callback, context);
- if (!conn) {
- callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
- return NULL;
+ /* Purged all data */
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
+ silc_buffer_clear(sock->outbuf);
}
-
- /* Signal connection machine to start connecting */
- conn->internal->connect = TRUE;
- return conn->internal->cop;
}
-/* Starts key exchange in the remote stream indicated by `stream'. This
- creates the connection context and returns it in the connection callback. */
-
-SilcAsyncOperation
-silc_client_key_exchange(SilcClient client,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcStream stream,
- SilcConnectionType conn_type,
- SilcClientConnectCallback callback,
- void *context)
+/* Closes connection to remote end. Free's all allocated data except
+ for some information such as nickname etc. that are valid at all time.
+ If the `sock' is NULL then the conn->sock will be used. If `sock' is
+ provided it will be checked whether the sock and `conn->sock' are the
+ same (they can be different, ie. a socket can use `conn' as its
+ connection but `conn->sock' might be actually a different connection
+ than the `sock'). */
+
+void silc_client_close_connection_real(SilcClient client,
+ SilcSocketConnection sock,
+ SilcClientConnection conn)
{
- SilcClientConnection conn;
- const char *host;
- SilcUInt16 port;
+ int del = FALSE;
+
+ SILC_LOG_DEBUG(("Start"));
- SILC_LOG_DEBUG(("Performing key exchange"));
+ if (!sock && !conn)
+ return;
- if (!client || !stream)
- return NULL;
+ if (!sock || (sock && conn->sock == sock))
+ del = TRUE;
+ if (!sock)
+ sock = conn->sock;
- if (!silc_socket_stream_get_info(stream, NULL, &host, NULL, &port)) {
- SILC_LOG_ERROR(("Socket stream does not have remote host name set"));
- callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
- return NULL;
+ if (!sock) {
+ if (del && conn)
+ silc_client_del_connection(client, conn);
+ return;
}
- /* Add new connection */
- conn = silc_client_add_connection(client, conn_type, TRUE, params,
- public_key, private_key,
- (char *)host, port, callback, context);
- if (!conn) {
- callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
- return NULL;
+ /* We won't listen for this connection anymore */
+ silc_schedule_unset_listen_fd(client->schedule, sock->sock);
+
+ /* Unregister all tasks */
+ silc_schedule_task_del_by_fd(client->schedule, sock->sock);
+
+ /* Close the actual connection */
+ silc_net_close_connection(sock->sock);
+
+ /* Cancel any active protocol */
+ if (sock->protocol) {
+ if (sock->protocol->protocol->type ==
+ SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type ==
+ SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute_final(sock->protocol, client->schedule);
+ /* The application will recall this function with these protocols
+ (the ops->connected client operation). */
+ return;
+ } else {
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute_final(sock->protocol, client->schedule);
+ sock->protocol = NULL;
+ }
}
- conn->internal->user_stream = stream;
- /* Signal connection to start key exchange */
- conn->internal->key_exchange = TRUE;
- return conn->internal->cop;
+ /* Free everything */
+ if (del && sock->user_data)
+ silc_client_del_connection(client, conn);
+
+ silc_socket_free(sock);
}
-/* Closes remote connection */
+/* Closes the connection to the remote end */
void silc_client_close_connection(SilcClient client,
SilcClientConnection conn)
{
- SILC_LOG_DEBUG(("Closing connection %p", conn));
+ silc_client_close_connection_real(client, NULL, conn);
+}
- /* Signal to close connection */
- conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
+/* Called when we receive disconnection packet from server. This
+ closes our end properly and displays the reason of the disconnection
+ on the screen. */
+
+SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
+{
+ SilcClient client = (SilcClient)context;
+ SilcSocketConnection sock;
+
+ SILC_CLIENT_GET_SOCK(client, fd, sock);
+ if (sock == NULL)
+ return;
+
+ silc_client_close_connection_real(client, sock, sock->user_data);
}
-/* Allocates new client object. This has to be done before client may
- work. After calling this one must call silc_client_init to initialize
- the client. The `application' is application specific user data pointer
- and caller must free it. */
+/* Called when we receive disconnection packet from server. This
+ closes our end properly and displays the reason of the disconnection
+ on the screen. */
-SilcClient silc_client_alloc(SilcClientOperations *ops,
- SilcClientParams *params,
- void *application,
- const char *version_string)
+void silc_client_disconnected_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet)
{
- SilcClient new_client;
+ SilcClientConnection conn;
+ SilcStatus status;
+ char *message = NULL;
- new_client = silc_calloc(1, sizeof(*new_client));
- if (!new_client)
- return NULL;
- new_client->application = application;
+ SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
- new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
- if (!new_client->internal) {
- silc_free(new_client);
- return NULL;
- }
- new_client->internal->ops = ops;
- new_client->internal->params =
- silc_calloc(1, sizeof(*new_client->internal->params));
- if (!version_string)
- version_string = silc_version_string;
- new_client->internal->silc_client_version = strdup(version_string);
+ if (packet->len < 1)
+ return;
- if (params)
- memcpy(new_client->internal->params, params, sizeof(*params));
+ status = (SilcStatus)packet->data[0];
- new_client->internal->params->
- nickname_format[sizeof(new_client->internal->
- params->nickname_format) - 1] = 0;
+ if (packet->len > 1 &&
+ silc_utf8_valid(packet->data + 1, packet->len - 1))
+ message = silc_memdup(packet->data + 1, packet->len - 1);
- silc_atomic_init16(&new_client->internal->conns, 0);
+ conn = (SilcClientConnection)sock->user_data;
+ if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
+ client->internal->ops->disconnected(client, conn, status, message);
- return new_client;
+ silc_free(message);
+
+ SILC_SET_DISCONNECTED(sock);
+
+ /* Close connection through scheduler. */
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_disconnected_by_server_later,
+ client, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
-/* Frees client object and its internals. */
+/* Received error message from server. Display it on the screen.
+ We don't take any action what so ever of the error message. */
-void silc_client_free(SilcClient client)
+void silc_client_error_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message)
{
- silc_schedule_uninit(client->schedule);
+ char *msg;
- if (client->rng)
- silc_rng_free(client->rng);
+ msg = silc_memdup(message->data, message->len);
+ client->internal->ops->say(client, sock->user_data,
+ SILC_CLIENT_MESSAGE_AUDIT, msg);
+ silc_free(msg);
+}
- if (!client->internal->params->dont_register_crypto_library) {
- silc_cipher_unregister_all();
- silc_pkcs_unregister_all();
- silc_hash_unregister_all();
- silc_hmac_unregister_all();
- }
+/* Auto-nicking callback to send NICK command to server. */
- silc_packet_engine_stop(client->internal->packet_engine);
- silc_dlist_uninit(client->internal->ftp_sessions);
- silc_atomic_uninit16(&client->internal->conns);
- silc_mutex_free(client->internal->lock);
- silc_free(client->username);
- silc_free(client->hostname);
- silc_free(client->realname);
- silc_free(client->internal->params);
- silc_free(client->internal->silc_client_version);
- silc_free(client->internal);
- silc_free(client);
+SILC_TASK_CALLBACK(silc_client_send_auto_nick)
+{
+ SilcClientConnection conn = (SilcClientConnection)context;
+ SilcClient client = conn->client;
+ if (client)
+ silc_client_command_send(client, conn, SILC_COMMAND_NICK,
+ ++conn->cmd_ident, 1, 1,
+ client->nickname, strlen(client->nickname));
}
-/* Initializes the client. This makes all the necessary steps to make
- the client ready to be run. One must call silc_client_run to run the
- client. Returns FALSE if error occured, TRUE otherwise. */
+/* Client session resuming callback. If the session was resumed
+ this callback is called after the resuming is completed. This
+ will call the `connect' client operation to the application
+ since it has not been called yet. */
-SilcBool silc_client_init(SilcClient client, const char *username,
- const char *hostname, const char *realname,
- SilcClientRunning running, void *context)
+static void silc_client_resume_session_cb(SilcClient client,
+ SilcClientConnection conn,
+ bool success,
+ void *context)
{
- SILC_LOG_DEBUG(("Initializing client"));
+ SilcBuffer sidp;
+
+ /* Notify application that connection is created to server */
+ client->internal->ops->connected(client, conn, success ?
+ SILC_CLIENT_CONN_SUCCESS_RESUME :
+ SILC_CLIENT_CONN_ERROR_RESUME);
+
+ if (success) {
+ /* Issue INFO command to fetch the real server name and server
+ information and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+ }
+}
- if (!client)
- return FALSE;
+/* Processes the received new Client ID from server. Old Client ID is
+ deleted from cache and new one is added. */
- if (!username || !hostname) {
- SILC_LOG_ERROR(("Username and hostname must be given to "
- "silc_client_init"));
- return FALSE;
- }
- if (!realname)
- realname = username;
+void silc_client_receive_new_id(SilcClient client,
+ SilcSocketConnection sock,
+ SilcIDPayload idp)
+{
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ int connecting = FALSE;
+ SilcClientID *client_id = silc_id_payload_get_id(idp);
+ char *nickname;
+
+ if (!conn->local_entry)
+ connecting = TRUE;
+
+ /* Delete old ID from ID cache */
+ if (conn->local_id) {
+ /* Check whether they are different */
+ if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
+ silc_free(client_id);
+ return;
+ }
- /* Validate essential strings */
- if (!silc_identifier_verify(username, strlen(username),
- SILC_STRING_UTF8, 128)) {
- SILC_LOG_ERROR(("Malformed username '%s'. Username must be UTF-8 string",
- client->username));
- return FALSE;
- }
- if (!silc_identifier_verify(hostname, strlen(hostname),
- SILC_STRING_UTF8, 256)) {
- SILC_LOG_ERROR(("Malformed hostname '%s'. Hostname must be UTF-8 string",
- client->hostname));
- return FALSE;
- }
- if (!silc_utf8_valid(realname, strlen(realname))) {
- SILC_LOG_ERROR(("Malformed realname '%s'. Realname must be UTF-8 string",
- client->realname));
- return FALSE;
+ silc_idcache_del_by_context(conn->internal->client_cache,
+ conn->local_entry);
+ silc_free(conn->local_id);
}
- /* Take the name strings */
- client->username = strdup(username);
- client->hostname = strdup(hostname);
- client->realname = strdup(realname);
- if (!username || !hostname || !realname)
- return FALSE;
+ /* Save the new ID */
+
+ if (conn->local_id_data)
+ silc_free(conn->local_id_data);
+
+ conn->local_id = client_id;
+ conn->local_id_data = silc_id_payload_get_data(idp);
+ conn->local_id_data_len = silc_id_payload_get_len(idp);;
+
+ if (!conn->local_entry)
+ conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
+
+ conn->local_entry->nickname = conn->nickname;
+ if (!conn->local_entry->username)
+ conn->local_entry->username = strdup(client->username);
+ if (!conn->local_entry->server)
+ conn->local_entry->server = strdup(conn->remote_host);
+ conn->local_entry->id = conn->local_id;
+ conn->local_entry->valid = TRUE;
+ if (!conn->local_entry->channels)
+ conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ TRUE);
+
+ /* Normalize nickname */
+ nickname = silc_identifier_check(conn->nickname, strlen(conn->nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nickname)
+ return;
+
+ /* Put it to the ID cache */
+ silc_idcache_add(conn->internal->client_cache, nickname, conn->local_id,
+ (void *)conn->local_entry, 0, NULL);
+
+ if (connecting) {
+ SilcBuffer sidp;
+
+ /* Issue IDENTIFY command for itself to get resolved hostname
+ correctly from server. */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 5, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+
+ if (!conn->internal->params.detach_data) {
+ /* Send NICK command if the nickname was set by the application (and is
+ not same as the username). Send this with little timeout. */
+ if (client->nickname &&
+ !silc_utf8_strcasecmp(client->nickname, client->username))
+ silc_schedule_task_add(client->schedule, 0,
+ silc_client_send_auto_nick, conn,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ /* Notify application of successful connection. We do it here now that
+ we've received the Client ID and are allowed to send traffic. */
+ client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
+
+ /* Issue INFO command to fetch the real server name and server
+ information and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+ } else {
+ /* We are resuming session. Start resolving informations from the
+ server we need to set the client libary in the state before
+ detaching the session. The connect client operation is called
+ after this is successfully completed */
+ silc_client_resume_session(client, conn, silc_client_resume_session_cb,
+ NULL);
+ }
+ }
+}
- client->internal->ftp_sessions = silc_dlist_init();
- if (!client->internal->ftp_sessions)
- return FALSE;
+/* Removes a client entry from all channels it has joined. */
- if (!client->internal->params->dont_register_crypto_library) {
- /* Initialize the crypto library. If application has done this already
- this has no effect. Also, we will not be overriding something
- application might have registered earlier. */
- silc_cipher_register_default();
- silc_pkcs_register_default();
- silc_hash_register_default();
- silc_hmac_register_default();
+void silc_client_remove_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+
+ silc_hash_table_list(client_entry->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ silc_hash_table_del(chu->client->channels, chu->channel);
+ silc_hash_table_del(chu->channel->user_list, chu->client);
+ silc_free(chu);
}
- /* Initialize random number generator */
- client->rng = silc_rng_alloc();
- if (!client->rng)
- return FALSE;
- silc_rng_init(client->rng);
- silc_rng_global_init(client->rng);
+ silc_hash_table_list_reset(&htl);
+}
- /* Initialize the scheduler */
- client->schedule = silc_schedule_init(0, client);
- if (!client->schedule)
- return FALSE;
+/* Replaces `old' client entries from all channels to `new' client entry.
+ This can be called for example when nickname changes and old ID entry
+ is replaced from ID cache with the new one. If the old ID entry is only
+ updated, then this fucntion needs not to be called. */
- /* Allocate client lock */
- silc_mutex_alloc(&client->internal->lock);
+void silc_client_replace_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry old,
+ SilcClientEntry new)
+{
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+
+ silc_hash_table_list(old->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ /* Replace client entry */
+ silc_hash_table_del(chu->client->channels, chu->channel);
+ silc_hash_table_del(chu->channel->user_list, chu->client);
+
+ chu->client = new;
+ silc_hash_table_add(chu->channel->user_list, chu->client, chu);
+ silc_hash_table_add(chu->client->channels, chu->channel, chu);
+ }
+ silc_hash_table_list_reset(&htl);
+}
- /* Register commands */
- silc_client_commands_register(client);
+/* Registers failure timeout to process the received failure packet
+ with timeout. */
- /* Start packet engine */
- client->internal->packet_engine =
- silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
- client);
- if (!client->internal->packet_engine)
- return FALSE;
+void silc_client_process_failure(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcUInt32 failure = 0;
- /* Initialize and start the client FSM */
- client->internal->running = running;
- client->internal->running_context = context;
- silc_fsm_init(&client->internal->fsm, client, NULL, NULL, client->schedule);
- silc_fsm_event_init(&client->internal->wait_event, &client->internal->fsm);
- silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
+ if (sock->protocol) {
+ if (packet->buffer->len >= 4)
+ SILC_GET32_MSB(failure, packet->buffer->data);
- /* Signal the application when we are running */
- client->internal->run_callback = TRUE;
- SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
+ /* Notify application */
+ client->internal->ops->failure(client, sock->user_data, sock->protocol,
+ SILC_32_TO_PTR(failure));
+ }
+}
- return TRUE;
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
+{
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcClient client = (SilcClient)conn->internal->rekey->context;
+ SilcProtocol protocol;
+ SilcClientRekeyInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* If rekey protocol is active already wait for it to finish */
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
+ return;
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = silc_socket_dup(sock);
+ proto_ctx->responder = FALSE;
+ proto_ctx->pfs = conn->internal->rekey->pfs;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
+ &protocol, proto_ctx, silc_client_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
}
-/* Starts the SILC client FSM machine and blocks here. When this returns
- the client has ended. */
+/* The final callback for the REKEY protocol. This will actually take the
+ new key material into use. */
-void silc_client_run(SilcClient client)
+SILC_TASK_CALLBACK(silc_client_rekey_final)
{
- SILC_LOG_DEBUG(("Starting SILC client"));
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcSocketConnection sock = ctx->sock;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ silc_protocol_cancel(protocol, client->schedule);
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_socket_free(ctx->sock);
+ silc_free(ctx);
+ return;
+ }
- /* Run the scheduler */
- silc_schedule(client->schedule);
+ /* Purge the outgoing data queue to assure that all rekey packets really
+ go to the network before we quit the protocol. */
+ silc_client_packet_queue_purge(client, sock);
+
+ /* Re-register re-key timeout */
+ if (ctx->responder == FALSE)
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_rekey_callback,
+ sock, conn->internal->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ /* Cleanup */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_socket_free(ctx->sock);
+ silc_free(ctx);
}
-/* Call scheduler one iteration and return. */
+/* Processes incoming connection authentication method request packet.
+ It is a reply to our previously sent request. The packet can be used
+ to resolve the authentication method for the current session if the
+ client does not know it beforehand. */
-void silc_client_run_one(SilcClient client)
+void silc_client_connection_auth_request(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- if (silc_fsm_is_started(&client->internal->fsm))
- silc_schedule_one(client->schedule, 0);
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcUInt16 conn_type, auth_meth;
+ int ret;
+
+ /* If we haven't send our request then ignore this one. */
+ if (!conn->internal->connauth)
+ return;
+
+ /* Parse the payload */
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI_SHORT(&conn_type),
+ SILC_STR_UI_SHORT(&auth_meth),
+ SILC_STR_END);
+ if (ret == -1)
+ auth_meth = SILC_AUTH_NONE;
+
+ /* Call the request callback to notify application for received
+ authentication method information. */
+ if (conn->internal->connauth->callback)
+ (*conn->internal->connauth->callback)(client, conn, auth_meth,
+ conn->internal->connauth->context);
+
+ silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
+
+ silc_free(conn->internal->connauth);
+ conn->internal->connauth = NULL;
}
-/* Stops the client. This is called to stop the client and thus to stop
- the program. */
+/* Timeout task callback called if the server does not reply to our
+ connection authentication method request in the specified time interval. */
-void silc_client_stop(SilcClient client, SilcClientStopped stopped,
- void *context)
+SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
{
- SILC_LOG_DEBUG(("Stopping client"));
+ SilcClientConnection conn = (SilcClientConnection)context;
+ SilcClient client = conn->client;
+
+ if (!conn->internal->connauth)
+ return;
- client->internal->running = (SilcClientRunning)stopped;
- client->internal->running_context = context;
+ /* Call the request callback to notify application */
+ if (conn->internal->connauth->callback)
+ (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
+ conn->internal->connauth->context);
- /* Signal to stop */
- client->internal->stop = TRUE;
- SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event);
+ silc_free(conn->internal->connauth);
+ conn->internal->connauth = NULL;
+}
+
+/* This function can be used to request the current authentication method
+ from the server. This may be called when connecting to the server
+ and the client library requests the authentication data from the
+ application. If the application does not know the current authentication
+ method it can request it from the server using this function.
+ The `callback' with `context' will be called after the server has
+ replied back with the current authentication method. */
+
+void
+silc_client_request_authentication_method(SilcClient client,
+ SilcClientConnection conn,
+ SilcConnectionAuthRequest callback,
+ void *context)
+{
+ SilcClientConnAuthRequest connauth;
+ SilcBuffer packet;
+
+ assert(client && conn);
+ connauth = silc_calloc(1, sizeof(*connauth));
+ connauth->callback = callback;
+ connauth->context = context;
+
+ if (conn->internal->connauth)
+ silc_free(conn->internal->connauth);
+
+ conn->internal->connauth = connauth;
+
+ /* Assemble the request packet and send it to the server */
+ packet = silc_buffer_alloc(4);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+ SILC_STR_UI_SHORT(SILC_AUTH_NONE),
+ SILC_STR_END);
+ silc_client_packet_send(client, conn->sock,
+ SILC_PACKET_CONNECTION_AUTH_REQUEST,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+
+ /* Register a timeout in case server does not reply anything back. */
+ connauth->timeout =
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
+ silc_client_request_authentication_method_timeout,
+ conn,
+ client->internal->params->connauth_request_secs, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/*
- client.h
+ client.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 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
#ifndef CLIENT_H
#define CLIENT_H
-#ifndef SILCCLIENT_H
-#error "Do not include this header directly"
-#endif
-
/* Forward declarations */
typedef struct SilcClientStruct *SilcClient;
typedef struct SilcClientConnectionStruct *SilcClientConnection;
+typedef struct SilcClientPingStruct SilcClientPing;
+typedef struct SilcClientAwayStruct SilcClientAway;
+typedef struct SilcClientKeyAgreementStruct *SilcClientKeyAgreement;
+typedef struct SilcClientFtpSessionStruct *SilcClientFtpSession;
typedef struct SilcClientEntryStruct *SilcClientEntry;
typedef struct SilcChannelEntryStruct *SilcChannelEntry;
typedef struct SilcServerEntryStruct *SilcServerEntry;
-
-typedef struct SilcClientKeyAgreementStruct *SilcClientKeyAgreement;
-typedef struct SilcClientFtpSessionStruct *SilcClientFtpSession;
+typedef struct SilcClientCommandStruct *SilcClientCommand;
+typedef struct SilcClientCommandContextStruct *SilcClientCommandContext;
typedef struct SilcClientCommandReplyContextStruct
*SilcClientCommandReplyContext;
typedef struct SilcChannelUserStruct *SilcChannelUser;
typedef struct SilcClientInternalStruct *SilcClientInternal;
-typedef struct SilcClientConnectionInternalStruct
- *SilcClientConnectionInternal;
+typedef struct SilcClientConnectionInternalStruct
+ *SilcClientConnectionInternal;
typedef struct SilcChannelPrivateKeyStruct *SilcChannelPrivateKey;
+
+/* Client entry status */
+typedef enum {
+ SILC_CLIENT_STATUS_NONE = 0x0000,
+ SILC_CLIENT_STATUS_RESOLVING = 0x0001,
+} SilcEntryStatus;
-/* Internal client entry context */
-typedef struct SilcClientEntryInternalStruct {
- SilcRwLock lock; /* Read/write lock */
- SilcCipher send_key; /* Private message key for sending */
- SilcCipher receive_key; /* Private message key for receiving */
- SilcHmac hmac_send; /* Private mesage key HMAC for sending */
- SilcHmac hmac_receive; /* Private mesage key HMAC for receiving */
- unsigned char *key; /* Valid if application provided the key */
- SilcUInt32 key_len; /* Key data length */
- SilcClientKeyAgreement ke; /* Current key agreement context or NULL */
-
- /* Flags */
- unsigned int valid : 1; /* FALSE if this entry is not valid. Entry
- without nickname is not valid. */
- unsigned int generated : 1; /* TRUE if library generated `key' */
- unsigned int prv_resp : 1; /* TRUE if we are responder when using
- private message keys. */
- SilcUInt16 resolve_cmd_ident; /* Command identifier when resolving */
- SilcAtomic8 refcnt; /* Reference counter */
-} SilcClientEntryInternal;
-
-/* Internal channel entry context */
-typedef struct SilcChannelEntryInternalStruct {
- SilcRwLock lock; /* Read/write lock */
-
- /* SilcChannelEntry status information */
- SilcDList old_channel_keys;
- SilcDList old_hmacs;
-
- /* Channel private keys */
- SilcDList private_keys; /* List of private keys or NULL */
- SilcChannelPrivateKey curr_key; /* Current private key */
-
- /* Channel keys */
- SilcCipher send_key; /* The channel key */
- SilcCipher receive_key; /* The channel key */
- SilcHmac hmac; /* Current HMAC */
- unsigned char iv[SILC_CIPHER_MAX_IV_SIZE]; /* Current IV */
-
- SilcUInt16 resolve_cmd_ident; /* Channel information resolving
- identifier. This is used when
- resolving users, and other
- stuff that relates to the
- channel. Not used for the
- channel resolving itself. */
- SilcAtomic16 refcnt; /* Reference counter */
-} SilcChannelEntryInternal;
-
-/* Internal server entry context */
-typedef struct SilcServerEntryInternalStruct {
- SilcRwLock lock; /* Read/write lock */
- SilcUInt16 resolve_cmd_ident; /* Resolving identifier */
- SilcAtomic8 refcnt; /* Reference counter */
-} SilcServerEntryInternal;
-
-#endif /* CLIENT_H */
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 Pekka Riikonen
+ Copyright (C) 2002 - 2004 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
SilcAttributePayload attr = context;
SilcAttrForeach *f = user_context;
const unsigned char *data;
- unsigned char tmp[32];
SilcUInt32 data_len;
if (!context) {
SILC_LOG_DEBUG(("Attribute %d found", attribute));
data = silc_attribute_get_data(attr, &data_len);
+#if 0
/* We replace the TIMEZONE with valid value here */
if (attribute == SILC_ATTRIBUTE_TIMEZONE) {
- if (silc_timezone(tmp, sizeof(tmp))) {
- data = tmp;
- data_len = strlen(tmp);
- f->buffer = silc_attribute_payload_encode(f->buffer, attribute,
- SILC_ATTRIBUTE_FLAG_VALID,
- (void *)data, data_len);
- }
+ data = (const unsigned char *)silc_get_time(0);
+ data_len = strlen(data);
+ f->buffer = silc_attribute_payload_encode(f->buffer, attribute,
+ SILC_ATTRIBUTE_FLAG_VALID,
+ (void *)data, data_len);
return;
}
+#endif
f->buffer = silc_attribute_payload_encode_data(f->buffer, attribute,
SILC_ATTRIBUTE_FLAG_VALID,
/* Process list of attributes. Returns reply to the requested attributes. */
SilcBuffer silc_client_attributes_process(SilcClient client,
- SilcClientConnection conn,
+ SilcSocketConnection sock,
SilcDList attrs)
{
+ SilcClientConnection conn = sock->user_data;
SilcBuffer buffer = NULL;
SilcAttrForeach f;
SilcAttribute attribute;
/* If nothing is set by application assume that we don't want to use
attributes, ignore the request. */
- if (!conn->internal->attrs) {
- SILC_LOG_DEBUG(("User has not set any attributes"));
+ if (!conn->internal->attrs)
return NULL;
- }
/* Always put our public key. */
pk.type = "silc-rsa";
- pk.data = silc_pkcs_public_key_encode(conn->public_key, &pk.data_len);
+ pk.data = silc_pkcs_public_key_encode(client->public_key, &pk.data_len);
buffer = silc_attribute_payload_encode(buffer,
SILC_ATTRIBUTE_USER_PUBLIC_KEY,
pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
buffer = f.buffer;
/* Finally compute the digital signature of all the data we provided. */
- if (silc_pkcs_sign(conn->private_key, silc_buffer_data(buffer),
- silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
- TRUE, conn->internal->sha1hash)) {
+ if (silc_pkcs_sign_with_hash(client->pkcs, client->sha1hash,
+ buffer->data, buffer->len,
+ sign, &sign_len)) {
pk.type = NULL;
pk.data = sign;
pk.data_len = sign_len;
/* Delete one attribute */
-SilcBool silc_client_attribute_del(SilcClient client,
- SilcClientConnection conn,
- SilcAttribute attribute,
- SilcAttributePayload attr)
+bool silc_client_attribute_del(SilcClient client,
+ SilcClientConnection conn,
+ SilcAttribute attribute,
+ SilcAttributePayload attr)
{
- SilcBool ret;
+ bool ret;
if (!conn->internal->attrs)
return FALSE;
if (!attribute)
return silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
- SILC_ATTRIBUTE_USER_ICON,
SILC_ATTRIBUTE_SERVICE,
SILC_ATTRIBUTE_STATUS_MOOD,
SILC_ATTRIBUTE_STATUS_FREETEXT,
SILC_ATTRIBUTE_TIMEZONE,
SILC_ATTRIBUTE_GEOLOCATION,
SILC_ATTRIBUTE_DEVICE_INFO,
- SILC_ATTRIBUTE_USER_PUBLIC_KEY, 0);
+ SILC_ATTRIBUTE_USER_PUBLIC_KEY,
+ SILC_ATTRIBUTE_USER_ICON, 0);
va_start(va, attribute);
while (attribute) {
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2004 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
*/
/* $Id$ */
+/* This file includes channel message sending and receiving routines,
+ channel key receiving and setting, and channel private key handling
+ routines. */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Channel Message Send ****************************/
+/* Sends packet to the `channel'. Packet to channel is always encrypted
+ differently from "normal" packets. SILC header of the packet is
+ encrypted with the next receiver's key and the rest of the packet is
+ encrypted with the channel specific key. Padding and HMAC is computed
+ with the next receiver's key. The `data' is the channel message. If
+ the `force_send' is TRUE then the packet is sent immediately. */
-/* Sends channel message to `channel'. */
-
-SilcBool silc_client_send_channel_message(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcChannelPrivateKey key,
- SilcMessageFlags flags,
- SilcHash hash,
- unsigned char *data,
- SilcUInt32 data_len)
+bool silc_client_send_channel_message(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcChannelPrivateKey key,
+ SilcMessageFlags flags,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send)
{
- SilcChannelUser chu;
- SilcBuffer buffer;
+ SilcSocketConnection sock;
+ SilcBuffer payload;
+ SilcPacketContext packetdata;
+ const SilcBufferStruct packet;
SilcCipher cipher;
SilcHmac hmac;
- SilcBool ret;
- SilcID sid, rid;
-
- SILC_LOG_DEBUG(("Sending channel message"));
+ unsigned char *id_string;
+ int block_len;
+ SilcChannelUser chu;
+ bool ret = FALSE;
- if (silc_unlikely(!client || !conn || !channel))
- return FALSE;
- if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
- return FALSE;
- if (silc_unlikely(conn->internal->disconnected))
- return FALSE;
+ assert(client && conn && channel);
+ sock = conn->sock;
+ SILC_LOG_DEBUG(("Sending packet to channel"));
chu = silc_client_on_channel(channel, conn->local_entry);
- if (silc_unlikely(!chu)) {
- client->internal->ops->say(conn->client, conn,
- SILC_CLIENT_MESSAGE_AUDIT,
- "Cannot talk to channel: not joined");
+ if (!chu) {
+ SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
return FALSE;
}
/* Check if it is allowed to send messages to this channel by us. */
- if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
- !chu->mode))
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
return FALSE;
- if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
- chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
- !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
+ chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
+ !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
return FALSE;
- if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
+ if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
return FALSE;
/* Take the key to be used */
- if (channel->internal.private_keys) {
+ if (channel->private_keys) {
if (key) {
/* Use key application specified */
cipher = key->cipher;
hmac = key->hmac;
} else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
- channel->internal.curr_key) {
+ channel->curr_key) {
/* Use current private key */
- cipher = channel->internal.curr_key->cipher;
- hmac = channel->internal.curr_key->hmac;
+ cipher = channel->curr_key->cipher;
+ hmac = channel->curr_key->hmac;
} else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
- !channel->internal.curr_key &&
- channel->internal.private_keys) {
+ !channel->curr_key && channel->private_keys) {
/* Use just some private key since we don't know what to use
and private keys are set. */
- silc_dlist_start(channel->internal.private_keys);
- key = silc_dlist_get(channel->internal.private_keys);
+ silc_dlist_start(channel->private_keys);
+ key = silc_dlist_get(channel->private_keys);
cipher = key->cipher;
hmac = key->hmac;
/* Use this key as current private key */
- channel->internal.curr_key = key;
+ channel->curr_key = key;
} else {
/* Use normal channel key generated by the server */
- cipher = channel->internal.send_key;
- hmac = channel->internal.hmac;
+ cipher = channel->channel_key;
+ hmac = channel->hmac;
}
} else {
/* Use normal channel key generated by the server */
- cipher = channel->internal.send_key;
- hmac = channel->internal.hmac;
+ cipher = channel->channel_key;
+ hmac = channel->hmac;
}
- if (silc_unlikely(!cipher || !hmac)) {
+ if (!cipher || !hmac) {
SILC_LOG_ERROR(("No cipher and HMAC for channel"));
return FALSE;
}
+ block_len = silc_cipher_get_block_len(cipher);
+
/* Encode the message payload. This also encrypts the message payload. */
- sid.type = SILC_ID_CLIENT;
- sid.u.client_id = chu->client->id;
- rid.type = SILC_ID_CHANNEL;
- rid.u.channel_id = chu->channel->id;
- buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
- cipher, hmac, client->rng, NULL,
- conn->private_key, hash, &sid, &rid,
- NULL);
- if (silc_unlikely(!buffer)) {
+ payload = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
+ cipher, hmac, client->rng, NULL,
+ client->private_key, client->sha1hash);
+ if (!payload) {
SILC_LOG_ERROR(("Error encoding channel message"));
return FALSE;
}
- /* Send the channel message */
- ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
- 0, NULL, SILC_ID_CHANNEL, &channel->id,
- silc_buffer_datalen(buffer), NULL, NULL);
+ /* Get data used in packet header encryption, keys and stuff. */
+ cipher = conn->internal->send_key;
+ hmac = conn->internal->hmac_send;
+ id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+
+ /* Set the packet context pointers. The destination ID is always
+ the Channel ID of the channel. Server and router will handle the
+ distribution of the packet. */
+ data = payload->data;
+ data_len = payload->len;
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+ packetdata.src_id = conn->local_id_data;
+ packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
+ packetdata.src_id_type = SILC_ID_CLIENT;
+ packetdata.dst_id = id_string;
+ packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+ packetdata.dst_id_type = SILC_ID_CHANNEL;
+ data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len);
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len), block_len, packetdata.padlen);
+
+ /* Create the outgoing packet */
+ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
+ data, data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Error assembling packet"));
+ goto out;
+ }
+
+ /* Encrypt the header and padding of the packet. This is encrypted
+ with normal session key shared with our server. */
+ silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
+ (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ SILC_LOG_HEXDUMP(("Packet to channel, len %d", packet.len),
+ packet.data, packet.len);
+
+ /* Now actually send the packet */
+ silc_client_packet_send_real(client, sock, force_send);
+
+ /* Check for mandatory rekey */
+ if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_rekey_callback, sock, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ ret = TRUE;
+
+ out:
+ silc_buffer_free(payload);
+ silc_free(id_string);
- silc_buffer_free(buffer);
return ret;
}
-/************************* Channel Message Receive **************************/
+typedef struct {
+ SilcMessagePayload payload;
+ SilcChannelID *channel_id;
+ SilcChannelPrivateKey key;
+} *SilcChannelClientResolve;
+
+static void silc_client_channel_message_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
+ void *context)
+{
+ SilcChannelClientResolve res = (SilcChannelClientResolve)context;
+
+ if (clients_count == 1) {
+ SilcChannelEntry channel;
+ unsigned char *message;
+ SilcUInt32 message_len;
+
+ channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
+ if (!channel)
+ goto out;
+
+ /* If this client is not on channel, add it there since it clearly
+ is there. */
+ if (!silc_client_on_channel(channel, clients[0])) {
+ SilcChannelUser chu = silc_calloc(1, sizeof(*chu));
+ chu->client = clients[0];
+ chu->channel = channel;
+ silc_hash_table_add(channel->user_list, clients[0], chu);
+ silc_hash_table_add(clients[0]->channels, channel, chu);
+ }
-/* Client resolving callback. Continues with the channel message processing */
+ message = silc_message_get_data(res->payload, &message_len);
-static void silc_client_channel_message_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- /* If no client found, ignore the channel message, a silent error */
- if (!clients)
- silc_fsm_next(context, silc_client_channel_message_error);
+ /* Pass the message to application */
+ client->internal->ops->channel_message(
+ client, conn, clients[0], channel, res->payload,
+ res->key, silc_message_get_flags(res->payload),
+ message, message_len);
+ }
- /* Continue processing the channel message packet */
- SILC_FSM_CALL_CONTINUE(context);
+ out:
+ silc_message_payload_free(res->payload);
+ silc_free(res->channel_id);
+ silc_free(res);
}
-/* Process received channel message */
+/* Process received message to a channel (or from a channel, really). This
+ decrypts the channel message with channel specific key and parses the
+ message payload. Finally it displays the message on the screen. */
-SILC_FSM_STATE(silc_client_channel_message)
+void silc_client_channel_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcBuffer buffer = &packet->buffer;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcBuffer buffer = packet->buffer;
SilcMessagePayload payload = NULL;
+ SilcChannelID *id = NULL;
SilcChannelEntry channel;
SilcClientEntry client_entry;
- SilcClientID remote_id;
- SilcChannelID channel_id;
+ SilcClientID *client_id = NULL;
unsigned char *message;
SilcUInt32 message_len;
SilcChannelPrivateKey key = NULL;
SILC_LOG_DEBUG(("Received channel message"));
- SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
- silc_buffer_len(buffer));
-
- if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
- /** Invalid packet */
- silc_fsm_next(fsm, silc_client_channel_message_error);
- return SILC_FSM_CONTINUE;
- }
-
- if (silc_unlikely(!silc_id_str2id(packet->src_id,
- packet->src_id_len, SILC_ID_CLIENT,
- &remote_id, sizeof(remote_id)))) {
- /** Invalid source ID */
- silc_fsm_next(fsm, silc_client_channel_message_error);
- return SILC_FSM_CONTINUE;
- }
+ /* Sanity checks */
+ if (packet->dst_id_type != SILC_ID_CHANNEL)
+ goto out;
- /* Get sender client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
- if (!client_entry || !client_entry->internal.valid) {
- /** Resolve client info */
- silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &remote_id, NULL,
- silc_client_channel_message_resolved,
- fsm));
- /* NOT REACHED */
- }
+ client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!client_id)
+ goto out;
+ id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
+ if (!id)
+ goto out;
- if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
- SILC_ID_CHANNEL, &channel_id,
- sizeof(channel_id)))) {
- /** Invalid destination ID */
- silc_fsm_next(fsm, silc_client_channel_message_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Find the channel */
- channel = silc_client_get_channel_by_id(client, conn, &channel_id);
- if (silc_unlikely(!channel)) {
- /** Unknown channel */
- silc_fsm_next(fsm, silc_client_channel_message_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Check that user is on channel */
- if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
- /** User not on channel */
- SILC_LOG_WARNING(("Message from user not on channel, client or "
- "server bug"));
- silc_fsm_next(fsm, silc_client_channel_message_error);
- return SILC_FSM_CONTINUE;
- }
+ /* Find the channel entry from channels on this connection */
+ channel = silc_client_get_channel_by_id(client, conn, id);
+ if (!channel)
+ goto out;
/* If there is no channel private key then just decrypt the message
with the channel key. If private keys are set then just go through
all private keys and check what decrypts correctly. */
- if (!channel->internal.private_keys) {
+ if (!channel->private_keys) {
/* Parse the channel message payload. This also decrypts the payload */
- payload = silc_message_payload_parse(silc_buffer_data(buffer),
- silc_buffer_len(buffer), FALSE,
- FALSE, channel->internal.receive_key,
- channel->internal.hmac,
- packet->src_id, packet->src_id_len,
- packet->dst_id, packet->dst_id_len,
- NULL, FALSE, NULL);
+ payload = silc_message_payload_parse(buffer->data, buffer->len, FALSE,
+ FALSE, channel->channel_key,
+ channel->hmac);
/* If decryption failed and we have just performed channel key rekey
we will use the old key in decryption. If that fails too then we
cannot do more and will drop the packet. */
- if (silc_unlikely(!payload)) {
- SilcCipher cipher;
+ if (!payload) {
+ SilcCipher key;
SilcHmac hmac;
+ int i;
- if (!channel->internal.old_channel_keys ||
- !silc_dlist_count(channel->internal.old_channel_keys))
+ if (!channel->old_channel_keys ||
+ !silc_dlist_count(channel->old_channel_keys))
goto out;
SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
- silc_dlist_end(channel->internal.old_channel_keys);
- silc_dlist_end(channel->internal.old_hmacs);
- while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
- hmac = silc_dlist_get(channel->internal.old_hmacs);
- if (!hmac)
+ silc_dlist_end(channel->old_channel_keys);
+ silc_dlist_end(channel->old_hmacs);
+ for (i = 0; i < silc_dlist_count(channel->old_channel_keys); i++) {
+ key = silc_dlist_get(channel->old_channel_keys);
+ hmac = silc_dlist_get(channel->old_hmacs);
+ if (!key || !hmac)
break;
- payload = silc_message_payload_parse(silc_buffer_data(buffer),
- silc_buffer_len(buffer),
- FALSE, FALSE, cipher, hmac,
- packet->src_id,
- packet->src_id_len,
- packet->dst_id,
- packet->dst_id_len,
- NULL, FALSE, NULL);
+ payload = silc_message_payload_parse(buffer->data, buffer->len,
+ FALSE, FALSE, key, hmac);
if (payload)
break;
}
goto out;
}
} else {
- /* If the private key mode is not set on the channel then try the actual
- channel key first before trying private keys. */
+ /* If the private key mode, however is not set on the channel then
+ try the actual channel key first before trying private keys. */
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
- payload = silc_message_payload_parse(silc_buffer_data(buffer),
- silc_buffer_len(buffer),
- FALSE, FALSE,
- channel->internal.receive_key,
- channel->internal.hmac,
- packet->src_id,
- packet->src_id_len,
- packet->dst_id,
- packet->dst_id_len,
- NULL, FALSE, NULL);
+ payload = silc_message_payload_parse(buffer->data, buffer->len, FALSE,
+ FALSE, channel->channel_key,
+ channel->hmac);
if (!payload) {
- silc_dlist_start(channel->internal.private_keys);
- while ((key = silc_dlist_get(channel->internal.private_keys))) {
+ silc_dlist_start(channel->private_keys);
+ while ((key = silc_dlist_get(channel->private_keys))
+ != SILC_LIST_END) {
/* Parse the message payload. This also decrypts the payload */
- payload = silc_message_payload_parse(silc_buffer_data(buffer),
- silc_buffer_len(buffer),
- FALSE, FALSE, key->cipher,
- key->hmac, packet->src_id,
- packet->src_id_len,
- packet->dst_id,
- packet->dst_id_len,
- NULL, FALSE, NULL);
+ payload = silc_message_payload_parse(buffer->data, buffer->len,
+ FALSE, FALSE,
+ key->cipher, key->hmac);
if (payload)
break;
}
}
}
+ /* Find client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry || !client_entry->nickname ||
+ !silc_client_on_channel(channel, client_entry)) {
+ /* Resolve the client info */
+ SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
+ res->payload = payload;
+ res->channel_id = id;
+ res->key = key;
+ silc_client_get_client_by_id_resolve(client, conn, client_id, NULL,
+ silc_client_channel_message_cb,
+ res);
+ payload = NULL;
+ id = NULL;
+ goto out;
+ }
+
message = silc_message_get_data(payload, &message_len);
/* Pass the message to application */
message, message_len);
out:
- silc_client_unref_client(client, conn, client_entry);
- silc_client_unref_channel(client, conn, channel);
+ silc_free(id);
+ silc_free(client_id);
if (payload)
silc_message_payload_free(payload);
- return SILC_FSM_FINISH;
-}
-
-/* Channel message error. */
-
-SILC_FSM_STATE(silc_client_channel_message_error)
-{
- SilcPacket packet = state_context;
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
}
-/******************************* Channel Key ********************************/
-
/* Timeout callback that is called after a short period of time after the
new channel key has been created. This removes the first channel key
in the list. */
SilcCipher key;
SilcHmac hmac;
- if (channel->internal.old_channel_keys) {
- silc_dlist_start(channel->internal.old_channel_keys);
- key = silc_dlist_get(channel->internal.old_channel_keys);
+ if (channel->old_channel_keys) {
+ silc_dlist_start(channel->old_channel_keys);
+ key = silc_dlist_get(channel->old_channel_keys);
if (key) {
- silc_dlist_del(channel->internal.old_channel_keys, key);
+ silc_dlist_del(channel->old_channel_keys, key);
silc_cipher_free(key);
}
}
- if (channel->internal.old_hmacs) {
- silc_dlist_start(channel->internal.old_hmacs);
- hmac = silc_dlist_get(channel->internal.old_hmacs);
+ if (channel->old_hmacs) {
+ silc_dlist_start(channel->old_hmacs);
+ hmac = silc_dlist_get(channel->old_hmacs);
if (hmac) {
- silc_dlist_del(channel->internal.old_hmacs, hmac);
+ silc_dlist_del(channel->old_hmacs, hmac);
silc_hmac_free(hmac);
}
}
}
-/* Saves channel key from encoded `key_payload'. This is used when we receive
- Channel Key Payload and when we are processing JOIN command reply. */
+/* Saves channel key from encoded `key_payload'. This is used when we
+ receive Channel Key Payload and when we are processing JOIN command
+ reply. */
-SilcBool silc_client_save_channel_key(SilcClient client,
- SilcClientConnection conn,
- SilcBuffer key_payload,
- SilcChannelEntry channel)
+void silc_client_save_channel_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcBuffer key_payload,
+ SilcChannelEntry channel)
{
unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
SilcUInt32 tmp_len;
- SilcChannelID id;
+ SilcChannelID *id;
SilcChannelKeyPayload payload;
- SILC_LOG_DEBUG(("New channel key"));
-
- payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
- silc_buffer_len(key_payload));
+ payload = silc_channel_key_payload_parse(key_payload->data,
+ key_payload->len);
if (!payload)
- return FALSE;
+ return;
id_string = silc_channel_key_get_id(payload, &tmp_len);
if (!id_string) {
silc_channel_key_payload_free(payload);
- return FALSE;
+ return;
}
- if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
+ id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
+ if (!id) {
silc_channel_key_payload_free(payload);
- return FALSE;
+ return;
}
/* Find channel. */
if (!channel) {
- channel = silc_client_get_channel_by_id(client, conn, &id);
- if (!channel) {
- SILC_LOG_DEBUG(("Key for unknown channel"));
- silc_channel_key_payload_free(payload);
- return FALSE;
- }
- } else {
- silc_client_ref_channel(client, conn, channel);
+ channel = silc_client_get_channel_by_id(client, conn, id);
+ if (!channel)
+ goto out;
}
+ hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) :
+ SILC_DEFAULT_HMAC);
+
/* Save the old key for a short period of time so that we can decrypt
channel message even after the rekey if some client would be sending
messages with the old key after the rekey. */
- if (!channel->internal.old_channel_keys)
- channel->internal.old_channel_keys = silc_dlist_init();
- if (!channel->internal.old_hmacs)
- channel->internal.old_hmacs = silc_dlist_init();
- if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
- silc_dlist_add(channel->internal.old_channel_keys,
- channel->internal.receive_key);
- silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
- silc_schedule_task_add_timeout(client->schedule,
- silc_client_save_channel_key_rekey,
- channel, 15, 0);
- }
+ if (!channel->old_channel_keys)
+ channel->old_channel_keys = silc_dlist_init();
+ if (!channel->old_hmacs)
+ channel->old_hmacs = silc_dlist_init();
+ silc_dlist_add(channel->old_channel_keys, channel->channel_key);
+ silc_dlist_add(channel->old_hmacs, channel->hmac);
+ silc_schedule_task_add(client->schedule, 0,
+ silc_client_save_channel_key_rekey, channel,
+ 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ /* Free the old channel key data */
+ silc_free(channel->key);
- /* Get channel cipher */
+ /* Save the key */
+ key = silc_channel_key_get_key(payload, &tmp_len);
cipher = silc_channel_key_get_cipher(payload, NULL);
- if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
- client->internal->ops->say(
- conn->client, conn,
- SILC_CLIENT_MESSAGE_AUDIT,
- "Cannot talk to channel: unsupported cipher %s",
- cipher);
- silc_client_unref_channel(client, conn, channel);
- silc_channel_key_payload_free(payload);
- return FALSE;
- }
- if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
+ channel->key_len = tmp_len * 8;
+ channel->key = silc_memdup(key, tmp_len);
+
+ if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
client->internal->ops->say(
conn->client, conn,
SILC_CLIENT_MESSAGE_AUDIT,
"Cannot talk to channel: unsupported cipher %s",
cipher);
- silc_client_unref_channel(client, conn, channel);
- silc_channel_key_payload_free(payload);
- return FALSE;
+ goto out;
}
- /* Set the cipher key. Both sending and receiving keys are same */
- key = silc_channel_key_get_key(payload, &tmp_len);
- silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
- silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);
+ /* Set the cipher key */
+ silc_cipher_set_key(channel->channel_key, key, channel->key_len);
- /* Get channel HMAC */
- hmac = (channel->internal.hmac ?
- (char *)silc_hmac_get_name(channel->internal.hmac) :
- SILC_DEFAULT_HMAC);
- if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
- client->internal->ops->say(
- conn->client, conn,
- SILC_CLIENT_MESSAGE_AUDIT,
- "Cannot talk to channel: unsupported HMAC %s",
- hmac);
- silc_client_unref_channel(client, conn, channel);
- silc_channel_key_payload_free(payload);
- return FALSE;
- }
-
- /* Set HMAC key */
- silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
- tmp_len, hash);
- silc_hmac_set_key(channel->internal.hmac, hash,
- silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
+ /* Generate HMAC key from the channel key data and set it */
+ silc_hmac_alloc(hmac, NULL, &channel->hmac);
+ silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
memset(hash, 0, sizeof(hash));
- silc_channel_key_payload_free(payload);
-
- silc_client_unref_channel(client, conn, channel);
- return TRUE;
+ out:
+ silc_free(id);
+ silc_channel_key_payload_free(payload);
}
-/* Received channel key packet. The key will replace old channel key. */
+/* Processes received key for channel. The received key will be used
+ to protect the traffic on the channel for now on. Client must receive
+ the key to the channel before talking on the channel is possible.
+ This is the key that server has generated, this is not the channel
+ private key, it is entirely local setting. */
-SILC_FSM_STATE(silc_client_channel_key)
+void silc_client_receive_channel_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
-
- SILC_LOG_DEBUG(("Received channel key"));
+ SILC_LOG_DEBUG(("Received key for channel"));
/* Save the key */
- silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
- silc_packet_free(packet);
-
- return SILC_FSM_FINISH;
+ silc_client_save_channel_key(client, sock->user_data, packet, NULL);
}
-/**************************** Channel Private Key ***************************/
-
-/* Add new channel private key */
-
-SilcBool silc_client_add_channel_private_key(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- const char *name,
- char *cipher,
- char *hmac,
- unsigned char *key,
- SilcUInt32 key_len,
- SilcChannelPrivateKey *ret_key)
+/* Adds private key for channel. When channel has private key then the
+ messages are encrypted using that key. All clients on the channel must
+ also know the key in order to decrypt the messages. However, it is
+ possible to have several private keys per one channel. In this case
+ only some of the clients on the channel may know the one key and only
+ some the other key.
+
+ If `cipher' and/or `hmac' is NULL then default values will be used
+ (aes-256-cbc for cipher and hmac-sha1-96 for hmac).
+
+ The private key for channel is optional. If it is not set then the
+ channel messages are encrypted using the channel key generated by the
+ server. However, setting the private key (or keys) for the channel
+ significantly adds security. If more than one key is set the library
+ will automatically try all keys at the message decryption phase. Note:
+ setting many keys slows down the decryption phase as all keys has to
+ be tried in order to find the correct decryption key. However, setting
+ a few keys does not have big impact to the decryption performace.
+
+ NOTE: that this is entirely local setting. The key set using this function
+ is not sent to the network at any phase.
+
+ NOTE: If the key material was originated by the SKE protocol (using
+ silc_client_send_key_agreement) then the `key' MUST be the
+ key->send_enc_key as this is dictated by the SILC protocol. However,
+ currently it is not expected that the SKE key material would be used
+ as channel private key. However, this API allows it. */
+
+bool silc_client_add_channel_private_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ const char *name,
+ char *cipher,
+ char *hmac,
+ unsigned char *key,
+ SilcUInt32 key_len,
+ SilcChannelPrivateKey *ret_key)
{
SilcChannelPrivateKey entry;
unsigned char hash[SILC_HASH_MAXLEN];
- SilcSKEKeyMaterial keymat;
+ SilcSKEKeyMaterial *keymat;
- if (!client || !conn || !channel)
- return FALSE;
+ assert(client && channel);
if (!cipher)
cipher = SILC_DEFAULT_CIPHER;
if (!silc_cipher_is_supported(cipher))
return FALSE;
+
if (!silc_hmac_is_supported(hmac))
return FALSE;
- if (!channel->internal.private_keys) {
- channel->internal.private_keys = silc_dlist_init();
- if (!channel->internal.private_keys)
- return FALSE;
- }
-
/* Produce the key material */
- keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
- conn->internal->sha1hash);
- if (!keymat)
+ keymat = silc_calloc(1, sizeof(*keymat));
+ if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
+ client->sha1hash, keymat)
+ != SILC_SKE_STATUS_OK)
return FALSE;
+ if (!channel->private_keys)
+ channel->private_keys = silc_dlist_init();
+
/* Save the key */
entry = silc_calloc(1, sizeof(*entry));
- if (!entry) {
- silc_ske_free_key_material(keymat);
- return FALSE;
- }
entry->name = name ? strdup(name) : NULL;
+ entry->key = silc_memdup(keymat->send_enc_key, keymat->enc_key_len / 8);
+ entry->key_len = keymat->enc_key_len / 8;
- /* Allocate the cipher and set the key */
- if (!silc_cipher_alloc(cipher, &entry->cipher)) {
- silc_free(entry);
- silc_free(entry->name);
- silc_ske_free_key_material(keymat);
- return FALSE;
- }
- silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
- keymat->enc_key_len, TRUE);
+ /* Allocate the cipher and set the key*/
+ silc_cipher_alloc(cipher, &entry->cipher);
+ silc_cipher_set_key(entry->cipher, entry->key, keymat->enc_key_len);
/* Generate HMAC key from the channel key data and set it */
- if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
- silc_free(entry);
- silc_free(entry->name);
- silc_cipher_free(entry->cipher);
- silc_ske_free_key_material(keymat);
- return FALSE;
- }
- silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
- keymat->enc_key_len / 8, hash);
+ silc_hmac_alloc(hmac, NULL, &entry->hmac);
+ silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key,
+ entry->key_len, hash);
silc_hmac_set_key(entry->hmac, hash,
silc_hash_len(silc_hmac_get_hash(entry->hmac)));
memset(hash, 0, sizeof(hash));
/* Add to the private keys list */
- silc_dlist_add(channel->internal.private_keys, entry);
+ silc_dlist_add(channel->private_keys, entry);
- if (!channel->internal.curr_key)
- channel->internal.curr_key = entry;
+ if (!channel->curr_key)
+ channel->curr_key = entry;
/* Free the key material */
silc_ske_free_key_material(keymat);
after calling this to protect the channel messages. Returns FALSE on
on error, TRUE otherwise. */
-SilcBool silc_client_del_channel_private_keys(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel)
+bool silc_client_del_channel_private_keys(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel)
{
SilcChannelPrivateKey entry;
- if (!client || !conn || !channel)
- return FALSE;
+ assert(client && channel);
- if (!channel->internal.private_keys)
+ if (!channel->private_keys)
return FALSE;
- silc_dlist_start(channel->internal.private_keys);
- while ((entry = silc_dlist_get(channel->internal.private_keys))) {
- silc_dlist_del(channel->internal.private_keys, entry);
+ silc_dlist_start(channel->private_keys);
+ while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
+ silc_dlist_del(channel->private_keys, entry);
+ memset(entry->key, 0, entry->key_len);
+ silc_free(entry->key);
silc_free(entry->name);
silc_cipher_free(entry->cipher);
silc_hmac_free(entry->hmac);
silc_free(entry);
}
- channel->internal.curr_key = NULL;
+ channel->curr_key = NULL;
- silc_dlist_uninit(channel->internal.private_keys);
- channel->internal.private_keys = NULL;
+ silc_dlist_uninit(channel->private_keys);
+ channel->private_keys = NULL;
return TRUE;
}
old channel key is used hereafter to protect the channel messages. This
returns FALSE on error, TRUE otherwise. */
-SilcBool silc_client_del_channel_private_key(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcChannelPrivateKey key)
+bool silc_client_del_channel_private_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcChannelPrivateKey key)
{
SilcChannelPrivateKey entry;
- if (!client || !conn || !channel)
- return FALSE;
+ assert(client && channel);
- if (!channel->internal.private_keys)
+ if (!channel->private_keys)
return FALSE;
- silc_dlist_start(channel->internal.private_keys);
- while ((entry = silc_dlist_get(channel->internal.private_keys))) {
- if (entry != key)
- continue;
-
- if (channel->internal.curr_key == entry)
- channel->internal.curr_key = NULL;
-
- silc_dlist_del(channel->internal.private_keys, entry);
- silc_free(entry->name);
- silc_cipher_free(entry->cipher);
- silc_hmac_free(entry->hmac);
- silc_free(entry);
+ silc_dlist_start(channel->private_keys);
+ while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
+ if (entry == key) {
+ if (channel->curr_key == entry)
+ channel->curr_key = NULL;
+
+ silc_dlist_del(channel->private_keys, entry);
+ memset(entry->key, 0, entry->key_len);
+ silc_free(entry->key);
+ silc_free(entry->name);
+ silc_cipher_free(entry->cipher);
+ silc_hmac_free(entry->hmac);
+ silc_free(entry);
+
+ if (silc_dlist_count(channel->private_keys) == 0) {
+ silc_dlist_uninit(channel->private_keys);
+ channel->private_keys = NULL;
+ }
- if (silc_dlist_count(channel->internal.private_keys) == 0) {
- silc_dlist_uninit(channel->internal.private_keys);
- channel->internal.private_keys = NULL;
+ return TRUE;
}
-
- return TRUE;
}
return FALSE;
used to delete the specific key by giving the pointer as argument to the
function silc_client_del_channel_private_key. */
-SilcDList silc_client_list_channel_private_keys(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel)
+SilcChannelPrivateKey *
+silc_client_list_channel_private_keys(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcUInt32 *key_count)
{
- SilcChannelPrivateKey entry;
- SilcDList list;
+ SilcChannelPrivateKey *keys = NULL, entry;
+ SilcUInt32 count = 0;
- if (!client || !conn || !channel)
- return FALSE;
+ assert(client && channel);
- if (!channel->internal.private_keys)
+ if (!channel->private_keys)
return NULL;
- list = silc_dlist_init();
- if (!list)
- return NULL;
+ silc_dlist_start(channel->private_keys);
+ while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
+ keys = silc_realloc(keys, sizeof(*keys) * (count + 1));
+ keys[count] = entry;
+ count++;
+ }
- silc_dlist_start(channel->internal.private_keys);
- while ((entry = silc_dlist_get(channel->internal.private_keys)))
- silc_dlist_add(list, entry);
+ if (key_count)
+ *key_count = count;
- return list;
+ return keys;
+}
+
+/* Frees the SilcChannelPrivateKey array. */
+
+void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
+ SilcUInt32 key_count)
+{
+ silc_free(keys);
}
/* Sets the `key' to be used as current channel private key on the
SilcChannelEntry channel,
SilcChannelPrivateKey key)
{
- if (!channel)
- return;
- channel->internal.curr_key = key;
+ assert(client && channel);
+ channel->curr_key = key;
}
-/***************************** Utility routines *****************************/
-
/* Returns the SilcChannelUser entry if the `client_entry' is joined on the
channel indicated by the `channel'. NULL if client is not joined on
the channel. */
return NULL;
}
-
-/* Adds client to channel. Returns TRUE if user was added or is already
- added to the channel, FALSE on error. Must be called with both `channel'
- and `client_entry' locked. */
-
-SilcBool silc_client_add_to_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcClientEntry client_entry,
- SilcUInt32 cumode)
-{
- SilcChannelUser chu;
-
- if (silc_client_on_channel(channel, client_entry))
- return TRUE;
-
- SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
-
- chu = silc_calloc(1, sizeof(*chu));
- if (!chu)
- return FALSE;
-
- chu->client = client_entry;
- chu->channel = channel;
- chu->mode = cumode;
-
- silc_client_ref_client(client, conn, client_entry);
- silc_client_ref_channel(client, conn, channel);
-
- silc_hash_table_add(channel->user_list, client_entry, chu);
- silc_hash_table_add(client_entry->channels, channel, chu);
-
- return TRUE;
-}
-
-/* Removes client from a channel. Returns FALSE if user is not on channel.
- This handles entry locking internally. */
-
-SilcBool silc_client_remove_from_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcClientEntry client_entry)
-{
- SilcChannelUser chu;
-
- chu = silc_client_on_channel(channel, client_entry);
- if (!chu)
- return FALSE;
-
- SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
-
- silc_rwlock_wrlock(client_entry->internal.lock);
- silc_rwlock_wrlock(channel->internal.lock);
-
- silc_hash_table_del(chu->client->channels, chu->channel);
- silc_hash_table_del(chu->channel->user_list, chu->client);
- silc_free(chu);
-
- /* If channel became empty, delete it */
- if (!silc_hash_table_count(channel->user_list))
- silc_client_del_channel(client, conn, channel);
-
- silc_rwlock_unlock(client_entry->internal.lock);
- silc_rwlock_unlock(channel->internal.lock);
-
- silc_client_unref_client(client, conn, client_entry);
- silc_client_unref_channel(client, conn, channel);
-
- return TRUE;
-}
-
-/* Removes a client entry from all channels it has joined. This handles
- entry locking internally. */
-
-void silc_client_remove_from_channels(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry)
-{
- SilcHashTableList htl;
- SilcChannelUser chu;
-
- if (!silc_hash_table_count(client_entry->channels))
- return;
-
- SILC_LOG_DEBUG(("Remove client from all joined channels"));
-
- silc_rwlock_wrlock(client_entry->internal.lock);
-
- silc_hash_table_list(client_entry->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
- silc_rwlock_wrlock(chu->channel->internal.lock);
-
- silc_hash_table_del(chu->client->channels, chu->channel);
- silc_hash_table_del(chu->channel->user_list, chu->client);
-
- /* If channel became empty, delete it */
- if (!silc_hash_table_count(chu->channel->user_list))
- silc_client_del_channel(client, conn, chu->channel);
-
- silc_rwlock_unlock(chu->channel->internal.lock);
-
- silc_client_unref_client(client, conn, chu->client);
- silc_client_unref_channel(client, conn, chu->channel);
- silc_free(chu);
- }
-
- silc_rwlock_unlock(client_entry->internal.lock);
-
- silc_hash_table_list_reset(&htl);
-}
-
-/* Empties channel from users. This handles entry locking internally. */
-
-void silc_client_empty_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel)
-{
- SilcHashTableList htl;
- SilcChannelUser chu;
-
- silc_rwlock_wrlock(channel->internal.lock);
-
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
- silc_hash_table_del(chu->client->channels, chu->channel);
- silc_hash_table_del(chu->channel->user_list, chu->client);
- silc_client_unref_client(client, conn, chu->client);
- silc_client_unref_channel(client, conn, chu->channel);
- silc_free(chu);
- }
-
- silc_rwlock_unlock(channel->internal.lock);
-
- silc_hash_table_list_reset(&htl);
-}
-
-/* Save public keys to channel public key list. Removes keys that are
- marked to be removed. Must be called with `channel' locked. */
-
-SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
- unsigned char *chpk_list,
- SilcUInt32 chpk_list_len)
-{
- SilcArgumentDecodedList a, b;
- SilcDList chpks;
- SilcBool found;
-
- chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
- SILC_ARGUMENT_PUBLIC_KEY);
- if (!chpks)
- return FALSE;
-
- if (!channel->channel_pubkeys) {
- channel->channel_pubkeys = silc_dlist_init();
- if (!channel->channel_pubkeys) {
- silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
- return FALSE;
- }
- }
-
- silc_dlist_start(chpks);
- while ((a = silc_dlist_get(chpks))) {
- found = FALSE;
- silc_dlist_start(channel->channel_pubkeys);
- while ((b = silc_dlist_get(channel->channel_pubkeys))) {
- if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
- found = TRUE;
- break;
- }
- }
-
- if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
- silc_dlist_add(channel->channel_pubkeys, a);
- silc_dlist_del(chpks, a);
- } else if (a->arg_type == 0x01 && found) {
- silc_dlist_del(channel->channel_pubkeys, b);
- }
- }
-
- silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
-
- return TRUE;
-}
+++ /dev/null
-/*
-
- client_channel.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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 CLIENT_CHANNEL_H
-#define CLIENT_CHANNEL_H
-
-SILC_FSM_STATE(silc_client_channel_message);
-SILC_FSM_STATE(silc_client_channel_message_error);
-SILC_FSM_STATE(silc_client_channel_key);
-
-SilcBool silc_client_save_channel_key(SilcClient client,
- SilcClientConnection conn,
- SilcBuffer key_payload,
- SilcChannelEntry channel);
-SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
- SilcClientEntry client_entry);
-SilcBool silc_client_add_to_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcClientEntry client_entry,
- SilcUInt32 cumode);
-SilcBool silc_client_remove_from_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcClientEntry client_entry);
-void silc_client_remove_from_channels(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry);
-void silc_client_empty_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel);
-SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
- unsigned char *chpk_list,
- SilcUInt32 chpk_list_len);
-
-#endif /* CLIENT_CHANNEL_H */
+++ /dev/null
-/*
-
- client_st_connect.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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 "silcclient.h"
-#include "client_internal.h"
-
-/************************ Static utility functions **************************/
-
-/* Callback called after connected to remote host */
-
-static void silc_client_connect_callback(SilcNetStatus status,
- SilcStream stream, void *context)
-{
- SilcFSMThread fsm = context;
- SilcClientConnection conn = silc_fsm_get_context(fsm);
- SilcClient client = conn->client;
-
- conn->internal->op = NULL;
- if (conn->internal->verbose) {
- switch (status) {
- case SILC_NET_OK:
- break;
- case SILC_NET_UNKNOWN_IP:
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to host %s: unknown IP address",
- conn->remote_host);
- break;
- case SILC_NET_UNKNOWN_HOST:
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to host %s: unknown host name",
- conn->remote_host);
- break;
- case SILC_NET_HOST_UNREACHABLE:
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to host %s: network unreachable",
- conn->remote_host);
- break;
- case SILC_NET_CONNECTION_REFUSED:
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to host %s: connection refused",
- conn->remote_host);
- break;
- case SILC_NET_CONNECTION_TIMEOUT:
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to host %s: connection timeout",
- conn->remote_host);
- break;
- default:
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to host %s",
- conn->remote_host);
- break;
- }
- }
-
- if (status != SILC_NET_OK) {
- /* Notify application of failure */
- SILC_LOG_DEBUG(("Connecting failed"));
- conn->internal->status = SILC_CLIENT_CONN_ERROR;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- SILC_FSM_CALL_CONTINUE(fsm);
- return;
- }
-
- /* Connection created successfully */
- SILC_LOG_DEBUG(("Connected"));
- conn->internal->user_stream = stream;
- SILC_FSM_CALL_CONTINUE(fsm);
-}
-
-/* Called after application has verified remote host's public key */
-
-static void silc_client_ke_verify_key_cb(SilcBool success, void *context)
-{
- SilcVerifyKeyContext verify = context;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Call the completion callback back to the SKE */
- verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
- SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
- verify->completion_context);
-
- silc_free(verify);
-}
-
-/* Verify remote host's public key */
-
-static void silc_client_ke_verify_key(SilcSKE ske,
- SilcPublicKey public_key,
- void *context,
- SilcSKEVerifyCbCompletion completion,
- void *completion_context)
-{
- SilcFSMThread fsm = context;
- SilcClientConnection conn = silc_fsm_get_context(fsm);
- SilcClient client = conn->client;
- SilcVerifyKeyContext verify;
-
- /* If we provided repository for SKE and we got here the key was not
- found from the repository. */
- if (conn->internal->params.repository &&
- !conn->internal->params.verify_notfound) {
- completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
- completion_context);
- return;
- }
-
- SILC_LOG_DEBUG(("Verify remote public key"));
-
- verify = silc_calloc(1, sizeof(*verify));
- if (!verify) {
- completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
- completion_context);
- return;
- }
- verify->ske = ske;
- verify->completion = completion;
- verify->completion_context = completion_context;
-
- /* Verify public key in application */
- client->internal->ops->verify_public_key(client, conn,
- conn->type, public_key,
- silc_client_ke_verify_key_cb,
- verify);
-}
-
-/* Key exchange protocol completion callback */
-
-static void silc_client_ke_completion(SilcSKE ske,
- SilcSKEStatus status,
- SilcSKESecurityProperties prop,
- SilcSKEKeyMaterial keymat,
- SilcSKERekeyMaterial rekey,
- void *context)
-{
- SilcFSMThread fsm = context;
- SilcClientConnection conn = silc_fsm_get_context(fsm);
- SilcClient client = conn->client;
- SilcCipher send_key, receive_key;
- SilcHmac hmac_send, hmac_receive;
-
- conn->internal->op = NULL;
- if (status != SILC_SKE_STATUS_OK) {
- /* Key exchange failed */
- SILC_LOG_DEBUG(("Error during key exchange with %s: %s (%d)",
- conn->remote_host, silc_ske_map_status(status), status));
-
- if (conn->internal->verbose)
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Error during key exchange with %s: %s",
- conn->remote_host,
- silc_ske_map_status(status));
-
- conn->internal->status = SILC_CLIENT_CONN_ERROR_KE;
- conn->internal->error = status;
- silc_ske_free_rekey_material(rekey);
-
- silc_fsm_next(fsm, silc_client_st_connect_error);
- SILC_FSM_CALL_CONTINUE(fsm);
- return;
- }
-
- SILC_LOG_DEBUG(("Setting keys into use"));
-
- /* Allocate the cipher and HMAC contexts */
- if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
- &hmac_send, &hmac_receive, &conn->internal->hash)) {
- /* Error setting keys */
- SILC_LOG_DEBUG(("Could not set keys into use"));
-
- if (conn->internal->verbose)
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Error during key exchange with %s: cannot use keys",
- conn->remote_host);
-
- conn->internal->status = SILC_CLIENT_CONN_ERROR_KE;
- silc_ske_free_rekey_material(rekey);
-
- silc_fsm_next(fsm, silc_client_st_connect_error);
- SILC_FSM_CALL_CONTINUE(fsm);
- return;
- }
-
- /* Set the keys into the packet stream. After this call packets will be
- encrypted with these keys. */
- if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
- hmac_receive, FALSE)) {
- /* Error setting keys */
- SILC_LOG_DEBUG(("Could not set keys into use"));
-
- if (conn->internal->verbose)
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Error during key exchange with %s: cannot use keys",
- conn->remote_host);
-
- conn->internal->status = SILC_CLIENT_CONN_ERROR_KE;
- silc_ske_free_rekey_material(rekey);
-
- silc_fsm_next(fsm, silc_client_st_connect_error);
- SILC_FSM_CALL_CONTINUE(fsm);
- return;
- }
-
- conn->internal->rekey = rekey;
-
- SILC_LOG_DEBUG(("Key Exchange completed"));
-
- /* Key exchange done */
- SILC_FSM_CALL_CONTINUE_SYNC(fsm);
-}
-
-/* Rekey protocol completion callback */
-
-static void silc_client_rekey_completion(SilcSKE ske,
- SilcSKEStatus status,
- SilcSKESecurityProperties prop,
- SilcSKEKeyMaterial keymat,
- SilcSKERekeyMaterial rekey,
- void *context)
-{
- SilcFSMThread fsm = context;
- SilcClientConnection conn = silc_fsm_get_context(fsm);
- SilcClient client = conn->client;
-
- conn->internal->op = NULL;
- if (status != SILC_SKE_STATUS_OK) {
- /* Rekey failed */
- SILC_LOG_DEBUG(("Error during rekey with %s: %s (%d)",
- conn->remote_host, silc_ske_map_status(status), status));
-
- if (conn->internal->verbose)
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Error during rekey with %s: %s",
- conn->remote_host,
- silc_ske_map_status(status));
-
- silc_fsm_finish(fsm);
- return;
- }
-
- silc_ske_free_rekey_material(conn->internal->rekey);
- conn->internal->rekey = rekey;
-
- silc_ske_free(conn->internal->ske);
- conn->internal->ske = NULL;
-
- SILC_LOG_DEBUG(("Rekey completed conn %p", conn));
-
- /* Rekey done */
- silc_fsm_finish(fsm);
-}
-
-/* Callback called by application to return authentication data */
-
-static void silc_client_connect_auth_method(SilcAuthMethod auth_meth,
- void *auth, SilcUInt32 auth_len,
- void *context)
-{
- SilcFSMThread fsm = context;
- SilcClientConnection conn = silc_fsm_get_context(fsm);
-
- conn->internal->params.auth_method = auth_meth;
- conn->internal->params.auth = auth;
- conn->internal->params.auth_len = auth_len;
-
- SILC_FSM_CALL_CONTINUE(fsm);
-}
-
-/* Connection authentication completion callback */
-
-static void silc_client_connect_auth_completion(SilcConnAuth connauth,
- SilcBool success,
- void *context)
-{
- SilcFSMThread fsm = context;
- SilcClientConnection conn = silc_fsm_get_context(fsm);
- SilcClient client = conn->client;
-
- conn->internal->op = NULL;
- silc_connauth_free(connauth);
-
- if (!success) {
- if (conn->internal->verbose)
- client->internal->ops->say(
- client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Authentication failed");
-
- conn->internal->status = SILC_CLIENT_CONN_ERROR_AUTH;
- conn->internal->error = SILC_STATUS_ERR_AUTH_FAILED;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- }
-
- SILC_FSM_CALL_CONTINUE_SYNC(fsm);
-}
-
-/********************** CONNECTION_AUTH_REQUEST packet **********************/
-
-/* Received connection authentication request packet. We get the
- required authentication method here. */
-
-SILC_FSM_STATE(silc_client_connect_auth_request)
-{
- SilcClientConnection conn = fsm_context;
- SilcPacket packet = state_context;
- SilcUInt16 conn_type, auth_meth;
-
- if (!conn->internal->auth_request) {
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- }
-
- /* Parse the payload */
- if (silc_buffer_unformat(&packet->buffer,
- SILC_STR_UI_SHORT(&conn_type),
- SILC_STR_UI_SHORT(&auth_meth),
- SILC_STR_END) < 0)
- auth_meth = SILC_AUTH_NONE;
-
- silc_packet_free(packet);
-
- SILC_LOG_DEBUG(("Resolved authentication method: %s",
- (auth_meth == SILC_AUTH_NONE ? "none" :
- auth_meth == SILC_AUTH_PASSWORD ? "passphrase" :
- "public key")));
- conn->internal->params.auth_method = auth_meth;
-
- /* Continue authentication */
- silc_fsm_continue_sync(&conn->internal->event_thread);
- return SILC_FSM_FINISH;
-}
-
-/*************************** Connect remote host ****************************/
-
-/* Connection timeout callback */
-
-SILC_TASK_CALLBACK(silc_client_connect_timeout)
-{
- SilcClientConnection conn = context;
-
- SILC_LOG_DEBUG(("Connection timeout"));
-
- conn->internal->status = SILC_CLIENT_CONN_ERROR_TIMEOUT;
- conn->internal->error = SILC_STATUS_ERR_TIMEDOUT;
-
- silc_fsm_next(&conn->internal->event_thread, silc_client_st_connect_error);
- silc_fsm_continue_sync(&conn->internal->event_thread);
-}
-
-/* Creates a connection to remote host */
-
-SILC_FSM_STATE(silc_client_st_connect)
-{
- SilcClientConnection conn = fsm_context;
-
- SILC_LOG_DEBUG(("Connecting to %s:%d", conn->remote_host,
- conn->remote_port));
-
- /** Connect */
- silc_fsm_next(fsm, silc_client_st_connect_set_stream);
-
- /* Add connection timeout */
- if (conn->internal->params.timeout_secs)
- silc_schedule_task_add_timeout(conn->internal->schedule,
- silc_client_connect_timeout, conn,
- conn->internal->params.timeout_secs, 0);
-
- if (conn->internal->params.udp) {
- SilcStream stream;
-
- if (!conn->internal->params.local_ip) {
- /** IP address not given */
- SILC_LOG_ERROR(("Local UDP IP address not specified"));
- conn->internal->status = SILC_CLIENT_CONN_ERROR;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Connect (UDP) */
- stream = silc_net_udp_connect(conn->internal->params.bind_ip ?
- conn->internal->params.bind_ip :
- conn->internal->params.local_ip,
- conn->internal->params.local_port,
- conn->remote_host, conn->remote_port,
- conn->internal->schedule);
-
- SILC_FSM_CALL(silc_client_connect_callback(stream ? SILC_NET_OK :
- SILC_NET_HOST_UNREACHABLE,
- stream, fsm));
- } else {
- /* Connect (TCP) */
- SILC_FSM_CALL(conn->internal->op = silc_net_tcp_connect(
- NULL, conn->remote_host,
- conn->remote_port,
- conn->internal->schedule,
- silc_client_connect_callback, fsm));
- }
-}
-
-/* Sets the new connection stream into use and creates packet stream */
-
-SILC_FSM_STATE(silc_client_st_connect_set_stream)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Create packet stream */
- conn->stream = silc_packet_stream_create(client->internal->packet_engine,
- conn->internal->schedule,
- conn->internal->user_stream);
- if (!conn->stream) {
- /** Cannot create packet stream */
- SILC_LOG_DEBUG(("Could not create packet stream"));
- conn->internal->status = SILC_CLIENT_CONN_ERROR;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- silc_packet_set_context(conn->stream, conn);
-
- /** Start key exchange */
- silc_fsm_next(fsm, silc_client_st_connect_key_exchange);
- return SILC_FSM_CONTINUE;
-}
-
-/* Starts key exchange protocol with remote host */
-
-SILC_FSM_STATE(silc_client_st_connect_key_exchange)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcSKEParamsStruct params;
-
- SILC_LOG_DEBUG(("Starting key exchange protocol"));
-
- /* Allocate SKE */
- conn->internal->ske =
- silc_ske_alloc(client->rng, conn->internal->schedule,
- conn->internal->params.repository,
- conn->public_key, conn->private_key, fsm);
- if (!conn->internal->ske) {
- /** Out of memory */
- conn->internal->status = SILC_CLIENT_CONN_ERROR_KE;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Set SKE callbacks */
- silc_ske_set_callbacks(conn->internal->ske, silc_client_ke_verify_key,
- silc_client_ke_completion, fsm);
-
- /* Set up key exchange parameters */
- params.version = client->internal->silc_client_version;
- params.timeout_secs = conn->internal->params.timeout_secs;
- params.flags = SILC_SKE_SP_FLAG_MUTUAL;
- if (conn->internal->params.pfs)
- params.flags |= SILC_SKE_SP_FLAG_PFS;
- if (conn->internal->params.udp) {
- params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
- params.session_port = conn->internal->params.local_port;
- }
-
- if (conn->internal->params.no_authentication)
- /** Run key exchange (no auth) */
- silc_fsm_next(fsm, silc_client_st_connected);
- else if (conn->internal->params.udp)
- /** Run key exchange (UDP)*/
- silc_fsm_next(fsm, silc_client_st_connect_setup_udp);
- else
- /** Run key exchange (TCP) */
- silc_fsm_next(fsm, silc_client_st_connect_auth_resolve);
-
- SILC_FSM_CALL(conn->internal->op = silc_ske_initiator(conn->internal->ske,
- conn->stream,
- ¶ms, NULL));
-}
-
-/* For UDP/IP connections, set up the UDP session after successful key
- exchange protocol */
-
-SILC_FSM_STATE(silc_client_st_connect_setup_udp)
-{
- SilcClientConnection conn = fsm_context;
- SilcStream stream, old;
- SilcSKESecurityProperties prop;
-
- SILC_LOG_DEBUG(("Setup UDP SILC session"));
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Create new UDP stream */
- prop = silc_ske_get_security_properties(conn->internal->ske);
- stream = silc_net_udp_connect(conn->internal->params.local_ip,
- conn->internal->params.local_port,
- conn->remote_host, prop->remote_port,
- conn->internal->schedule);
- if (!stream) {
- /** Cannot create UDP stream */
- conn->internal->status = SILC_CLIENT_CONN_ERROR;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Set the new stream to packet stream */
- old = silc_packet_stream_get_stream(conn->stream);
- silc_packet_stream_set_stream(conn->stream, stream);
- silc_packet_stream_set_iv_included(conn->stream);
- silc_packet_set_sid(conn->stream, 0);
-
- /* Delete the old stream */
- silc_stream_destroy(old);
-
- /** Start authentication */
- silc_fsm_next(fsm, silc_client_st_connect_auth_resolve);
- return SILC_FSM_CONTINUE;
-}
-
-/* Resolve authentication method to be used in authentication protocol */
-
-SILC_FSM_STATE(silc_client_st_connect_auth_resolve)
-{
- SilcClientConnection conn = fsm_context;
-
- SILC_LOG_DEBUG(("Resolve authentication method"));
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* If authentication method and data is set, use them */
- if (conn->internal->params.auth_set) {
- /** Got authentication data */
- silc_fsm_next(fsm, silc_client_st_connect_auth_start);
- return SILC_FSM_CONTINUE;
- }
-
- /* Send connection authentication request packet */
- silc_packet_send_va(conn->stream,
- SILC_PACKET_CONNECTION_AUTH_REQUEST, 0,
- SILC_STR_UI_SHORT(SILC_CONN_CLIENT),
- SILC_STR_UI_SHORT(SILC_AUTH_NONE),
- SILC_STR_END);
-
- /** Wait for authentication method */
- conn->internal->auth_request = TRUE;
- conn->internal->params.auth_method = SILC_AUTH_NONE;
- silc_fsm_next_later(fsm, silc_client_st_connect_auth_data, 2, 0);
- return SILC_FSM_WAIT;
-}
-
-/* Get authentication data to be used in authentication protocol */
-
-SILC_FSM_STATE(silc_client_st_connect_auth_data)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
-
- SILC_LOG_DEBUG(("Get authentication data"));
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- conn->internal->auth_request = FALSE;
-
- /** Get authentication data */
- silc_fsm_next(fsm, silc_client_st_connect_auth_start);
- SILC_FSM_CALL(client->internal->ops->get_auth_method(
- client, conn,
- conn->remote_host,
- conn->remote_port,
- conn->internal->params.auth_method,
- silc_client_connect_auth_method, fsm));
-}
-
-/* Start connection authentication with remote host */
-
-SILC_FSM_STATE(silc_client_st_connect_auth_start)
-{
- SilcClientConnection conn = fsm_context;
- SilcConnAuth connauth;
-
- SILC_LOG_DEBUG(("Starting connection authentication protocol"));
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* We always use the same key for connection authentication and SKE */
- if (conn->internal->params.auth_method == SILC_AUTH_PUBLIC_KEY)
- conn->internal->params.auth = conn->private_key;
-
- /* Allocate connection authentication protocol */
- connauth = silc_connauth_alloc(conn->internal->schedule,
- conn->internal->ske,
- conn->internal->params.rekey_secs);
- if (!connauth) {
- /** Out of memory */
- conn->internal->status = SILC_CLIENT_CONN_ERROR_AUTH;
- conn->internal->error = SILC_STATUS_ERR_AUTH_FAILED;
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- /** Start connection authentication */
- silc_fsm_next(fsm, silc_client_st_connected);
- SILC_FSM_CALL(conn->internal->op = silc_connauth_initiator(
- connauth, SILC_CONN_CLIENT,
- conn->internal->params.auth_method,
- conn->internal->params.auth,
- conn->internal->params.auth_len,
- silc_client_connect_auth_completion,
- fsm));
-}
-
-/* Connection fully established */
-
-SILC_FSM_STATE(silc_client_st_connected)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
-
- /* Get SILC protocol version remote supports */
- silc_ske_parse_version(conn->internal->ske, &conn->internal->remote_version,
- NULL, NULL, NULL, NULL);
-
- silc_ske_free(conn->internal->ske);
- conn->internal->ske = NULL;
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_connect_error);
- return SILC_FSM_CONTINUE;
- }
-
- SILC_LOG_DEBUG(("Connection established"));
-
- /* Install rekey timer */
- if (conn->type != SILC_CONN_CLIENT)
- silc_schedule_task_add_timeout(conn->internal->schedule,
- silc_client_rekey_timer, conn,
- conn->internal->params.rekey_secs, 0);
-
- /* If we connected to server, now register to network. */
- if (conn->type == SILC_CONN_SERVER &&
- !conn->internal->params.no_authentication) {
-
- /* If detach data is provided, resume the session. */
- if (conn->internal->params.detach_data &&
- conn->internal->params.detach_data_len) {
- /** Resume detached session */
- silc_fsm_next(fsm, silc_client_st_resume);
- } else {
- /** Register to network */
- silc_fsm_next(fsm, silc_client_st_register);
- }
-
- return SILC_FSM_CONTINUE;
- }
-
- silc_schedule_task_del_by_all(conn->internal->schedule, 0,
- silc_client_connect_timeout, conn);
-
- /* Call connection callback */
- conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
- conn->callback_context);
-
- silc_async_free(conn->internal->cop);
- conn->internal->cop = NULL;
-
- return SILC_FSM_FINISH;
-}
-
-/* Error during connecting */
-
-SILC_FSM_STATE(silc_client_st_connect_error)
-{
- SilcClientConnection conn = fsm_context;
-
- if (conn->internal->ske) {
- silc_ske_free(conn->internal->ske);
- conn->internal->ske = NULL;
- }
-
- /* Signal to close connection */
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
-
- silc_schedule_task_del_by_all(conn->internal->schedule, 0,
- silc_client_connect_timeout, conn);
-
- return SILC_FSM_FINISH;
-}
-
-/****************************** Connect rekey *******************************/
-
-/* Connection rekey timer callback */
-
-SILC_TASK_CALLBACK(silc_client_rekey_timer)
-{
- SilcClientConnection conn = context;
-
- /* Signal to start rekey */
- if (!silc_fsm_is_started(&conn->internal->event_thread)) {
- conn->internal->rekey_responder = FALSE;
- conn->internal->rekeying = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
-
- /* Reinstall rekey timer */
- silc_schedule_task_add_timeout(conn->internal->schedule,
- silc_client_rekey_timer, conn,
- conn->internal->params.rekey_secs, 0);
-}
-
-/* Performs rekey */
-
-SILC_FSM_STATE(silc_client_st_rekey)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
-
- SILC_LOG_DEBUG(("Rekey conn %p", conn));
-
- if (conn->internal->disconnected)
- return SILC_FSM_FINISH;
-
- /* Allocate SKE */
- conn->internal->ske =
- silc_ske_alloc(client->rng, conn->internal->schedule,
- conn->internal->params.repository,
- conn->public_key, conn->private_key, fsm);
- if (!conn->internal->ske)
- return SILC_FSM_FINISH;
-
- /* Set SKE callbacks */
- silc_ske_set_callbacks(conn->internal->ske, NULL,
- silc_client_rekey_completion, fsm);
-
- /** Perform rekey */
- if (!conn->internal->rekey_responder)
- SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_initiator(
- conn->internal->ske,
- conn->stream,
- conn->internal->rekey));
- else
- SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_responder(
- conn->internal->ske,
- conn->stream,
- conn->internal->rekey));
-}
+++ /dev/null
-/*
-
- client_connect.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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 CLIENT_CONNECT_H
-#define CLIENT_CONNECT_H
-
-SILC_FSM_STATE(silc_client_connect_auth_request);
-SILC_FSM_STATE(silc_client_st_connect);
-SILC_FSM_STATE(silc_client_st_connect_set_stream);
-SILC_FSM_STATE(silc_client_st_connect_key_exchange);
-SILC_FSM_STATE(silc_client_st_connect_setup_udp);
-SILC_FSM_STATE(silc_client_st_connect_auth_resolve);
-SILC_FSM_STATE(silc_client_st_connect_auth_data);
-SILC_FSM_STATE(silc_client_st_connect_auth_start);
-SILC_FSM_STATE(silc_client_st_connected);
-SILC_FSM_STATE(silc_client_st_connect_error);
-SILC_FSM_STATE(silc_client_st_rekey);
-
-SILC_TASK_CALLBACK(silc_client_connect_timeout);
-SILC_TASK_CALLBACK(silc_client_rekey_timer);
-
-#endif /* CLIENT_CONNECT_H */
+++ /dev/null
-/*
-
- client_entry.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2001 - 2007 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 "silcclient.h"
-#include "client_internal.h"
-
-/************************ Client Searching Locally **************************/
-
-/* Finds entry for client by the client's ID. Returns the entry or NULL
- if the entry was not found. */
-
-SilcClientEntry silc_client_get_client_by_id(SilcClient client,
- SilcClientConnection conn,
- SilcClientID *client_id)
-{
- SilcIDCacheEntry id_cache;
- SilcClientEntry client_entry;
-
- if (!client || !conn || !client_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Finding client by ID (%s)",
- silc_id_render(client_id, SILC_ID_CLIENT)));
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Find ID from cache */
- if (!silc_idcache_find_by_id_one(conn->internal->client_cache, client_id,
- &id_cache)) {
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- client_entry = id_cache->context;
-
- /* Reference */
- silc_client_ref_client(client, conn, client_entry);
- silc_mutex_unlock(conn->internal->lock);
-
- SILC_LOG_DEBUG(("Found"));
-
- return client_entry;
-}
-
-/* Finds clients by nickname from local cache. */
-
-SilcDList silc_client_get_clients_local(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *format)
-{
- SilcIDCacheEntry id_cache;
- SilcList list;
- SilcDList clients;
- SilcClientEntry entry;
- char *nicknamec;
-
- if (!client || !conn || !nickname)
- return NULL;
-
- SILC_LOG_DEBUG(("Find clients by nickname %s", nickname));
-
- /* Normalize nickname for search */
- nicknamec = silc_identifier_check(nickname, strlen(nickname),
- SILC_STRING_UTF8, 128, NULL);
- if (!nicknamec)
- return NULL;
-
- clients = silc_dlist_init();
- if (!clients) {
- silc_free(nicknamec);
- return NULL;
- }
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Find from cache */
- silc_list_init(list, struct SilcIDCacheEntryStruct, next);
- if (!silc_idcache_find_by_name(conn->internal->client_cache, nicknamec,
- &list)) {
- silc_mutex_unlock(conn->internal->lock);
- silc_free(nicknamec);
- silc_dlist_uninit(clients);
- return NULL;
- }
-
- if (!format) {
- /* Take all without any further checking */
- silc_list_start(list);
- while ((id_cache = silc_list_get(list))) {
- silc_client_ref_client(client, conn, id_cache->context);
- silc_dlist_add(clients, id_cache->context);
- }
- } else {
- /* Check multiple cache entries for exact match */
- silc_list_start(list);
- while ((id_cache = silc_list_get(list))) {
- entry = id_cache->context;
- if (silc_utf8_strcasecmp(entry->nickname, format)) {
- silc_client_ref_client(client, conn, entry);
- silc_dlist_add(clients, entry);
- }
- }
- }
-
- silc_mutex_unlock(conn->internal->lock);
-
- silc_dlist_start(clients);
-
- silc_free(nicknamec);
- return clients;
-}
-
-/********************** Client Resolving from Server ************************/
-
-/* Resolving context */
-typedef struct {
- SilcDList clients;
- SilcGetClientCallback completion;
- void *context;
- SilcClientEntry client_entry;
-} *SilcClientGetClientInternal;
-
-/* Resolving command callback */
-
-static SilcBool silc_client_get_clients_cb(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- SilcClientGetClientInternal i = context;
- SilcClientEntry client_entry;
-
- if (error != SILC_STATUS_OK) {
- SILC_LOG_DEBUG(("Resolving failed: %s", silc_get_status_message(error)));
-
- if (i->client_entry) {
- i->client_entry->internal.resolve_cmd_ident = 0;
- silc_client_unref_client(client, conn, i->client_entry);
- }
-
- if (i->completion)
- i->completion(client, conn, error, NULL, i->context);
- goto out;
- }
-
- /* Add the returned client to list */
- if (i->completion) {
- client_entry = va_arg(ap, SilcClientEntry);
- silc_client_ref_client(client, conn, client_entry);
- silc_dlist_add(i->clients, client_entry);
- client_entry->internal.resolve_cmd_ident = 0;
- }
-
- if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) {
- /* Deliver the clients to the caller */
- if (i->completion) {
- SILC_LOG_DEBUG(("Resolved %d clients", silc_dlist_count(i->clients)));
-
- if (i->client_entry) {
- i->client_entry->internal.resolve_cmd_ident = 0;
- silc_client_unref_client(client, conn, i->client_entry);
- }
-
- silc_dlist_start(i->clients);
- i->completion(client, conn, SILC_STATUS_OK, i->clients, i->context);
- }
- goto out;
- }
-
- return TRUE;
-
- out:
- silc_client_list_free(client, conn, i->clients);
- silc_free(i);
- return FALSE;
-}
-
-/* Resolves client information from server by the client ID. */
-
-SilcUInt16
-silc_client_get_client_by_id_resolve(SilcClient client,
- SilcClientConnection conn,
- SilcClientID *client_id,
- SilcBuffer attributes,
- SilcGetClientCallback completion,
- void *context)
-{
- SilcClientGetClientInternal i;
- SilcClientEntry client_entry;
- SilcBuffer idp;
- SilcUInt16 cmd_ident;
-
- if (!client || !conn | !client_id)
- return 0;
-
- SILC_LOG_DEBUG(("Resolve client by ID (%s)",
- silc_id_render(client_id, SILC_ID_CLIENT)));
-
- i = silc_calloc(1, sizeof(*i));
- if (!i)
- return 0;
- i->completion = completion;
- i->context = context;
- i->clients = silc_dlist_init();
- if (!i->clients) {
- silc_free(i);
- return 0;
- }
-
- /* Attach to resolving, if on going */
- client_entry = silc_client_get_client_by_id(client, conn, client_id);
- if (client_entry && client_entry->internal.resolve_cmd_ident) {
- SILC_LOG_DEBUG(("Attach to existing resolving"));
- silc_client_unref_client(client, conn, client_entry);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
- client_entry->internal.resolve_cmd_ident,
- silc_client_get_clients_cb, i);
- return client_entry->internal.resolve_cmd_ident;
- }
-
- /* Send the command */
- idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- cmd_ident = silc_client_command_send(client, conn, SILC_COMMAND_WHOIS,
- silc_client_get_clients_cb, i,
- 2, 3, silc_buffer_datalen(attributes),
- 4, silc_buffer_datalen(idp));
- if (!cmd_ident && completion)
- completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
-
- if (client_entry && cmd_ident) {
- client_entry->internal.resolve_cmd_ident = cmd_ident;
- i->client_entry = client_entry;
- } else {
- silc_client_unref_client(client, conn, client_entry);
- }
-
- silc_buffer_free(idp);
-
- return cmd_ident;
-}
-
-/* Finds client entry or entries by the `nickname' and `server'. The
- completion callback will be called when the client entries has been
- found. Used internally by the library. */
-
-static SilcUInt16 silc_client_get_clients_i(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- const char *nickname,
- const char *server,
- SilcBuffer attributes,
- SilcGetClientCallback completion,
- void *context)
-{
- SilcClientGetClientInternal i;
- char userhost[768 + 1];
- int len;
-
- SILC_LOG_DEBUG(("Resolve client by %s command",
- silc_get_command_name(command)));
-
- if (!client || !conn)
- return 0;
- if (!nickname && !attributes)
- return 0;
-
- i = silc_calloc(1, sizeof(*i));
- if (!i)
- return 0;
- i->clients = silc_dlist_init();
- if (!i->clients) {
- silc_free(i);
- return 0;
- }
- i->completion = completion;
- i->context = context;
-
- memset(userhost, 0, sizeof(userhost));
- if (nickname && server) {
- len = strlen(nickname) + strlen(server) + 3;
- silc_strncat(userhost, len, nickname, strlen(nickname));
- silc_strncat(userhost, len, "@", 1);
- silc_strncat(userhost, len, server, strlen(server));
- } else if (nickname) {
- silc_strncat(userhost, sizeof(userhost) - 1, nickname, strlen(nickname));
- }
-
- /* Send the command */
- if (command == SILC_COMMAND_IDENTIFY)
- return silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_get_clients_cb, i,
- 1, 1, userhost, strlen(userhost));
- return silc_client_command_send(client, conn, SILC_COMMAND_WHOIS,
- silc_client_get_clients_cb, i,
- 2, 1, userhost, strlen(userhost),
- 3, silc_buffer_datalen(attributes));
-}
-
-/* Get clients from server with IDENTIFY command */
-
-SilcUInt16 silc_client_get_clients(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *server,
- SilcGetClientCallback completion,
- void *context)
-{
- return silc_client_get_clients_i(client, conn, SILC_COMMAND_IDENTIFY,
- nickname, server, NULL,
- completion, context);
-}
-
-/* Get clients from server with WHOIS command */
-
-SilcUInt16 silc_client_get_clients_whois(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *server,
- SilcBuffer attributes,
- SilcGetClientCallback completion,
- void *context)
-{
- return silc_client_get_clients_i(client, conn, SILC_COMMAND_WHOIS,
- nickname, server, attributes,
- completion, context);
-}
-
-/* ID list resolving context */
-typedef struct {
- SilcGetClientCallback completion;
- void *context;
- SilcBuffer client_id_list;
- SilcUInt32 list_count;
-} *GetClientsByListInternal;
-
-static SilcBool silc_client_get_clients_list_cb(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- GetClientsByListInternal i = context;
- SilcClientEntry client_entry;
- SilcDList clients;
- SilcUInt16 idp_len;
- SilcID id;
- int c;
-
- /* Process the list after all replies have been received */
- if (status != SILC_STATUS_OK && !SILC_STATUS_IS_ERROR(status) &&
- status != SILC_STATUS_LIST_END)
- return TRUE;
-
- SILC_LOG_DEBUG(("Resolved all clients"));
-
- clients = silc_dlist_init();
- if (!clients) {
- status = SILC_STATUS_ERR_RESOURCE_LIMIT;
- goto out;
- }
-
- for (c = 0; c < i->list_count; c++) {
- /* Get Client ID */
- SILC_GET16_MSB(idp_len, i->client_id_list->data + 2);
- idp_len += 4;
- if (!silc_id_payload_parse_id(i->client_id_list->data, idp_len, &id)) {
- status = SILC_STATUS_ERR_BAD_CLIENT_ID;
- goto out;
- }
-
- /* Get client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry)
- silc_dlist_add(clients, client_entry);
-
- if (!silc_buffer_pull(i->client_id_list, idp_len)) {
- status = SILC_STATUS_ERR_BAD_CLIENT_ID;
- goto out;
- }
- }
-
- silc_dlist_start(clients);
- status = SILC_STATUS_OK;
- if (i->completion)
- i->completion(client, conn, status, clients, i->context);
-
- out:
- if (status != SILC_STATUS_OK && i->completion)
- i->completion(client, conn, status, NULL, i->context);
-
- silc_client_list_free(client, conn, clients);
- silc_buffer_free(i->client_id_list);
- silc_free(i);
-
- return FALSE;
-}
-
-/* Gets client entries by the list of client ID's `client_id_list'. This
- always resolves those client ID's it does not know yet from the server
- so this function might take a while. The `client_id_list' is a list
- of ID Payloads added one after other. JOIN command reply and USERS
- command reply for example returns this sort of list. The `completion'
- will be called after the entries are available. */
-
-SilcUInt16 silc_client_get_clients_by_list(SilcClient client,
- SilcClientConnection conn,
- SilcUInt32 list_count,
- SilcBuffer client_id_list,
- SilcGetClientCallback completion,
- void *context)
-{
- GetClientsByListInternal in;
- SilcClientEntry entry;
- unsigned char **res_argv = NULL;
- SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
- SilcUInt16 idp_len, cmd_ident;
- SilcID id;
- va_list tmp;
- int i;
-
- SILC_LOG_DEBUG(("Resolve clients from Client ID list"));
-
- if (!client || !conn || !client_id_list)
- return 0;
-
- in = silc_calloc(1, sizeof(*in));
- if (!in)
- return 0;
- in->completion = completion;
- in->context = context;
- in->list_count = list_count;
- in->client_id_list = silc_buffer_copy(client_id_list);
- if (!in->client_id_list)
- goto err;
-
- for (i = 0; i < list_count; i++) {
- /* Get Client ID */
- SILC_GET16_MSB(idp_len, client_id_list->data + 2);
- idp_len += 4;
- if (!silc_id_payload_parse_id(client_id_list->data, idp_len, &id))
- goto err;
-
- /* Check if we have this client cached already. If we don't have the
- entry or it has incomplete info, then resolve it from the server. */
- entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!entry || !entry->nickname[0] || !entry->username[0] ||
- !entry->realname) {
- if (!res_argv) {
- res_argv = silc_calloc(list_count, sizeof(*res_argv));
- res_argv_lens = silc_calloc(list_count, sizeof(*res_argv_lens));
- res_argv_types = silc_calloc(list_count, sizeof(*res_argv_types));
- if (!res_argv || !res_argv_lens || !res_argv_types) {
- silc_client_unref_client(client, conn, entry);
- goto err;
- }
- }
-
- res_argv[res_argc] = client_id_list->data;
- res_argv_lens[res_argc] = idp_len;
- res_argv_types[res_argc] = res_argc + 4;
- res_argc++;
- }
- silc_client_unref_client(client, conn, entry);
-
- if (!silc_buffer_pull(client_id_list, idp_len))
- goto err;
- }
- silc_buffer_start(client_id_list);
-
- /* Query the unknown client information from server */
- if (res_argc) {
- cmd_ident = silc_client_command_send_argv(client,
- conn, SILC_COMMAND_WHOIS,
- silc_client_get_clients_list_cb,
- in, res_argc, res_argv,
- res_argv_lens,
- res_argv_types);
- silc_free(res_argv);
- silc_free(res_argv_lens);
- silc_free(res_argv_types);
- return cmd_ident;
- }
-
- /* We have the clients in cache, get them and call the completion */
- silc_client_get_clients_list_cb(client, conn, SILC_COMMAND_WHOIS,
- SILC_STATUS_OK, SILC_STATUS_OK, in, tmp);
- return 0;
-
- err:
- silc_buffer_free(in->client_id_list);
- silc_free(in);
- silc_free(res_argv);
- silc_free(res_argv_lens);
- silc_free(res_argv_types);
- return 0;
-}
-
-#if 0
-typedef struct {
- SilcClient client;
- SilcClientConnection conn;
- SilcChannelID channel_id;
- SilcGetClientCallback completion;
- void *context;
- int res_count;
-} *GetClientsByChannelInternal;
-
-SILC_CLIENT_CMD_FUNC(get_clients_by_channel_cb)
-{
- GetClientsByChannelInternal i = context;
- SilcClientEntry *clients = NULL;
- SilcUInt32 clients_count = 0;
- SilcBool found = FALSE;
- SilcChannelEntry channel;
- SilcHashTableList htl;
- SilcChannelUser chu;
-
- if (i->res_count) {
- i->res_count--;
- if (i->res_count)
- return;
- }
-
- channel = silc_client_get_channel_by_id(i->client, i->conn, &i->channel_id);
- if (channel && !silc_hash_table_count(channel->user_list)) {
- clients = silc_calloc(silc_hash_table_count(channel->user_list),
- sizeof(*clients));
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu))
- clients[clients_count++] = chu->client;
- silc_hash_table_list_reset(&htl);
- found = TRUE;
- }
-
- if (found) {
- i->completion(i->client, i->conn, clients, clients_count, i->context);
- silc_free(clients);
- } else {
- i->completion(i->client, i->conn, NULL, 0, i->context);
- }
-
- silc_free(i);
-}
-
-/* Gets client entries by the channel entry indicated by `channel'. Thus,
- it resolves the clients currently on that channel. */
-
-void silc_client_get_clients_by_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcGetClientCallback completion,
- void *context)
-{
- GetClientsByChannelInternal in;
- SilcHashTableList htl;
- SilcChannelUser chu;
- SilcClientEntry entry;
- unsigned char **res_argv = NULL;
- SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
- SilcBuffer idp;
- SilcBool wait_res = FALSE;
-
- assert(client && conn && channel);
-
- SILC_LOG_DEBUG(("Start"));
-
- in = silc_calloc(1, sizeof(*in));
- in->client = client;
- in->conn = conn;
- in->channel_id = *channel->id;
- in->completion = completion;
- in->context = context;
-
- /* If user list does not exist, send USERS command. */
- if (!channel->user_list || !silc_hash_table_count(channel->user_list)) {
- SILC_LOG_DEBUG(("Sending USERS"));
- silc_client_command_register(client, SILC_COMMAND_USERS, NULL, NULL,
- silc_client_command_reply_users_i, 0,
- ++conn->cmd_ident);
- silc_client_command_send(client, conn, SILC_COMMAND_USERS,
- conn->cmd_ident, 1, 2, channel->channel_name,
- strlen(channel->channel_name));
- silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
- silc_client_command_get_clients_by_channel_cb,
- in);
- return;
- }
-
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
- entry = chu->client;
-
- /* If the entry has incomplete info, then resolve it from the server. */
- if (!entry->nickname[0] || !entry->realname) {
- if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
- /* Attach to this resolving and wait until it finishes */
- silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- entry->resolve_cmd_ident,
- silc_client_command_get_clients_by_channel_cb,
- (void *)in);
- wait_res = TRUE;
- in->res_count++;
- continue;
- }
- entry->status |= SILC_CLIENT_STATUS_RESOLVING;
- entry->resolve_cmd_ident = conn->cmd_ident + 1;
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-
- /* No we don't have it, query it from the server. Assemble argument
- table that will be sent for the WHOIS command later. */
- res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
- (res_argc + 1));
- res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
- (res_argc + 1));
- res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
- (res_argc + 1));
- res_argv[res_argc] = silc_memdup(idp->data, idp->len);
- res_argv_lens[res_argc] = idp->len;
- res_argv_types[res_argc] = res_argc + 4;
- res_argc++;
-
- silc_buffer_free(idp);
- }
- }
- silc_hash_table_list_reset(&htl);
-
- /* Query the client information from server if the list included clients
- that we don't know about. */
- if (res_argc) {
- SilcBuffer res_cmd;
-
- /* Send the WHOIS command to server */
- res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
- res_argc, res_argv, res_argv_lens,
- res_argv_types, ++conn->cmd_ident);
- silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
- NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
- TRUE);
-
- /* Register our own command reply for this command */
- silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
- silc_client_command_reply_whois_i, 0,
- conn->cmd_ident);
-
- /* Process the applications request after reply has been received */
- silc_client_command_pending(
- conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
- silc_client_command_get_clients_by_channel_cb,
- (void *)in);
- in->res_count++;
-
- silc_buffer_free(res_cmd);
- silc_free(res_argv);
- silc_free(res_argv_lens);
- silc_free(res_argv_types);
- return;
- }
-
- if (wait_res)
- return;
-
- /* We have the clients in cache, get them and call the completion */
- silc_client_command_get_clients_by_channel_cb((void *)in, NULL);
-}
-#endif /* 0 */
-
-
-/************************** Client Entry Routines ***************************/
-
-/* Creates new client entry and adds it to the ID cache. Returns pointer
- to the new entry. */
-
-SilcClientEntry silc_client_add_client(SilcClient client,
- SilcClientConnection conn,
- char *nickname, char *username,
- char *userinfo, SilcClientID *id,
- SilcUInt32 mode)
-{
- SilcClientEntry client_entry;
- char *nick = NULL;
-
- SILC_LOG_DEBUG(("Adding new client entry"));
-
- /* Save the client infos */
- client_entry = silc_calloc(1, sizeof(*client_entry));
- if (!client_entry)
- return NULL;
-
- silc_rwlock_alloc(&client_entry->internal.lock);
- silc_atomic_init8(&client_entry->internal.refcnt, 0);
- client_entry->id = *id;
- client_entry->mode = mode;
- client_entry->realname = userinfo ? strdup(userinfo) : NULL;
- silc_parse_userfqdn(nickname, client_entry->nickname,
- sizeof(client_entry->nickname),
- client_entry->server,
- sizeof(client_entry->server));
- silc_parse_userfqdn(username, client_entry->username,
- sizeof(client_entry->username),
- client_entry->hostname,
- sizeof(client_entry->hostname));
- client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
- NULL, NULL, NULL, TRUE);
- if (!client_entry->channels) {
- silc_free(client_entry->realname);
- silc_free(client_entry);
- return NULL;
- }
-
- /* Normalize nickname */
- if (client_entry->nickname[0]) {
- nick = silc_identifier_check(client_entry->nickname,
- strlen(client_entry->nickname),
- SILC_STRING_UTF8, 128, NULL);
- if (!nick) {
- silc_free(client_entry->realname);
- silc_hash_table_free(client_entry->channels);
- silc_free(client_entry);
- return NULL;
- }
- }
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Add client to cache, the normalized nickname is saved to cache */
- if (!silc_idcache_add(conn->internal->client_cache, nick,
- &client_entry->id, client_entry)) {
- silc_free(nick);
- silc_free(client_entry->realname);
- silc_hash_table_free(client_entry->channels);
- silc_free(client_entry);
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- client_entry->nickname_normalized = nick;
-
- silc_mutex_unlock(conn->internal->lock);
- silc_client_ref_client(client, conn, client_entry);
-
- /* Format the nickname */
- silc_client_nickname_format(client, conn, client_entry, FALSE);
-
- if (client_entry->nickname[0])
- client_entry->internal.valid = TRUE;
-
- SILC_LOG_DEBUG(("Added %p", client_entry));
-
- return client_entry;
-}
-
-/* Updates the `client_entry' with the new information sent as argument.
- This handles entry locking internally. */
-
-void silc_client_update_client(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *nickname,
- const char *username,
- const char *userinfo,
- SilcUInt32 mode)
-{
- char *nick = NULL;
-
- SILC_LOG_DEBUG(("Update client entry"));
-
- silc_rwlock_wrlock(client_entry->internal.lock);
-
- if (!client_entry->realname && userinfo)
- client_entry->realname = strdup(userinfo);
- if ((!client_entry->username[0] || !client_entry->hostname[0]) && username)
- silc_parse_userfqdn(username, client_entry->username,
- sizeof(client_entry->username),
- client_entry->hostname,
- sizeof(client_entry->username));
- if (!client_entry->nickname[0] && nickname) {
- silc_parse_userfqdn(nickname, client_entry->nickname,
- sizeof(client_entry->nickname),
- client_entry->server,
- sizeof(client_entry->server));
-
- /* Normalize nickname */
- nick = silc_identifier_check(client_entry->nickname,
- strlen(client_entry->nickname),
- SILC_STRING_UTF8, 128, NULL);
- if (!nick) {
- silc_rwlock_unlock(client_entry->internal.lock);
- return;
- }
-
- /* Format nickname */
- silc_client_nickname_format(client, conn, client_entry,
- client_entry == conn->local_entry);
-
- /* Update cache entry */
- silc_mutex_lock(conn->internal->lock);
- silc_idcache_update_by_context(conn->internal->client_cache,
- client_entry, NULL, nick, TRUE);
- silc_mutex_unlock(conn->internal->lock);
- client_entry->nickname_normalized = nick;
- client_entry->internal.valid = TRUE;
- }
- client_entry->mode = mode;
-
- silc_rwlock_unlock(client_entry->internal.lock);
-}
-
-/* Change a client's nickname. Must be called with `client_entry' locked. */
-
-SilcBool silc_client_change_nickname(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *new_nick,
- SilcClientID *new_id,
- const unsigned char *idp,
- SilcUInt32 idp_len)
-{
- char *tmp;
-
- SILC_LOG_DEBUG(("Change nickname %s to %s", client_entry->nickname,
- new_nick));
-
- /* Normalize nickname */
- tmp = silc_identifier_check(new_nick, strlen(new_nick),
- SILC_STRING_UTF8, 128, NULL);
- if (!tmp)
- return FALSE;
-
- /* Update the client entry */
- silc_mutex_lock(conn->internal->lock);
- if (!silc_idcache_update_by_context(conn->internal->client_cache,
- client_entry, new_id, tmp, TRUE)) {
- silc_free(tmp);
- silc_mutex_unlock(conn->internal->lock);
- return FALSE;
- }
- silc_mutex_unlock(conn->internal->lock);
-
- memset(client_entry->nickname, 0, sizeof(client_entry->nickname));
- memcpy(client_entry->nickname, new_nick, strlen(new_nick));
- client_entry->nickname_normalized = tmp;
- silc_client_nickname_format(client, conn, client_entry,
- client_entry == conn->local_entry);
-
- /* For my client entry, update ID and set new ID to packet stream */
- if (client_entry == conn->local_entry) {
- if (idp && idp_len) {
- silc_buffer_enlarge(conn->internal->local_idp, idp_len);
- silc_buffer_put(conn->internal->local_idp, idp, idp_len);
- }
- if (new_id)
- silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
- 0, NULL);
- }
-
- client_entry->internal.valid = TRUE;
- return TRUE;
-}
-
-/* Deletes the client entry and frees all memory. */
-
-void silc_client_del_client_entry(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry)
-{
- silc_free(client_entry->realname);
- silc_free(client_entry->nickname_normalized);
- silc_free(client_entry->internal.key);
- if (client_entry->public_key)
- silc_pkcs_public_key_free(client_entry->public_key);
- silc_hash_table_free(client_entry->channels);
- if (client_entry->internal.send_key)
- silc_cipher_free(client_entry->internal.send_key);
- if (client_entry->internal.receive_key)
- silc_cipher_free(client_entry->internal.receive_key);
- if (client_entry->internal.hmac_send)
- silc_hmac_free(client_entry->internal.hmac_send);
- if (client_entry->internal.hmac_receive)
- silc_hmac_free(client_entry->internal.hmac_receive);
- silc_client_ftp_session_free_client(client, client_entry);
- if (client_entry->internal.ke)
- silc_client_abort_key_agreement(client, conn, client_entry);
- silc_atomic_uninit8(&client_entry->internal.refcnt);
- silc_rwlock_free(client_entry->internal.lock);
- silc_free(client_entry);
-}
-
-/* Removes client from the cache by the client entry. */
-
-SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry)
-{
- SilcBool ret;
-
- if (!client_entry)
- return FALSE;
-
- if (silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) > 0)
- return FALSE;
-
- SILC_LOG_DEBUG(("Deleting client %p", client_entry));
-
- silc_mutex_lock(conn->internal->lock);
- ret = silc_idcache_del_by_context(conn->internal->client_cache,
- client_entry, NULL);
- silc_mutex_unlock(conn->internal->lock);
-
- if (ret) {
- /* Remove from channels */
- silc_client_remove_from_channels(client, conn, client_entry);
-
- /* Free the client entry data */
- silc_client_del_client_entry(client, conn, client_entry);
- }
-
- return ret;
-}
-
-/* Internal routine used to find client by ID and if not found this creates
- new client entry and returns it. */
-
-SilcClientEntry silc_client_get_client(SilcClient client,
- SilcClientConnection conn,
- SilcClientID *client_id)
-{
- SilcClientEntry client_entry;
-
- client_entry = silc_client_get_client_by_id(client, conn, client_id);
- if (!client_entry) {
- client_entry = silc_client_add_client(client, conn, NULL, NULL, NULL,
- client_id, 0);
- if (!client_entry)
- return NULL;
- silc_client_ref_client(client, conn, client_entry);
- }
-
- return client_entry;
-}
-
-/* Lock client */
-
-void silc_client_lock_client(SilcClientEntry client_entry)
-{
- silc_rwlock_rdlock(client_entry->internal.lock);
-}
-
-/* Unlock client */
-
-void silc_client_unlock_client(SilcClientEntry client_entry)
-{
- silc_rwlock_unlock(client_entry->internal.lock);
-}
-
-/* Take reference of client entry */
-
-SilcClientEntry silc_client_ref_client(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry)
-{
- silc_atomic_add_int8(&client_entry->internal.refcnt, 1);
- SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
- silc_atomic_get_int8(&client_entry->internal.refcnt) - 1,
- silc_atomic_get_int8(&client_entry->internal.refcnt)));
- return client_entry;
-}
-
-/* Release reference of client entry */
-
-void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry)
-{
- if (client_entry) {
- SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
- silc_atomic_get_int8(&client_entry->internal.refcnt),
- silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
- silc_client_del_client(client, conn, client_entry);
- }
-}
-
-/* Free client entry list */
-
-void silc_client_list_free(SilcClient client, SilcClientConnection conn,
- SilcDList client_list)
-{
- SilcClientEntry client_entry;
-
- if (client_list) {
- silc_dlist_start(client_list);
- while ((client_entry = silc_dlist_get(client_list)))
- silc_client_unref_client(client, conn, client_entry);
-
- silc_dlist_uninit(client_list);
- }
-}
-
-/* Formats the nickname of the client specified by the `client_entry'.
- If the format is specified by the application this will format the
- nickname and replace the old nickname in the client entry. If the
- format string is not specified then this function has no effect.
- Returns the client entry that was formatted. */
-
-SilcClientEntry silc_client_nickname_format(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcBool priority)
-{
- char *cp;
- char newnick[128 + 1];
- int i, off = 0, len;
- SilcBool freebase;
- SilcDList clients;
- SilcClientEntry entry, unformatted = NULL;
-
- if (!client->internal->params->nickname_format[0])
- return client_entry;
- if (!client_entry->nickname[0])
- return NULL;
-
- SILC_LOG_DEBUG(("Format nickname"));
-
- /* Get all clients with same nickname. Do not perform the formatting
- if there aren't any clients with same nickname unless the application
- is forcing us to do so. */
- clients = silc_client_get_clients_local(client, conn,
- client_entry->nickname, NULL);
- if (!clients)
- return NULL;
- if (silc_dlist_count(clients) == 1 &&
- !client->internal->params->nickname_force_format) {
- silc_client_list_free(client, conn, clients);
- return client_entry;
- }
-
- len = 0;
- freebase = TRUE;
- while ((entry = silc_dlist_get(clients))) {
- if (entry->internal.valid && entry != client_entry)
- len++;
- if (entry->internal.valid && entry != client_entry &&
- silc_utf8_strcasecmp(entry->nickname, client_entry->nickname)) {
- freebase = FALSE;
- unformatted = entry;
- break;
- }
- }
- if (!len || freebase) {
- silc_client_list_free(client, conn, clients);
- return client_entry;
- }
-
- /* If priority formatting, this client always gets unformatted nickname. */
- if (unformatted && priority)
- client_entry = unformatted;
-
- memset(newnick, 0, sizeof(newnick));
- cp = client->internal->params->nickname_format;
- while (cp && *cp) {
- if (*cp == '%') {
- cp++;
- continue;
- }
-
- switch(*cp) {
- case 'n':
- /* Nickname */
- if (!client_entry->nickname[0])
- break;
- len = strlen(client_entry->nickname);
- memcpy(&newnick[off], client_entry->nickname, len);
- off += len;
- break;
- case 'h':
- /* Stripped hostname */
- if (!client_entry->hostname[0])
- break;
- len = strcspn(client_entry->hostname, ".");
- i = strcspn(client_entry->hostname, "-");
- if (i < len)
- len = i;
- memcpy(&newnick[off], client_entry->hostname, len);
- off += len;
- break;
- case 'H':
- /* Full hostname */
- if (!client_entry->hostname[0])
- break;
- len = strlen(client_entry->hostname);
- memcpy(&newnick[off], client_entry->hostname, len);
- off += len;
- break;
- case 's':
- /* Stripped server name */
- if (!client_entry->server)
- break;
- len = strcspn(client_entry->server, ".");
- memcpy(&newnick[off], client_entry->server, len);
- off += len;
- break;
- case 'S':
- /* Full server name */
- if (!client_entry->server)
- break;
- len = strlen(client_entry->server);
- memcpy(&newnick[off], client_entry->server, len);
- off += len;
- break;
- case 'a':
- /* Ascending number */
- {
- char tmp[6];
- int num, max = 1;
-
- if (silc_dlist_count(clients) == 1)
- break;
-
- silc_dlist_start(clients);
- while ((entry = silc_dlist_get(clients))) {
- if (!silc_utf8_strncasecmp(entry->nickname, newnick, off))
- continue;
- if (strlen(entry->nickname) <= off)
- continue;
- num = atoi(&entry->nickname[off]);
- if (num > max)
- max = num;
- }
-
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
- len = strlen(tmp);
- memcpy(&newnick[off], tmp, len);
- off += len;
- }
- break;
- default:
- /* Some other character in the string */
- memcpy(&newnick[off], cp, 1);
- off++;
- break;
- }
-
- cp++;
- }
-
- newnick[off] = 0;
- memcpy(client_entry->nickname, newnick, strlen(newnick));
- silc_client_list_free(client, conn, clients);
-
- return client_entry;
-}
-
-/* Parses nickname according to nickname format string */
-
-SilcBool silc_client_nickname_parse(SilcClient client,
- SilcClientConnection conn,
- char *nickname,
- char **ret_nick)
-{
- char *cp, s = 0, e = 0, *nick;
- SilcBool n = FALSE;
- int len;
-
- if (!client->internal->params->nickname_format[0])
- return TRUE;
-
- if (!nickname || !nickname[0])
- return FALSE;
-
- cp = client->internal->params->nickname_format;
- while (cp && *cp) {
- if (*cp == '%') {
- cp++;
- continue;
- }
-
- switch(*cp) {
- case 'n':
- n = TRUE;
- break;
-
- case 'h':
- case 'H':
- case 's':
- case 'S':
- case 'a':
- break;
-
- default:
- /* Get separator character */
- if (n)
- e = *cp;
- else
- s = *cp;
- break;
- }
-
- cp++;
- }
- if (!n)
- return FALSE;
-
- /* Parse the nickname */
- nick = nickname;
- len = strlen(nick);
- if (s)
- if (strchr(nickname, s))
- nick = strchr(nickname, s) + 1;
- if (e)
- if (strchr(nick, e))
- len = strchr(nick, e) - nick;
- if (!len)
- return FALSE;
-
- *ret_nick = silc_memdup(nick, len);
- if (!(*ret_nick))
- return FALSE;
-
- SILC_LOG_DEBUG(("Parsed nickname: %s", *ret_nick));
-
- return TRUE;
-}
-
-/************************ Channel Searching Locally *************************/
-
-/* Finds entry for channel by the channel name. Returns the entry or NULL
- if the entry was not found. It is found only if the client is joined
- to the channel. */
-
-SilcChannelEntry silc_client_get_channel(SilcClient client,
- SilcClientConnection conn,
- char *channel)
-{
- SilcIDCacheEntry id_cache;
- SilcChannelEntry entry;
-
- if (!client || !conn || !channel)
- return NULL;
-
- SILC_LOG_DEBUG(("Find channel %s", channel));
-
- /* Normalize name for search */
- channel = silc_channel_name_check(channel, strlen(channel), SILC_STRING_UTF8,
- 256, NULL);
- if (!channel)
- return NULL;
-
- silc_mutex_lock(conn->internal->lock);
-
- if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
- &id_cache)) {
- silc_mutex_unlock(conn->internal->lock);
- silc_free(channel);
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Found"));
-
- entry = id_cache->context;
-
- /* Reference */
- silc_client_ref_channel(client, conn, entry);
- silc_mutex_unlock(conn->internal->lock);
-
- silc_free(channel);
-
- return entry;
-}
-
-/* Finds entry for channel by the channel ID. Returns the entry or NULL
- if the entry was not found. It is found only if the client is joined
- to the channel. */
-
-SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
- SilcClientConnection conn,
- SilcChannelID *channel_id)
-{
- SilcIDCacheEntry id_cache;
- SilcChannelEntry entry;
-
- if (!client || !conn || !channel_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Find channel by id %s",
- silc_id_render(channel_id, SILC_ID_CHANNEL)));
-
- silc_mutex_lock(conn->internal->lock);
-
- if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
- &id_cache)) {
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Found"));
-
- entry = id_cache->context;
-
- /* Reference */
- silc_client_ref_channel(client, conn, entry);
- silc_mutex_unlock(conn->internal->lock);
-
- return entry;
-}
-
-/********************** Channel Resolving from Server ***********************/
-
-/* Channel resolving context */
-typedef struct {
- SilcDList channels;
- SilcGetChannelCallback completion;
- void *context;
-} *SilcClientGetChannelInternal;
-
-/* Resolving command callback */
-
-static SilcBool silc_client_get_channel_cb(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- SilcClientGetChannelInternal i = context;
- SilcChannelEntry entry;
-
- if (error != SILC_STATUS_OK) {
- SILC_LOG_DEBUG(("Resolving failed: %s", silc_get_status_message(error)));
- if (i->completion)
- i->completion(client, conn, error, NULL, i->context);
- goto out;
- }
-
- /* Add the returned channel to list */
- if (i->completion) {
- entry = va_arg(ap, SilcChannelEntry);
- silc_client_ref_channel(client, conn, entry);
- silc_dlist_add(i->channels, entry);
- }
-
- if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) {
- /* Deliver the channels to the caller */
- if (i->completion) {
- SILC_LOG_DEBUG(("Resolved %d channels", silc_dlist_count(i->channels)));
- silc_dlist_start(i->channels);
- i->completion(client, conn, SILC_STATUS_OK, i->channels, i->context);
- }
- goto out;
- }
-
- return TRUE;
-
- out:
- silc_client_list_free_channels(client, conn, i->channels);
- silc_free(i);
- return FALSE;
-}
-
-/* Resolves channel entry from the server by the channel name. */
-
-void silc_client_get_channel_resolve(SilcClient client,
- SilcClientConnection conn,
- char *channel_name,
- SilcGetChannelCallback completion,
- void *context)
-{
- SilcClientGetChannelInternal i;
-
- if (!client || !conn || !channel_name || !completion)
- return;
-
- SILC_LOG_DEBUG(("Resolve channel %s", channel_name));
-
- i = silc_calloc(1, sizeof(*i));
- if (!i)
- return;
- i->completion = completion;
- i->context = context;
- i->channels = silc_dlist_init();
- if (!i->channels) {
- silc_free(i);
- return;
- }
-
- /* Send the command */
- if (!silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_get_channel_cb, i, 1,
- 3, channel_name, strlen(channel_name))) {
- if (completion)
- completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
- }
-}
-
-/* Resolves channel information from the server by the channel ID. */
-
-SilcUInt16
-silc_client_get_channel_by_id_resolve(SilcClient client,
- SilcClientConnection conn,
- SilcChannelID *channel_id,
- SilcGetChannelCallback completion,
- void *context)
-{
- SilcClientGetChannelInternal i;
- SilcBuffer idp;
- SilcUInt16 cmd_ident;
-
- if (!client || !conn || !channel_id || !completion)
- return 0;
-
- SILC_LOG_DEBUG(("Resolve channel by id %s",
- silc_id_render(channel_id, SILC_ID_CHANNEL)));
-
- i = silc_calloc(1, sizeof(*i));
- if (!i)
- return 0;
- i->completion = completion;
- i->context = context;
- i->channels = silc_dlist_init();
- if (!i->channels) {
- silc_free(i);
- return 0;
- }
-
- /* Send the command */
- idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
- cmd_ident = silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_get_channel_cb, i, 1,
- 5, silc_buffer_datalen(idp));
- silc_buffer_free(idp);
- if (!cmd_ident && completion)
- completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
-
- return cmd_ident;
-}
-
-/************************* Channel Entry Routines ***************************/
-
-/* Add new channel entry to the ID Cache */
-
-SilcChannelEntry silc_client_add_channel(SilcClient client,
- SilcClientConnection conn,
- const char *channel_name,
- SilcUInt32 mode,
- SilcChannelID *channel_id)
-{
- SilcChannelEntry channel;
- char *channel_namec;
-
- SILC_LOG_DEBUG(("Start"));
-
- channel = silc_calloc(1, sizeof(*channel));
- if (!channel)
- return NULL;
-
- silc_rwlock_alloc(&channel->internal.lock);
- silc_atomic_init16(&channel->internal.refcnt, 0);
- channel->id = *channel_id;
- channel->mode = mode;
-
- channel->channel_name = strdup(channel_name);
- if (!channel->channel_name) {
- silc_free(channel);
- return NULL;
- }
-
- channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
- NULL, NULL, NULL, TRUE);
- if (!channel->user_list) {
- silc_free(channel->channel_name);
- silc_free(channel);
- return NULL;
- }
-
- /* Normalize channel name */
- channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
- SILC_STRING_UTF8, 256, NULL);
- if (!channel_namec) {
- silc_free(channel->channel_name);
- silc_hash_table_free(channel->user_list);
- silc_free(channel);
- return NULL;
- }
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Add channel to cache, the normalized channel name is saved to cache */
- if (!silc_idcache_add(conn->internal->channel_cache, channel_namec,
- &channel->id, channel)) {
- silc_free(channel_namec);
- silc_free(channel->channel_name);
- silc_hash_table_free(channel->user_list);
- silc_free(channel);
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- silc_mutex_unlock(conn->internal->lock);
- silc_client_ref_channel(client, conn, channel);
-
- SILC_LOG_DEBUG(("Added %p", channel));
-
- return channel;
-}
-
-/* Removes channel from the cache by the channel entry. */
-
-SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
- SilcChannelEntry channel)
-{
- SilcIDCacheEntry id_cache;
- SilcBool ret;
- SilcCipher key;
- SilcHmac hmac;
-
- if (!channel)
- return FALSE;
-
- if (silc_atomic_sub_int16(&channel->internal.refcnt, 1) > 0)
- return FALSE;
-
- SILC_LOG_DEBUG(("Deleting channel %p", channel));
-
- silc_mutex_lock(conn->internal->lock);
- if (silc_idcache_find_by_context(conn->internal->channel_cache, channel,
- &id_cache))
- silc_free(id_cache->name);
- ret = silc_idcache_del_by_context(conn->internal->channel_cache,
- channel, NULL);
- silc_mutex_unlock(conn->internal->lock);
-
- if (!ret)
- return FALSE;
-
- silc_client_empty_channel(client, conn, channel);
- silc_hash_table_free(channel->user_list);
- silc_free(channel->channel_name);
- silc_free(channel->topic);
- if (channel->founder_key)
- silc_pkcs_public_key_free(channel->founder_key);
- if (channel->internal.send_key)
- silc_cipher_free(channel->internal.send_key);
- if (channel->internal.receive_key)
- silc_cipher_free(channel->internal.receive_key);
- if (channel->internal.hmac)
- silc_hmac_free(channel->internal.hmac);
- if (channel->internal.old_channel_keys) {
- silc_dlist_start(channel->internal.old_channel_keys);
- while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
- silc_cipher_free(key);
- silc_dlist_uninit(channel->internal.old_channel_keys);
- }
- if (channel->internal.old_hmacs) {
- silc_dlist_start(channel->internal.old_hmacs);
- while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
- silc_hmac_free(hmac);
- silc_dlist_uninit(channel->internal.old_hmacs);
- }
- if (channel->channel_pubkeys)
- silc_argument_list_free(channel->channel_pubkeys,
- SILC_ARGUMENT_PUBLIC_KEY);
- silc_client_del_channel_private_keys(client, conn, channel);
- silc_atomic_uninit16(&channel->internal.refcnt);
- silc_rwlock_free(channel->internal.lock);
- silc_schedule_task_del_by_context(conn->client->schedule, channel);
- silc_free(channel);
-
- return ret;
-}
-
-/* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
- if the ID could not be changed. This handles entry locking internally. */
-
-SilcBool silc_client_replace_channel_id(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcChannelID *new_id)
-{
- SilcBool ret = FALSE;
-
- if (!new_id)
- return FALSE;
-
- SILC_LOG_DEBUG(("Old Channel ID id(%s)",
- silc_id_render(&channel->id, SILC_ID_CHANNEL)));
- SILC_LOG_DEBUG(("New Channel ID id(%s)",
- silc_id_render(new_id, SILC_ID_CHANNEL)));
-
- /* Update the ID */
- silc_rwlock_wrlock(channel->internal.lock);
- silc_mutex_lock(conn->internal->lock);
- silc_idcache_update_by_context(conn->internal->channel_cache, channel,
- new_id, NULL, FALSE);
- silc_mutex_unlock(conn->internal->lock);
- silc_rwlock_unlock(channel->internal.lock);
-
- return ret;
-}
-
-/* Lock channel */
-
-void silc_client_lock_channel(SilcChannelEntry channel_entry)
-{
- silc_rwlock_rdlock(channel_entry->internal.lock);
-}
-
-/* Unlock channel */
-
-void silc_client_unlock_channel(SilcChannelEntry channel_entry)
-{
- silc_rwlock_unlock(channel_entry->internal.lock);
-}
-
-/* Take reference of channel entry */
-
-SilcChannelEntry silc_client_ref_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel_entry)
-{
- silc_atomic_add_int16(&channel_entry->internal.refcnt, 1);
- SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
- silc_atomic_get_int16(&channel_entry->internal.refcnt) - 1,
- silc_atomic_get_int16(&channel_entry->internal.refcnt)));
- return channel_entry;
-}
-
-/* Release reference of channel entry */
-
-void silc_client_unref_channel(SilcClient client, SilcClientConnection conn,
- SilcChannelEntry channel_entry)
-{
- if (channel_entry) {
- SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
- silc_atomic_get_int16(&channel_entry->internal.refcnt),
- silc_atomic_get_int16(&channel_entry->internal.refcnt)
- - 1));
- silc_client_del_channel(client, conn, channel_entry);
- }
-}
-
-/* Free channel entry list */
-
-void silc_client_list_free_channels(SilcClient client,
- SilcClientConnection conn,
- SilcDList channel_list)
-{
- SilcChannelEntry channel_entry;
-
- if (channel_list) {
- silc_dlist_start(channel_list);
- while ((channel_entry = silc_dlist_get(channel_list)))
- silc_client_unref_channel(client, conn, channel_entry);
-
- silc_dlist_uninit(channel_list);
- }
-}
-
-/************************* Server Searching Locally *************************/
-
-/* Finds entry for server by the server name. */
-
-SilcServerEntry silc_client_get_server(SilcClient client,
- SilcClientConnection conn,
- char *server_name)
-{
- SilcIDCacheEntry id_cache;
- SilcServerEntry entry;
-
- if (!client || !conn || !server_name)
- return NULL;
-
- SILC_LOG_DEBUG(("Find server by name %s", server_name));
-
- /* Normalize server name for search */
- server_name = silc_identifier_check(server_name, strlen(server_name),
- SILC_STRING_UTF8, 256, NULL);
- if (!server_name)
- return NULL;
-
- silc_mutex_lock(conn->internal->lock);
-
- if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
- server_name, &id_cache)) {
- silc_free(server_name);
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Found"));
-
- /* Reference */
- entry = id_cache->context;
- silc_client_ref_server(client, conn, entry);
-
- silc_mutex_unlock(conn->internal->lock);
-
- silc_free(server_name);
-
- return entry;
-}
-
-/* Finds entry for server by the server ID. */
-
-SilcServerEntry silc_client_get_server_by_id(SilcClient client,
- SilcClientConnection conn,
- SilcServerID *server_id)
-{
- SilcIDCacheEntry id_cache;
- SilcServerEntry entry;
-
- if (!client || !conn || !server_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Find server by id %s",
- silc_id_render(server_id, SILC_ID_SERVER)));
-
- silc_mutex_lock(conn->internal->lock);
-
- if (!silc_idcache_find_by_id_one(conn->internal->server_cache,
- server_id, &id_cache)) {
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Found"));
-
- /* Reference */
- entry = id_cache->context;
- silc_client_ref_server(client, conn, entry);
-
- silc_mutex_unlock(conn->internal->lock);
-
- return entry;
-}
-
-/*********************** Server Resolving from Server ***********************/
-
-/* Resolving context */
-typedef struct {
- SilcDList servers;
- SilcGetServerCallback completion;
- void *context;
-} *SilcClientGetServerInternal;
-
-/* Resolving command callback */
-
-static SilcBool silc_client_get_server_cb(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- SilcClientGetServerInternal i = context;
- SilcServerEntry server;
-
- if (error != SILC_STATUS_OK) {
- SILC_LOG_DEBUG(("Resolving failed: %s", silc_get_status_message(error)));
- if (i->completion)
- i->completion(client, conn, error, NULL, i->context);
- goto out;
- }
-
- /* Add the returned servers to list */
- if (i->completion) {
- server = va_arg(ap, SilcServerEntry);
- silc_client_ref_server(client, conn, server);
- silc_dlist_add(i->servers, server);
- server->internal.resolve_cmd_ident = 0;
- }
-
- if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END) {
- /* Deliver the servers to the caller */
- if (i->completion) {
- SILC_LOG_DEBUG(("Resolved %d servers", silc_dlist_count(i->servers)));
- silc_dlist_start(i->servers);
- i->completion(client, conn, SILC_STATUS_OK, i->servers, i->context);
- }
- goto out;
- }
-
- return TRUE;
-
- out:
- silc_client_list_free_servers(client, conn, i->servers);
- silc_free(i);
- return FALSE;
-}
-
-/* Resolve server by server ID */
-
-SilcUInt16
-silc_client_get_server_by_id_resolve(SilcClient client,
- SilcClientConnection conn,
- SilcServerID *server_id,
- SilcGetServerCallback completion,
- void *context)
-{
- SilcClientGetServerInternal i;
- SilcServerEntry server;
- SilcBuffer idp;
- SilcUInt16 cmd_ident;
-
- if (!client || !conn || !server_id || !completion)
- return 0;
-
- SILC_LOG_DEBUG(("Resolve server by id %s",
- silc_id_render(server_id, SILC_ID_SERVER)));
-
- i = silc_calloc(1, sizeof(*i));
- if (!i)
- return 0;
- i->completion = completion;
- i->context = context;
- i->servers = silc_dlist_init();
- if (!i->servers) {
- silc_free(i);
- return 0;
- }
-
- /* Attach to resolving, if on going */
- server = silc_client_get_server_by_id(client, conn, server_id);
- if (server && server->internal.resolve_cmd_ident) {
- SILC_LOG_DEBUG(("Attach to existing resolving"));
- silc_client_unref_server(client, conn, server);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
- server->internal.resolve_cmd_ident,
- silc_client_get_server_cb, i);
- return server->internal.resolve_cmd_ident;
- }
-
- /* Send the command */
- idp = silc_id_payload_encode(server_id, SILC_ID_SERVER);
- cmd_ident = silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_get_server_cb, i, 1,
- 5, silc_buffer_datalen(idp));
- silc_buffer_free(idp);
- if (!cmd_ident && completion)
- completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context);
-
- if (server && cmd_ident)
- server->internal.resolve_cmd_ident = cmd_ident;
-
- silc_client_unref_server(client, conn, server);
-
- return cmd_ident;
-}
-
-/************************** Server Entry Routines ***************************/
-
-/* Add new server entry */
-
-SilcServerEntry silc_client_add_server(SilcClient client,
- SilcClientConnection conn,
- const char *server_name,
- const char *server_info,
- SilcServerID *server_id)
-{
- SilcServerEntry server_entry;
- char *server_namec = NULL;
-
- if (!server_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Adding new server %s", server_name));
-
- server_entry = silc_calloc(1, sizeof(*server_entry));
- if (!server_entry)
- return NULL;
-
- silc_rwlock_alloc(&server_entry->internal.lock);
- silc_atomic_init8(&server_entry->internal.refcnt, 0);
- server_entry->id = *server_id;
- if (server_name)
- server_entry->server_name = strdup(server_name);
- if (server_info)
- server_entry->server_info = strdup(server_info);
-
- /* Normalize server name */
- if (server_name) {
- server_namec = silc_identifier_check(server_name, strlen(server_name),
- SILC_STRING_UTF8, 256, NULL);
- if (!server_namec) {
- silc_free(server_entry->server_name);
- silc_free(server_entry->server_info);
- silc_free(server_entry);
- return NULL;
- }
- }
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Add server to cache */
- if (!silc_idcache_add(conn->internal->server_cache, server_namec,
- &server_entry->id, server_entry)) {
- silc_free(server_namec);
- silc_free(server_entry->server_name);
- silc_free(server_entry->server_info);
- silc_free(server_entry);
- silc_mutex_unlock(conn->internal->lock);
- return NULL;
- }
-
- silc_mutex_unlock(conn->internal->lock);
- silc_client_ref_server(client, conn, server_entry);
-
- SILC_LOG_DEBUG(("Added %p", server_entry));
-
- return server_entry;
-}
-
-/* Removes server from the cache by the server entry. */
-
-SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn,
- SilcServerEntry server)
-{
- SilcIDCacheEntry id_cache;
- SilcBool ret;
-
- if (!server)
- return FALSE;
-
- if (silc_atomic_sub_int8(&server->internal.refcnt, 1) > 0)
- return FALSE;
-
- SILC_LOG_DEBUG(("Deleting server %p", server));
-
- silc_mutex_lock(conn->internal->lock);
- if (silc_idcache_find_by_context(conn->internal->server_cache, server,
- &id_cache))
- silc_free(id_cache->name);
- ret = silc_idcache_del_by_context(conn->internal->server_cache,
- server, NULL);
- silc_mutex_unlock(conn->internal->lock);
-
- silc_free(server->server_name);
- silc_free(server->server_info);
- if (server->public_key)
- silc_pkcs_public_key_free(server->public_key);
- silc_atomic_uninit8(&server->internal.refcnt);
- silc_rwlock_free(server->internal.lock);
- silc_free(server);
-
- return ret;
-}
-
-/* Updates the `server_entry' with the new information sent as argument. */
-
-void silc_client_update_server(SilcClient client,
- SilcClientConnection conn,
- SilcServerEntry server_entry,
- const char *server_name,
- const char *server_info)
-{
- char *server_namec = NULL;
-
- SILC_LOG_DEBUG(("Updating server %p", server_entry));
-
- if (server_name &&
- (!server_entry->server_name ||
- !silc_utf8_strcasecmp(server_entry->server_name, server_name))) {
-
- server_namec = silc_identifier_check(server_name, strlen(server_name),
- SILC_STRING_UTF8, 256, NULL);
- if (!server_namec)
- return;
-
- silc_free(server_entry->server_name);
- server_entry->server_name = strdup(server_name);
- if (!server_entry->server_name)
- return;
-
- /* Update cache entry */
- silc_mutex_lock(conn->internal->lock);
- silc_idcache_update_by_context(conn->internal->server_cache, server_entry,
- NULL, server_namec, TRUE);
- silc_mutex_unlock(conn->internal->lock);
- }
-
- if (server_info &&
- (!server_entry->server_info ||
- !silc_utf8_strcasecmp(server_entry->server_info, server_info))) {
- silc_free(server_entry->server_info);
- server_entry->server_info = strdup(server_info);
- }
-}
-
-/* Lock server */
-
-void silc_client_lock_server(SilcServerEntry server_entry)
-{
- silc_rwlock_rdlock(server_entry->internal.lock);
-}
-
-/* Unlock server */
-
-void silc_client_unlock_server(SilcServerEntry server_entry)
-{
- silc_rwlock_unlock(server_entry->internal.lock);
-}
-
-/* Take reference of server entry */
-
-SilcServerEntry silc_client_ref_server(SilcClient client,
- SilcClientConnection conn,
- SilcServerEntry server_entry)
-{
- silc_atomic_add_int8(&server_entry->internal.refcnt, 1);
- SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry,
- silc_atomic_get_int8(&server_entry->internal.refcnt) - 1,
- silc_atomic_get_int8(&server_entry->internal.refcnt)));
- return server_entry;
-}
-
-/* Release reference of server entry */
-
-void silc_client_unref_server(SilcClient client, SilcClientConnection conn,
- SilcServerEntry server_entry)
-{
- if (server_entry) {
- SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry,
- silc_atomic_get_int8(&server_entry->internal.refcnt),
- silc_atomic_get_int8(&server_entry->internal.refcnt)
- - 1));
- silc_client_del_server(client, conn, server_entry);
- }
-}
-
-/* Free server entry list */
-
-void silc_client_list_free_servers(SilcClient client,
- SilcClientConnection conn,
- SilcDList server_list)
-{
- SilcServerEntry server_entry;
-
- if (server_list) {
- silc_dlist_start(server_list);
- while ((server_entry = silc_dlist_get(server_list)))
- silc_client_unref_server(client, conn, server_entry);
-
- silc_dlist_uninit(server_list);
- }
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2004 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
+static int
+silc_client_connect_to_client(SilcClient client,
+ SilcClientConnection conn, int port,
+ char *host, void *context);
+static int
+silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx);
+SILC_TASK_CALLBACK(silc_client_ftp_connected);
+static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session,
+ int sock);
/* File transmission session */
struct SilcClientFtpSessionStruct {
- SilcClient client; /* Client */
- SilcClientConnection server_conn; /* Connection to server */
- SilcClientConnection conn; /* Connection to remote host */
- SilcClientEntry client_entry; /* The client entry */
- SilcClientListener listener; /* Listener */
- SilcAsyncOperation op; /* Operation for connecting */
- SilcClientConnectionParams params; /* Connection params */
- SilcPublicKey public_key; /* Public key used in key exchange */
- SilcPrivateKey private_key; /* Private key used in key exchange */
- SilcUInt32 session_id; /* File transfer ID */
-
- SilcClientFileMonitor monitor; /* File transfer monitor callback */
+ SilcUInt32 session_id;
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcClientEntry client_entry;
+
+ SilcSocketConnection sock;
+ SilcBuffer packet;
+
+ char *hostname;
+ SilcUInt16 port;
+ int listener;
+
+ SilcClientFileMonitor monitor;
void *monitor_context;
- SilcClientFileAskName ask_name; /* File name asking callback */
+ SilcClientFileAskName ask_name;
void *ask_name_context;
- char *filepath; /* The remote filename */
- char *path; /* User given path to save the file */
-
- SilcStream stream; /* Wrapped SilcPacketStream */
- SilcSFTP sftp; /* SFTP server/client */
- SilcSFTPFilesystem fs; /* SFTP memory file system */
- SilcSFTPHandle dir_handle; /* SFTP session directory handle */
- SilcSFTPHandle read_handle; /* SFTP session file handles */
-
- char *hostname; /* Remote host */
- SilcUInt16 port; /* Remote port */
- SilcUInt64 filesize; /* File size */
- SilcUInt64 read_offset; /* Current read offset */
- int fd; /* File descriptor */
- unsigned int initiator : 1; /* File sender sets this to TRUE */
- unsigned int closed : 1; /* silc_client_file_close called */
+ char *filepath;
+ char *path;
+
+ SilcSFTP sftp;
+ SilcSFTPFilesystem fs;
+ unsigned int server : 1; /* File sender sets this to TRUE */
+ unsigned int bound : 1;
+
+ SilcSFTPHandle dir_handle;
+ SilcSFTPHandle read_handle;
+ SilcUInt64 filesize;
+ SilcUInt64 read_offset;
+ int fd;
};
-/************************* SFTP Server Callbacks ****************************/
+SILC_TASK_CALLBACK(silc_client_ftp_connected)
+{
+ SilcClientInternalConnectContext *ctx =
+ (SilcClientInternalConnectContext *)context;
+ SilcClient client = ctx->client;
+ SilcClientConnection conn = ctx->conn;
+ SilcClientFtpSession session = (SilcClientFtpSession)ctx->context;
+ int opt, opt_len = sizeof(opt);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Check the socket status as it might be in error */
+ silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
+ if (opt != 0) {
+ if (ctx->tries < 2) {
+ /* Connection failed but lets try again */
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of client %s resumed",
+ ctx->port, ctx->host);
+
+ /* Unregister old connection try */
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_net_close_connection(fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+
+ /* Try again */
+ silc_client_connect_to_client_internal(ctx);
+ ctx->tries++;
+ } else {
+ /* Connection failed and we won't try anymore */
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_net_close_connection(fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+ silc_free(ctx);
+ silc_client_ftp_session_free(session);
+ }
+ return;
+ }
+
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+
+ /* Start the key agreement */
+ silc_client_ftp_start_key_agreement(session, fd);
+}
+
+static int
+silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
+{
+ int sock;
+
+ /* Create connection to server asynchronously */
+ sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
+ if (sock < 0)
+ return -1;
+
+ /* Register task that will receive the async connect and will
+ read the result. */
+ ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
+ silc_client_ftp_connected,
+ (void *)ctx, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+ silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
+ FALSE);
+ ctx->sock = sock;
+ return sock;
+}
+
+static int
+silc_client_connect_to_client(SilcClient client,
+ SilcClientConnection conn, int port,
+ char *host, void *context)
+{
+ SilcClientInternalConnectContext *ctx;
+
+ /* Allocate internal context for connection process. This is
+ needed as we are doing async connecting. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->conn = conn;
+ ctx->host = strdup(host);
+ ctx->port = port;
+ ctx->tries = 0;
+ ctx->context = context;
+
+ /* Do the actual connecting process */
+ return silc_client_connect_to_client_internal(ctx);
+}
+
+/* SFTP packet send callback. This will use preallocated buffer to avoid
+ reallocation of outgoing data buffer everytime. */
+
+static void silc_client_ftp_send_packet(SilcBuffer packet, void *context)
+{
+ SilcClientFtpSession session = (SilcClientFtpSession)context;
+ SilcClient client = session->client;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate outgoing packet */
+ if (!session->packet)
+ session->packet = silc_buffer_alloc(1 + packet->len);
+
+ /* Enlarge outgoing packet if needed */
+ if (session->packet->truelen < 1 + packet->len)
+ session->packet = silc_buffer_realloc(session->packet, 1 + packet->len);
+
+ /* Encode packet */
+ silc_buffer_pull_tail(session->packet, 1 + packet->len);
+ silc_buffer_format(session->packet,
+ SILC_STR_UI_CHAR(1),
+ SILC_STR_UI_XNSTRING(packet->data, packet->len),
+ SILC_STR_END);
+
+ /* Send the packet immediately */
+ silc_client_packet_send(client, session->sock, SILC_PACKET_FTP, NULL,
+ 0, NULL, NULL, session->packet->data,
+ session->packet->len, TRUE);
+
+ /* Clear buffer */
+ session->packet->data = session->packet->tail = session->packet->head;
+ session->packet->len = 0;
+}
/* SFTP monitor callback for SFTP server. This reports the application
how the transmission is going along. This function is for the client
}
}
-/************************* SFTP Client Callbacks ****************************/
-
/* Returns the read data. This is the downloader's function (client side)
to receive the read data and read more until EOF is received from
the other side. This will also monitor the transmission and notify
SILC_PACKET_MAX_LEN - 1024,
silc_client_ftp_data, session);
- /* Write the read data to the real file */
- silc_file_write(session->fd, data, data_len);
-
/* Call monitor callback */
if (session->monitor)
(*session->monitor)(session->client, session->conn,
session->read_offset, session->filesize,
session->client_entry, session->session_id,
session->filepath, session->monitor_context);
+
+ /* Write the read data to the real file */
+ silc_file_write(session->fd, data, data_len);
}
/* Returns handle for the opened file. This is the downloader's function.
/* Open the actual local file */
memset(path, 0, sizeof(path));
- silc_snprintf(path, sizeof(path) - 1, "%s%s", session->path ?
- session->path : "", session->filepath);
+ snprintf(path, sizeof(path) - 1, "%s%s", session->path ?
+ session->path : "", session->filepath);
session->fd = silc_file_open(path, O_RDWR | O_CREAT | O_EXCL);
if (session->fd < 0) {
/* Call monitor callback */
session->filepath, session->monitor_context);
}
-/* Ask filename completion callback. Delivers the filepath selected by
- user. */
-
static void silc_client_ftp_ask_name(const char *filepath,
void *context)
{
silc_sftp_opendir(sftp, "", silc_client_ftp_opendir_handle, session);
}
-/* SFTP stream error callback */
-
-static void silc_client_ftp_error(SilcSFTP sftp, SilcSFTPStatus status,
- void *context)
-{
-
-}
-
-/************************ Static utility functions **************************/
-
-/* Free session resources. Connection must be closed before getting
- here. */
-
-static void silc_client_ftp_session_free(SilcClientFtpSession session)
-{
- SILC_LOG_DEBUG(("Free session %d", session->session_id));
-
- silc_dlist_del(session->client->internal->ftp_sessions, session);
-
- /* Abort connecting */
- if (session->op)
- silc_async_abort(session->op, NULL, NULL);
-
- /* Destroy SFTP */
- if (session->sftp) {
- if (session->initiator)
- silc_sftp_server_shutdown(session->sftp);
- else
- silc_sftp_client_shutdown(session->sftp);
- }
- if (session->fs)
- silc_sftp_fs_memory_free(session->fs);
-
- /* Destroy listener */
- if (session->listener)
- silc_client_listener_free(session->listener);
-
- /* Destroy wrapped stream */
- if (session->stream)
- silc_stream_destroy(session->stream);
-
- silc_client_unref_client(session->client, session->server_conn,
- session->client_entry);
- silc_free(session->hostname);
- silc_free(session->filepath);
- silc_free(session->path);
- silc_free(session);
-}
-
-/* File transfer session timeout */
+/* This callback is called after the key agreement protocol has been
+ performed. This calls the final completion callback for the application. */
-SILC_TASK_CALLBACK(silc_client_ftp_timeout)
+SILC_TASK_CALLBACK(silc_client_ftp_key_agreement_final)
{
- SilcClientFtpSession session = context;
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClientFtpSession session = (SilcClientFtpSession)ctx->context;
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
- SILC_LOG_DEBUG(("Timeout"));
+ SILC_LOG_DEBUG(("Start"));
- /* Close connection (destroyes the session context later). If it is
- already closed, destroy the session now. */
- if (session->conn) {
- silc_client_close_connection(session->client, session->conn);
- session->conn = NULL;
- } else {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Call monitor callback */
if (session->monitor)
(*session->monitor)(session->client, session->conn,
SILC_CLIENT_FILE_MONITOR_ERROR,
- SILC_CLIENT_FILE_TIMEOUT, 0, 0,
+ SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED, 0, 0,
session->client_entry, session->session_id,
session->filepath, session->monitor_context);
- silc_client_ftp_session_free(context);
+ /* Error occured during protocol */
+ silc_ske_free_key_material(ctx->keymat);
+ goto out;
}
-}
-/* File transfer session closing task callback */
-
-SILC_TASK_CALLBACK(silc_client_file_close_final)
-{
- SilcClientFtpSession session = context;
-
- /* Close connection (destroyes the session context later). If it is
- already closed, destroy the session now. */
- if (session->conn) {
- silc_client_close_connection(session->client, session->conn);
- session->conn = NULL;
+ /* Set keys into use */
+ silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
+ ctx->ske->prop->cipher,
+ ctx->ske->prop->pkcs,
+ ctx->ske->prop->hash,
+ ctx->ske->prop->hmac,
+ ctx->ske->prop->group,
+ ctx->responder);
+
+ if (!session->server) {
+ /* If we are the SFTP client then start the SFTP session and retrieve
+ the info about the file available for download. */
+ session->sftp = silc_sftp_client_start(silc_client_ftp_send_packet,
+ session, silc_client_ftp_version,
+ session);
} else {
- silc_client_ftp_session_free(context);
- }
-}
+ /* Start SFTP server */
+ session->sftp = silc_sftp_server_start(silc_client_ftp_send_packet,
+ session, session->fs);
-/* Client resolving callback. Continues with the FTP packet processing */
-
-static void silc_client_ftp_client_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- SilcFSMThread thread = context;
- SilcPacket packet = silc_fsm_get_state_context(thread);
-
- /* If no client found, ignore the packet, a silent error */
- if (!clients) {
- silc_packet_free(packet);
- silc_fsm_finish(thread);
- return;
+ /* Monitor transmission */
+ silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ,
+ silc_client_ftp_monitor, session);
}
- /* Continue processing the packet */
- SILC_FSM_CALL_CONTINUE(context);
+ /* Set this as active session */
+ conn->internal->active_session = session;
+
+ out:
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx->dest_id);
+ ctx->sock->protocol = NULL;
+ silc_socket_free(ctx->sock);
+ silc_free(ctx);
+ silc_protocol_free(protocol);
}
-/* FTP packet payload encoder/decoder. This is called for every FTP packet.
- We add/remove FTP payload in this function, because SFTP library does not
- add/remove it. */
+/* The downloader's function to start the key agreement protocol with the
+ remote client after we have connected to it. */
-static SilcBool
-silc_client_ftp_coder(SilcStream stream, SilcStreamStatus status,
- SilcBuffer buffer, void *context)
+static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session,
+ int sock)
{
- /* Pull FTP type in the payload, revealing SFTP payload */
- if (status == SILC_STREAM_CAN_READ) {
- if (silc_buffer_len(buffer) >= 1)
- silc_buffer_pull(buffer, 1);
- return TRUE;
- }
+ SilcClient client = session->client;
+ SilcClientKEInternalContext *proto_ctx;
+ SilcProtocol protocol;
+ SilcClientConnection conn;
+ void *context;
- /* Add FTP type before SFTP data */
- if (status == SILC_STREAM_CAN_WRITE) {
- if (silc_buffer_format(buffer,
- SILC_STR_UI_CHAR(1),
- SILC_STR_END) < 0)
- return FALSE;
- return TRUE;
- }
+ SILC_LOG_DEBUG(("Start"));
- return FALSE;
+ /* Call monitor callback */
+ if (session->monitor)
+ (*session->monitor)(session->client, session->conn,
+ SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT,
+ SILC_CLIENT_FILE_OK, 0, 0,
+ session->client_entry, session->session_id,
+ NULL, session->monitor_context);
+
+ /* Add new connection for this session */
+ conn = silc_client_add_connection(client, NULL, session->hostname,
+ session->port, session);
+
+ /* Allocate new socket connection object */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_CLIENT, (void *)conn, &conn->sock);
+ conn->sock->hostname = strdup(session->hostname);
+ conn->sock->port = silc_net_get_remote_port(sock);
+ session->sock = silc_socket_dup(conn->sock);
+
+ /* Allocate internal context for key exchange protocol. This is
+ sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = client;
+ proto_ctx->sock = silc_socket_dup(conn->sock);
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = FALSE;
+ proto_ctx->context = session;
+ proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
+
+ /* Perform key exchange protocol. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &protocol, (void *)proto_ctx,
+ silc_client_ftp_key_agreement_final);
+ conn->sock->protocol = protocol;
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it will
+ be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)client;
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Execute the protocol */
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
}
-/* FTP Connection callback. The SFTP session is started here. */
+/* The remote client's (the client who made the file available for download)
+ function for accepting incoming connection. This will also start the
+ key agreement protocol with the other client. */
-static void
-silc_client_ftp_connect_completion(SilcClient client,
- SilcClientConnection conn,
- SilcClientConnectionStatus status,
- SilcStatus error,
- const char *message,
- void *context)
+SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement)
{
- SilcClientFtpSession session = context;
-
- session->conn = conn;
- session->op = NULL;
-
- silc_schedule_task_del_by_context(client->schedule, session);
-
- switch (status) {
- case SILC_CLIENT_CONN_SUCCESS:
- SILC_LOG_DEBUG(("Connected, conn %p", conn));
-
- /* Wrap the connection packet stream */
- session->stream = silc_packet_stream_wrap(conn->stream, SILC_PACKET_FTP,
- 0, FALSE,
- silc_client_ftp_coder, session);
- if (!session->stream) {
- /* Call monitor callback */
- if (session->monitor)
- (*session->monitor)(session->client, session->conn,
- SILC_CLIENT_FILE_MONITOR_ERROR,
- SILC_CLIENT_FILE_ERROR, 0, 0,
- session->client_entry, session->session_id,
- session->filepath, session->monitor_context);
- silc_client_close_connection(client, conn);
- session->conn = NULL;
- return;
- }
-
- if (!session->initiator) {
- /* If we are the SFTP client then start the SFTP session and retrieve
- the info about the file available for download. */
- session->sftp = silc_sftp_client_start(session->stream,
- conn->internal->schedule,
- silc_client_ftp_version,
- silc_client_ftp_error, session);
- } else {
- /* Start SFTP server */
- session->sftp = silc_sftp_server_start(session->stream,
- conn->internal->schedule,
- silc_client_ftp_error, session,
- session->fs);
-
- /* Monitor transmission */
- silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ,
- silc_client_ftp_monitor, session);
- }
-
- break;
-
- case SILC_CLIENT_CONN_DISCONNECTED:
- SILC_LOG_DEBUG(("Disconnected %p", conn));
-
- /* Call monitor callback */
- if (session->monitor)
- (*session->monitor)(session->client, session->conn,
- SILC_CLIENT_FILE_MONITOR_DISCONNECT,
- SILC_CLIENT_FILE_ERROR, 0, 0,
- session->client_entry, session->session_id,
- session->filepath, session->monitor_context);
-
- /* Connection already closed */
- session->conn = NULL;
-
- /* If closed by user, destroy the session now */
- if (session->closed)
- silc_client_ftp_session_free(session);
- break;
+ SilcClientFtpSession session = (SilcClientFtpSession)context;
+ SilcClient client = session->client;
+ SilcClientConnection conn;
+ SilcSocketConnection newsocket;
+ SilcClientKEInternalContext *proto_ctx;
+ int sock;
- case SILC_CLIENT_CONN_ERROR_TIMEOUT:
- SILC_LOG_DEBUG(("Connecting timeout"));
+ SILC_LOG_DEBUG(("Start"));
+ sock = silc_net_accept_connection(session->listener);
+ if (sock < 0) {
/* Call monitor callback */
if (session->monitor)
(*session->monitor)(session->client, session->conn,
SILC_CLIENT_FILE_MONITOR_ERROR,
- SILC_CLIENT_FILE_TIMEOUT, 0, 0,
+ SILC_CLIENT_FILE_ERROR, 0, 0,
session->client_entry, session->session_id,
session->filepath, session->monitor_context);
+ return;
+ }
- /* Connection already closed */
- session->conn = NULL;
- break;
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
- default:
- SILC_LOG_DEBUG(("Connecting error %d", status));
+ /* Allocate new socket connection object */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_CLIENT, NULL, &newsocket);
+ /* Perform name and address lookups for the remote host. */
+ silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
+ if (!newsocket->hostname && !newsocket->ip) {
/* Call monitor callback */
if (session->monitor)
(*session->monitor)(session->client, session->conn,
SILC_CLIENT_FILE_MONITOR_ERROR,
- status != SILC_CLIENT_CONN_ERROR ?
- SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED :
- SILC_CLIENT_FILE_CONNECT_FAILED, 0, 0,
+ SILC_CLIENT_FILE_ERROR, 0, 0,
session->client_entry, session->session_id,
session->filepath, session->monitor_context);
-
- /* Connection already closed */
- session->conn = NULL;
- break;
+ return;
}
-}
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
+ newsocket->port = silc_net_get_remote_port(sock);
-/*************************** File Transfer API ******************************/
+ /* Call monitor callback */
+ if (session->monitor)
+ (*session->monitor)(session->client, session->conn,
+ SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT,
+ SILC_CLIENT_FILE_OK, 0, 0,
+ session->client_entry, session->session_id,
+ NULL, session->monitor_context);
+
+ /* Add new connection for this session */
+ conn = silc_client_add_connection(client, NULL, newsocket->hostname,
+ newsocket->port, session);
+ conn->sock = newsocket;
+ conn->sock->user_data = conn;
+ session->sock = silc_socket_dup(conn->sock);
+
+ /* Allocate internal context for key exchange protocol. This is
+ sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = client;
+ proto_ctx->sock = silc_socket_dup(conn->sock);
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = TRUE;
+ proto_ctx->context = session;
+ proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
+
+ /* Prepare the connection for key exchange protocol. We allocate the
+ protocol but will not start it yet. The connector will be the
+ initiator of the protocol thus we will wait for initiation from
+ there before we start the protocol. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &newsocket->protocol, proto_ctx,
+ silc_client_ftp_key_agreement_final);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it
+ will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)client;
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
+}
/* Free all file transfer sessions. */
-void silc_client_ftp_free_sessions(SilcClient client)
+void silc_client_ftp_free_sessions(SilcClient client,
+ SilcClientConnection conn)
{
- SilcClientFtpSession session;
-
- if (!client->internal->ftp_sessions)
- return;
-
- silc_dlist_start(client->internal->ftp_sessions);
- while ((session = silc_dlist_get(client->internal->ftp_sessions)))
- silc_client_ftp_session_free(session);
- silc_dlist_del(client->internal->ftp_sessions, session);
+ if (conn->internal->ftp_sessions) {
+ SilcClientFtpSession session;
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
+ if (session->sock)
+ session->sock->user_data = NULL;
+ silc_client_ftp_session_free(session);
+ }
+ silc_dlist_del(conn->internal->ftp_sessions, session);
+ }
}
/* Free file transfer session by client entry. */
-void silc_client_ftp_session_free_client(SilcClient client,
+void silc_client_ftp_session_free_client(SilcClientConnection conn,
SilcClientEntry client_entry)
{
SilcClientFtpSession session;
- if (!client->internal->ftp_sessions)
+ if (!conn->internal->ftp_sessions)
return;
/* Get the session */
- silc_dlist_start(client->internal->ftp_sessions);
- while ((session = silc_dlist_get(client->internal->ftp_sessions)))
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
if (session->client_entry == client_entry)
silc_client_ftp_session_free(session);
+ }
+}
+
+/* Free session resources. */
+
+void silc_client_ftp_session_free(SilcClientFtpSession session)
+{
+ SilcClientConnection conn;
+
+ SILC_LOG_DEBUG(("Free session"));
+
+ if (session->conn && session->conn->internal->ftp_sessions)
+ silc_dlist_del(session->conn->internal->ftp_sessions, session);
+
+ if (session->conn && session->conn->internal->active_session == session)
+ session->conn->internal->active_session = NULL;
+
+ if (session->sftp) {
+ if (session->server)
+ silc_sftp_server_shutdown(session->sftp);
+ else
+ silc_sftp_client_shutdown(session->sftp);
+ }
+
+ if (session->fs)
+ silc_sftp_fs_memory_free(session->fs);
+
+ /* Destroy listener */
+ if (session->listener) {
+ silc_schedule_unset_listen_fd(session->client->schedule,
+ session->listener);
+ silc_net_close_connection(session->listener);
+ silc_schedule_task_del_by_fd(session->client->schedule, session->listener);
+ }
+
+ /* Destroy session connection */
+ if (session->sock) {
+ silc_schedule_unset_listen_fd(session->client->schedule,
+ session->sock->sock);
+ silc_net_close_connection(session->sock->sock);
+
+ if (session->sock->user_data) {
+ conn = (SilcClientConnection)session->sock->user_data;
+
+ if (conn->internal->active_session == session)
+ conn->internal->active_session = NULL;
+
+ silc_client_close_connection_real(session->client, session->sock, conn);
+ } else {
+ silc_socket_free(session->sock);
+ }
+ }
+
+ if (session->packet)
+ silc_buffer_free(session->packet);
+
+ silc_free(session->hostname);
+ silc_free(session->filepath);
+ silc_free(session->path);
+ memset(session, 'F', sizeof(*session));
+ silc_free(session);
}
/* Sends a file indicated by the `filepath' to the remote client
SilcClientFileError
silc_client_file_send(SilcClient client,
SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
SilcClientFileMonitor monitor,
void *monitor_context,
+ const char *local_ip,
+ SilcUInt32 local_port,
+ bool do_not_bind,
+ SilcClientEntry client_entry,
const char *filepath,
SilcUInt32 *session_id)
{
SilcClientFtpSession session;
- SilcBuffer keyagr;
+ SilcBuffer keyagr, ftp;
char *filename, *path;
int fd;
- SILC_LOG_DEBUG(("File send request (file: %s)", filepath));
+ assert(client && conn && client_entry);
- if (!client || !client_entry || !filepath || !params ||
- !public_key || !private_key)
- return SILC_CLIENT_FILE_ERROR;
+ SILC_LOG_DEBUG(("Start"));
/* Check for existing session for `filepath'. */
- silc_dlist_start(client->internal->ftp_sessions);
- while ((session = silc_dlist_get(client->internal->ftp_sessions))) {
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
if (session->filepath && !strcmp(session->filepath, filepath) &&
session->client_entry == client_entry)
return SILC_CLIENT_FILE_ALREADY_STARTED;
}
- /* See whether the file exists and can be opened */
+ /* See whether the file exists, and can be opened in generally speaking */
fd = silc_file_open(filepath, O_RDONLY);
if (fd < 0)
return SILC_CLIENT_FILE_NO_SUCH_FILE;
/* Add new session */
session = silc_calloc(1, sizeof(*session));
- if (!session)
- return SILC_CLIENT_FILE_ERROR;
- session->session_id = ++client->internal->next_session_id;
+ session->session_id = ++conn->internal->next_session_id;
session->client = client;
- session->server_conn = conn;
- session->initiator = TRUE;
- session->client_entry = silc_client_ref_client(client, conn, client_entry);
+ session->conn = conn;
+ session->server = TRUE;
+ session->client_entry = client_entry;
session->monitor = monitor;
session->monitor_context = monitor_context;
session->filepath = strdup(filepath);
- session->params = *params;
- session->public_key = public_key;
- session->private_key = private_key;
+ silc_dlist_add(conn->internal->ftp_sessions, session);
- if (silc_asprintf(&path, "file://%s", filepath) < 0) {
- silc_free(session);
- return SILC_CLIENT_FILE_NO_MEMORY;
- }
+ path = silc_calloc(strlen(filepath) + 9, sizeof(*path));
+ silc_strncat(path, strlen(filepath) + 9, "file://", 7);
+ silc_strncat(path, strlen(filepath) + 9, filepath, strlen(filepath));
/* Allocate memory filesystem and put the file to it */
if (strrchr(path, '/'))
session->filesize = silc_file_size(filepath);
- /* If local IP is provided, create listener for incoming key exchange */
- if (params->local_ip || params->bind_ip) {
- session->listener =
- silc_client_listener_add(client,
- conn->internal->schedule,
- params, public_key, private_key,
- silc_client_ftp_connect_completion,
- session);
- if (!session->listener) {
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot create listener for file transfer: "
- "%s", strerror(errno));
- silc_free(session);
- return SILC_CLIENT_FILE_NO_MEMORY;
+ /* Create the listener for incoming key exchange protocol. */
+ if (!do_not_bind) {
+ session->listener = -1;
+ if (local_ip)
+ session->hostname = strdup(local_ip);
+ else
+ silc_net_check_local_by_sock(conn->sock->sock, NULL,
+ &session->hostname);
+ if (session->hostname)
+ session->listener = silc_net_create_server(local_port,
+ session->hostname);
+ if (session->listener < 0) {
+ /* Could not create listener. Do the second best thing; send empty
+ key agreement packet and let the remote client provide the point
+ for the key exchange. */
+ SILC_LOG_DEBUG(("Could not create listener"));
+ silc_free(session->hostname);
+ session->listener = 0;
+ session->hostname = NULL;
+ session->port = 0;
+ } else {
+ /* Listener ready */
+ SILC_LOG_DEBUG(("Bound listener"));
+ session->port = silc_net_get_local_port(session->listener);
+ silc_schedule_task_add(client->schedule, session->listener,
+ silc_client_ftp_process_key_agreement, session,
+ 0, 0, SILC_TASK_FD, SILC_TASK_PRI_NORMAL);
+ session->bound = TRUE;
}
-
- session->hostname = (params->bind_ip ? strdup(params->bind_ip) :
- strdup(params->local_ip));
- session->port = silc_client_listener_get_local_port(session->listener);
}
SILC_LOG_DEBUG(("Sending key agreement for file transfer"));
/* Send the key agreement inside FTP packet */
- keyagr = silc_key_agreement_payload_encode(session->hostname, 0,
- session->port);
- if (!keyagr) {
- if (session->listener)
- silc_client_listener_free(session->listener);
- silc_free(session);
- return SILC_CLIENT_FILE_NO_MEMORY;
- }
- silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL,
- SILC_ID_CLIENT, &client_entry->id, NULL, NULL,
- SILC_STR_UI_CHAR(1),
- SILC_STR_DATA(silc_buffer_data(keyagr),
- silc_buffer_len(keyagr)),
- SILC_STR_END);
+ keyagr = silc_key_agreement_payload_encode(session->hostname, session->port);
+
+ ftp = silc_buffer_alloc(1 + keyagr->len);
+ silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp));
+ silc_buffer_format(ftp,
+ SILC_STR_UI_CHAR(1),
+ SILC_STR_UI_XNSTRING(keyagr->data, keyagr->len),
+ SILC_STR_END);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_FTP,
+ client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+ ftp->data, ftp->len, FALSE);
silc_buffer_free(keyagr);
+ silc_buffer_free(ftp);
silc_free(path);
- silc_dlist_add(client->internal->ftp_sessions, session);
if (session_id)
*session_id = session->session_id;
- /* Add session request timeout */
- if (params && params->timeout_secs)
- silc_schedule_task_add_timeout(client->schedule,
- silc_client_ftp_timeout, session,
- params->timeout_secs, 0);
-
return SILC_CLIENT_FILE_OK;
}
SilcClientFileError
silc_client_file_receive(SilcClient client,
SilcClientConnection conn,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
SilcClientFileMonitor monitor,
void *monitor_context,
const char *path,
void *ask_name_context)
{
SilcClientFtpSession session;
- SilcBuffer keyagr;
+ SilcBuffer keyagr, ftp;
- if (!client || !conn)
- return SILC_CLIENT_FILE_ERROR;
+ assert(client && conn);
SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
/* Get the session */
- silc_dlist_start(client->internal->ftp_sessions);
- while ((session = silc_dlist_get(client->internal->ftp_sessions))
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
!= SILC_LIST_END) {
if (session->session_id == session_id) {
break;
session->monitor_context = monitor_context;
session->ask_name = ask_name;
session->ask_name_context = ask_name_context;
+ session->conn = conn;
session->path = path ? strdup(path) : NULL;
/* If the hostname and port already exists then the remote client did
create the connection ourselves. */
if (session->hostname && session->port) {
SILC_LOG_DEBUG(("Connecting to remote client"));
- /* Connect to the remote client. Performs key exchange automatically. */
- session->op =
- silc_client_connect_to_client(client, params, public_key, private_key,
- session->hostname, session->port,
- silc_client_ftp_connect_completion,
- session);
- if (!session->op) {
- silc_free(session);
+ if (silc_client_connect_to_client(client, conn, session->port,
+ session->hostname, session) < 0)
return SILC_CLIENT_FILE_ERROR;
- }
} else {
/* Add the listener for the key agreement */
SILC_LOG_DEBUG(("Creating listener for file transfer"));
- if (!params || (!params->local_ip && !params->bind_ip)) {
- silc_free(session);
- return SILC_CLIENT_FILE_ERROR;
- }
- session->listener =
- silc_client_listener_add(client, conn->internal->schedule, params,
- public_key, private_key,
- silc_client_ftp_connect_completion,
- session);
- if (!session->listener) {
+ session->listener = -1;
+ silc_net_check_local_by_sock(conn->sock->sock, NULL, &session->hostname);
+ if (session->hostname)
+ session->listener = silc_net_create_server(0, session->hostname);
+ if (session->listener < 0) {
+ SILC_LOG_DEBUG(("Could not create listener"));
+ session->listener = 0;
client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot create listener for file transfer: "
- "%s", strerror(errno));
- silc_free(session);
- return SILC_CLIENT_FILE_NO_MEMORY;
+ "Cannot create listener on %s: %s",
+ session->hostname, strerror(errno));
+ return SILC_CLIENT_FILE_ERROR;
}
- session->hostname = (params->bind_ip ? strdup(params->bind_ip) :
- strdup(params->local_ip));
- session->port = silc_client_listener_get_local_port(session->listener);
+ session->port = silc_net_get_local_port(session->listener);
+ silc_schedule_task_add(client->schedule, session->listener,
+ silc_client_ftp_process_key_agreement, session,
+ 0, 0, SILC_TASK_FD, SILC_TASK_PRI_NORMAL);
/* Send the key agreement inside FTP packet */
SILC_LOG_DEBUG(("Sending key agreement for file transfer"));
- keyagr = silc_key_agreement_payload_encode(session->hostname, 0,
+ keyagr = silc_key_agreement_payload_encode(session->hostname,
session->port);
- if (!keyagr) {
- silc_client_listener_free(session->listener);
- silc_free(session);
- return SILC_CLIENT_FILE_NO_MEMORY;
- }
- silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL,
- SILC_ID_CLIENT, &session->client_entry->id,
- NULL, NULL,
- SILC_STR_UI_CHAR(1),
- SILC_STR_DATA(silc_buffer_data(keyagr),
- silc_buffer_len(keyagr)),
- SILC_STR_END);
- silc_buffer_free(keyagr);
+ ftp = silc_buffer_alloc(1 + keyagr->len);
+ silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp));
+ silc_buffer_format(ftp,
+ SILC_STR_UI_CHAR(1),
+ SILC_STR_UI_XNSTRING(keyagr->data, keyagr->len),
+ SILC_STR_END);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_FTP,
+ session->client_entry->id,
+ SILC_ID_CLIENT, NULL, NULL,
+ ftp->data, ftp->len, FALSE);
- /* Add session request timeout */
- if (params && params->timeout_secs)
- silc_schedule_task_add_timeout(client->schedule,
- silc_client_ftp_timeout, session,
- params->timeout_secs, 0);
+ silc_buffer_free(keyagr);
+ silc_buffer_free(ftp);
}
return SILC_CLIENT_FILE_OK;
}
+SILC_TASK_CALLBACK(silc_client_file_close_final)
+{
+ silc_client_ftp_session_free(context);
+}
+
/* Closes file transmission session indicated by the `session_id'.
If file transmission is being conducted it will be aborted
automatically. This function is also used to close the session
{
SilcClientFtpSession session;
- if (!client || !conn)
- return SILC_CLIENT_FILE_ERROR;
+ assert(client && conn);
- SILC_LOG_DEBUG(("Closing file transer session %d", session_id));
+ SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
/* Get the session */
- silc_dlist_start(client->internal->ftp_sessions);
- while ((session = silc_dlist_get(client->internal->ftp_sessions))
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
!= SILC_LIST_END) {
if (session->session_id == session_id)
break;
return SILC_CLIENT_FILE_UNKNOWN_SESSION;
}
- if (session->monitor) {
+ if (session->monitor)
(*session->monitor)(session->client, session->conn,
SILC_CLIENT_FILE_MONITOR_CLOSED,
SILC_CLIENT_FILE_OK, 0, 0,
session->client_entry, session->session_id,
session->filepath, session->monitor_context);
- /* No more callbacks to application */
- session->monitor = NULL;
- }
-
- silc_schedule_task_del_by_context(client->schedule, session);
-
- session->closed = TRUE;
-
/* Destroy via timeout */
- silc_schedule_task_add_timeout(conn->internal->schedule,
- silc_client_file_close_final, session,
- 0, 1);
+ silc_schedule_task_add(session->client->schedule, 0,
+ silc_client_file_close_final, session,
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
return SILC_CLIENT_FILE_OK;
}
-/************************** FTP Request Processing **************************/
-
-/* Received file transfer packet. Only file transfer requests get here.
- The actual file transfer is handled by the SFTP library when we give it
- the packet stream wrapped into SilcStream context. */
+/* Callback called after remote client information has been resolved.
+ This will try to find existing session for the client entry. If found
+ then continue with the key agreement protocol. If not then it means
+ this is a file transfer request and we let the application know. */
-SILC_FSM_STATE(silc_client_ftp)
+static void silc_client_ftp_resolve_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
+ void *context)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
+ SilcPacketContext *packet = (SilcPacketContext *)context;
SilcClientFtpSession session;
- SilcClientID remote_id;
- SilcClientEntry remote_client;
SilcKeyAgreementPayload payload = NULL;
+ SilcClientEntry client_entry;
char *hostname;
SilcUInt16 port;
- SILC_LOG_DEBUG(("Process file transfer packet"));
+ SILC_LOG_DEBUG(("Start"));
- if (silc_buffer_len(&packet->buffer) < 1)
+ if (!clients)
goto out;
- /* We support file transfer type number 1 (== SFTP) */
- if (packet->buffer.data[0] != 0x01) {
- SILC_LOG_DEBUG(("Unsupported file transfer type %d",
- packet->buffer.data[0]));
- goto out;
- }
+ client_entry = clients[0];
- if (!silc_id_str2id(packet->src_id, packet->src_id_len,
- SILC_ID_CLIENT, &remote_id, sizeof(remote_id))) {
- SILC_LOG_DEBUG(("Invalid client ID"));
- goto out;
- }
-
- /* Check whether we know this client already */
- remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
- if (!remote_client || !remote_client->internal.valid) {
- /** Resolve client info */
- silc_client_unref_client(client, conn, remote_client);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &remote_id, NULL,
- silc_client_ftp_client_resolved,
- fsm));
- /* NOT REACHED */
- }
-
- /* Get session */
- silc_dlist_start(client->internal->ftp_sessions);
- while ((session = silc_dlist_get(client->internal->ftp_sessions))) {
- if (session->client_entry == remote_client &&
- (!session->initiator || !session->listener))
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
+ if (session->client_entry == client_entry &&
+ (!session->server || !session->bound))
break;
}
/* Parse the key agreement payload */
- payload =
- silc_key_agreement_payload_parse(silc_buffer_data(&packet->buffer) + 1,
- silc_buffer_len(&packet->buffer) - 1);
- if (!payload) {
- SILC_LOG_DEBUG(("Invalid key agreement payload"));
+ payload = silc_key_agreement_payload_parse(packet->buffer->data,
+ packet->buffer->len);
+ if (!payload)
goto out;
- }
hostname = silc_key_agreement_get_hostname(payload);
port = silc_key_agreement_get_port(payload);
- if (!hostname || !port) {
- hostname = NULL;
+ if (!hostname)
port = 0;
- }
-
- /* If session doesn't exist, we create new one. If session exists, but
- we are responder it means that the remote sent another request and user
- hasn't even accepted the first one yet. We assume this session is new
- session as well. */
- if (!session || !hostname || !session->initiator) {
- /* New file transfer session */
- SILC_LOG_DEBUG(("New file transfer session %d",
- client->internal->next_session_id + 1));
+ if (!port)
+ hostname = NULL;
+ /* If session doesn't exist, we create one and let applicationi know about
+ incoming file transfer request. If session exists, but we are responder
+ it means that the remote sent another request and user hasn't even
+ accepted the first one yet. We assume this session is new session
+ as well. */
+ if (session == SILC_LIST_END || (!hostname && !port) ||
+ (session && session->server == FALSE)) {
+ /* No session found, create one and let the application know about
+ incoming file transfer request. */
+ SILC_LOG_DEBUG(("New file transfer session ID: %d",
+ conn->internal->next_session_id + 1));
+
+ /* Add new session */
session = silc_calloc(1, sizeof(*session));
- if (!session)
- goto out;
- session->session_id = ++client->internal->next_session_id;
+ session->session_id = ++conn->internal->next_session_id;
session->client = client;
- session->server_conn = conn;
- session->client_entry = silc_client_ref_client(client, conn,
- remote_client);
+ session->conn = conn;
+ session->client_entry = client_entry;
+ silc_dlist_add(conn->internal->ftp_sessions, session);
+
if (hostname && port) {
session->hostname = strdup(hostname);
session->port = port;
}
- silc_dlist_add(client->internal->ftp_sessions, session);
- /* Notify application of incoming FTP request */
- client->internal->ops->ftp(client, conn, remote_client,
+ /* Let the application know */
+ client->internal->ops->ftp(client, conn, client_entry,
session->session_id, hostname, port);
+
goto out;
}
/* Session exists, continue with key agreement protocol. */
- SILC_LOG_DEBUG(("Session %d exists, connecting to remote client",
+ SILC_LOG_DEBUG(("Session ID %d exists, connecting to remote client",
session->session_id));
session->hostname = strdup(hostname);
session->port = port;
- /* Connect to the remote client. Performs key exchange automatically. */
- session->op =
- silc_client_connect_to_client(client, &session->params,
- session->public_key, session->private_key,
- session->hostname, session->port,
- silc_client_ftp_connect_completion,
- session);
- if (!session->op) {
+ if (silc_client_connect_to_client(client, conn, port,
+ hostname, session) < 0) {
/* Call monitor callback */
if (session->monitor)
(*session->monitor)(session->client, session->conn,
out:
if (payload)
silc_key_agreement_payload_free(payload);
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
+ silc_packet_context_free(packet);
+}
+
+/* Called when file transfer packet is received. This will parse the
+ packet and give it to the file transfer protocol. */
+
+void silc_client_ftp(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcUInt8 type;
+ int ret;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Parse the payload */
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI_CHAR(&type),
+ SILC_STR_END);
+ if (ret == -1)
+ return;
+
+ /* We support only type number 1 (== SFTP) */
+ if (type != 1)
+ return;
+
+ silc_buffer_pull(packet->buffer, 1);
+
+ /* If we have active FTP session then give the packet directly to the
+ protocol processor. */
+ if (conn->internal->active_session) {
+ /* Give it to the SFTP */
+ if (conn->internal->active_session->server)
+ silc_sftp_server_receive_process(conn->internal->active_session->sftp,
+ sock, packet);
+ else
+ silc_sftp_client_receive_process(conn->internal->active_session->sftp,
+ sock, packet);
+ } else {
+ /* We don't have active session, resolve the remote client information
+ and then try to find the correct session. */
+ SilcClientID *remote_id;
+
+ if (packet->src_id_type != SILC_ID_CLIENT)
+ return;
+
+ remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!remote_id)
+ return;
+
+ /* Resolve the client */
+ silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+ NULL, silc_client_ftp_resolve_cb,
+ silc_packet_context_dup(packet));
+ silc_free(remote_id);
+ }
}
+++ /dev/null
-/*
-
- client_ftp.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2007 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 CLIENT_FTP_H
-#define CLIENT_FTP_H
-
-SILC_FSM_STATE(silc_client_ftp);
-void silc_client_ftp_free_sessions(SilcClient client);
-void silc_client_ftp_session_free_client(SilcClient client,
- SilcClientEntry client_entry);
-
-#endif /* CLIENT_FTP_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2004 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 CLIENT_INTERNAL_H
#define CLIENT_INTERNAL_H
-#include "command.h"
-#include "command_reply.h"
-#include "client_connect.h"
-#include "client_register.h"
-#include "client_entry.h"
-#include "client_prvmsg.h"
-#include "client_channel.h"
-#include "client_notify.h"
-#include "client_keyagr.h"
-#include "client_ftp.h"
-#include "client_listener.h"
-
-/****************************** Definitions *********************************/
-
-/* Packet retry counter and timer defines, for exponential backoff algorithm.
- Meaningful with UDP transport when packets may get lost. */
-#define SILC_CLIENT_RETRY_COUNT 4 /* Max packet retry count */
-#define SILC_CLIENT_RETRY_MUL 2 /* Retry timer interval growth */
-#define SILC_CLIENT_RETRY_RAND 2 /* Randomizer, timeout += rnd % 2 */
-#define SILC_CLIENT_RETRY_MIN 1 /* Min retry timeout, seconds */
-#define SLIC_CLIENT_RETRY_MAX 16 /* Max retry timeout, seconds */
-
-/********************************** Types ***********************************/
-
-/* Public key verification context */
+/* Context to hold the connection authentication request callbacks that
+ will be called when the server has replied back to our request about
+ current authentication method in the session. */
typedef struct {
- SilcSKE ske;
- SilcSKEVerifyCbCompletion completion;
- void *completion_context;
-} *SilcVerifyKeyContext;
-
-/* Command and command reply context used to hold registered commands
- in the SILC client. */
-typedef struct SilcClientCommandStruct {
- struct SilcClientCommandStruct *next;
- SilcCommand cmd; /* Command type */
- SilcFSMStateCallback command; /* Command function */
- SilcFSMStateCallback reply; /* Command reply callback */
- char *name; /* Name of the command (optional) */
- SilcUInt8 max_args; /* Maximum arguments (optional) */
-} *SilcClientCommand;
-
-/* Command reply callback structure */
-typedef struct SilcClientCommandReplyCallbackStruct {
- struct SilcClientCommandReplyCallbackStruct *next;
- SilcClientCommandReply reply; /* Command reply callback */
- void *context; /* Command reply context */
- unsigned int do_not_call : 1; /* Set to not call the callback */
-} *SilcClientCommandReplyCallback;
-
-/* Command context given as argument to command state functions. This same
- context is used when calling, sending and procesing command and command
- reply. */
-typedef struct SilcClientCommandContextStruct {
- struct SilcClientCommandContextStruct *next;
- SilcClientConnection conn; /* Connection */
- SilcFSMThreadStruct thread; /* FSM thread for command call */
-
- SilcCommand cmd; /* Command */
- SilcUInt16 cmd_ident; /* Command identifier */
- SilcUInt32 argc; /* Number of arguments */
- unsigned char **argv; /* Arguments, may be NULL */
- SilcUInt32 *argv_lens; /* Argument lengths, may be NULL */
- SilcUInt32 *argv_types; /* Argument types, may be NULL */
-
- SilcList reply_callbacks; /* Command reply callbacks */
- SilcStatus status; /* Current command reply status */
- SilcStatus error; /* Current command reply error */
-
- void *context; /* Context for free use */
- unsigned int called : 1; /* Set when called by application */
- unsigned int verbose : 1; /* Verbose with 'say' client operation */
- unsigned int resolved : 1; /* Set when resolving something */
-} *SilcClientCommandContext;
+ SilcConnectionAuthRequest callback;
+ void *context;
+ SilcTask timeout;
+} *SilcClientConnAuthRequest;
+
+/* Generic rekey context for connections */
+typedef struct {
+ /* Current sending encryption key, provided for re-key. The `pfs'
+ is TRUE if the Perfect Forward Secrecy is performed in re-key. */
+ unsigned char *send_enc_key;
+ SilcUInt32 enc_key_len;
+ int ske_group;
+ bool pfs;
+ SilcUInt32 timeout;
+ void *context;
+} *SilcClientRekey;
+
+/* Internal context for connection process. This is needed as we
+ doing asynchronous connecting. */
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcTask task;
+ int sock;
+ char *host;
+ int port;
+ int tries;
+ void *context;
+} SilcClientInternalConnectContext;
+
+/* Structure to hold ping time information. Every PING command will
+ add entry of this structure and is removed after reply to the ping
+ as been received. */
+struct SilcClientPingStruct {
+ time_t start_time;
+ void *dest_id;
+ char *dest_name;
+};
+
+/* Structure to hold away messages set by user. This is mainly created
+ for future extensions where away messages could be set according filters
+ such as nickname and hostname. For now only one away message can
+ be set in one connection. */
+struct SilcClientAwayStruct {
+ char *away;
+ struct SilcClientAwayStruct *next;
+};
/* Internal context for the client->internal pointer in the SilcClient. */
struct SilcClientInternalStruct {
- SilcFSMStruct fsm; /* Client's FSM */
- SilcFSMEventStruct wait_event; /* Event signaller */
- SilcClientOperations *ops; /* Client operations */
- SilcClientParams *params; /* Client parameters */
- SilcPacketEngine packet_engine; /* Packet engine */
- SilcMutex lock; /* Client lock */
- SilcList commands; /* Registered commands */
- SilcDList ftp_sessions; /* FTP sessions */
- char *silc_client_version; /* Version set by application */
- SilcClientRunning running; /* Running/Stopped callback */
- void *running_context; /* Context for runnign callback */
- SilcAtomic16 conns; /* Number of connections in client */
- SilcUInt16 next_session_id; /* Next FTP session ID */
-
- /* Events */
- unsigned int stop : 1; /* Stop client */
- unsigned int run_callback : 1; /* Call running/stopped callback */
- unsigned int connection_closed : 1; /* A connection closed */
+ /* All client operations that are implemented by the application. */
+ SilcClientOperations *ops;
+
+ /* Client Parameters */
+ SilcClientParams *params;
+
+ /* Table of connections in client. All the connection data is saved here. */
+ SilcClientConnection *conns;
+ SilcUInt32 conns_count;
+
+ /* Table of listenning sockets in client. Client can have listeners
+ (like key agreement protocol server) and those sockets are saved here.
+ This table is checked always if the connection object cannot be found
+ from the `conns' table. */
+ SilcSocketConnection *sockets;
+ SilcUInt32 sockets_count;
+
+ /* Registered commands */
+ SilcList commands;
+
+ /* Generic cipher and hash objects. */
+ SilcCipher none_cipher;
+ SilcHmac md5hmac;
+ SilcHmac sha1hmac;
+
+ /* Client version. Used to compare to remote host's version strings. */
+ char *silc_client_version;
};
/* Internal context for conn->internal in SilcClientConnection. */
struct SilcClientConnectionInternalStruct {
- SilcClientConnectionParams params; /* Connection parameters */
- SilcFSMStruct fsm; /* Connection FSM */
- SilcFSMThreadStruct event_thread; /* FSM thread for events */
- SilcFSMEventStruct wait_event; /* Event signaller */
- SilcSchedule schedule; /* Connection's scheduler */
- SilcMutex lock; /* Connection lock */
- SilcSKE ske; /* Key exchange protocol */
- SilcSKERekeyMaterial rekey; /* Rekey material */
- SilcList thread_pool; /* Packet thread pool */
- SilcList pending_commands; /* Pending commands list */
- SilcHash hash; /* Negotiated hash function */
- SilcHash sha1hash; /* SHA-1 default hash context */
- SilcBuffer local_idp; /* Local ID Payload */
- SilcBuffer remote_idp; /* Remote ID Payload */
- SilcAsyncOperation op; /* Protocols async operation */
- SilcAsyncOperation cop; /* Async operation for application */
- SilcHashTable attrs; /* Configured user attributes */
- SilcStream user_stream; /* Low level stream in connecting */
- char *disconnect_message; /* Disconnection message */
- char *away_message; /* Away message */
- void *prv_waiter; /* Private message packet waiter */
-
- SilcIDCache client_cache; /* Client entry cache */
- SilcIDCache channel_cache; /* Channel entry cache */
- SilcIDCache server_cache; /* Server entry cache */
-
- SilcUInt32 remote_version; /* Remote SILC protocol version */
- SilcAtomic16 cmd_ident; /* Current command identifier */
- SilcUInt8 retry_count; /* Packet retry counter */
- SilcUInt8 retry_timer; /* Packet retry timer */
- SilcClientConnectionStatus status; /* Connection callback status */
- SilcStatus error; /* Connection callback error */
-
- /* Events */
- unsigned int connect : 1; /* Connect remote host */
- unsigned int disconnected : 1; /* Disconnect remote connection */
- unsigned int key_exchange : 1; /* Start key exchange */
- unsigned int rekeying : 1; /* Start rekey */
-
- /* Flags */
- unsigned int verbose : 1; /* Notify application */
- unsigned int registering : 1; /* Set when registering to network */
- unsigned int rekey_responder : 1; /* Set when rekeying as responder */
- unsigned int auth_request : 1; /* Set when requesting auth method */
+ /* Keys and stuff negotiated in the SKE protocol */
+ SilcCipher send_key;
+ SilcCipher receive_key;
+ SilcHmac hmac_send;
+ SilcHmac hmac_receive;
+ SilcHash hash;
+ SilcUInt32 psn_send;
+ SilcUInt32 psn_receive;
+
+ /* Client ID and Channel ID cache. Messages transmitted in SILC network
+ are done using different unique ID's. These are the cache for
+ thoses ID's used in the communication. */
+ SilcIDCache client_cache;
+ SilcIDCache channel_cache;
+ SilcIDCache server_cache;
+
+ /* Pending command queue for this connection */
+ SilcDList pending_commands;
+
+ /* Requested pings. */
+ SilcClientPing *ping;
+ SilcUInt32 ping_count;
+
+ /* Set away message */
+ SilcClientAway *away;
+
+ /* Re-key context */
+ SilcClientRekey rekey;
+
+ /* Authentication request context. */
+ SilcClientConnAuthRequest connauth;
+
+ /* File transmission sessions */
+ SilcDList ftp_sessions;
+ SilcUInt32 next_session_id;
+ SilcClientFtpSession active_session;
+
+ /* Requested Attributes */
+ SilcHashTable attrs;
+
+ /* Connection parameters */
+ SilcClientConnectionParams params;
};
-SILC_FSM_STATE(silc_client_connection_st_run);
-SILC_FSM_STATE(silc_client_connection_st_packet);
-SILC_FSM_STATE(silc_client_connection_st_close);
-SILC_FSM_STATE(silc_client_error);
-SILC_FSM_STATE(silc_client_disconnect);
-SILC_FSM_STATE(silc_client_st_stop);
-
-void silc_client_del_connection(SilcClient client, SilcClientConnection conn);
-void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context);
-void silc_client_command_free(SilcClientCommandContext cmd);
-SilcClientConnection
-silc_client_add_connection(SilcClient client,
- SilcConnectionType conn_type,
- SilcBool connect,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *remote_host, int port,
- SilcClientConnectCallback callback,
- void *context);
+/* Session resuming callback */
+typedef void (*SilcClientResumeSessionCallback)(SilcClient client,
+ SilcClientConnection conn,
+ bool success,
+ void *context);
+
+/* Rekey must be performed at the lastest when this many packets is sent */
+#define SILC_CLIENT_REKEY_THRESHOLD 0xfffffe00
+
+/* Macros */
+
+/* Registers generic task for file descriptor for reading from network and
+ writing to network. As being generic task the actual task is allocated
+ only once and after that the same task applies to all registered fd's. */
+#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd) \
+do { \
+ silc_schedule_task_add(client->schedule, (fd), \
+ silc_client_packet_process, \
+ context, 0, 0, \
+ SILC_TASK_GENERIC, \
+ SILC_TASK_PRI_NORMAL); \
+} while(0)
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(s, fd) \
+do { \
+ silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ, FALSE); \
+} while(0)
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(s, fd) \
+do { \
+ silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | \
+ SILC_TASK_WRITE), FALSE); \
+} while(0)
+
+/* Finds socket connection object by file descriptor */
+#define SILC_CLIENT_GET_SOCK(__x, __fd, __sock) \
+do { \
+ int __i; \
+ \
+ for (__i = 0; __i < (__x)->internal->conns_count; __i++) \
+ if ((__x)->internal->conns[__i] && \
+ (__x)->internal->conns[__i]->sock && \
+ (__x)->internal->conns[__i]->sock->sock == (__fd)) \
+ break; \
+ \
+ if (__i >= (__x)->internal->conns_count) { \
+ (__sock) = NULL; \
+ for (__i = 0; __i < (__x)->internal->sockets_count; __i++) \
+ if ((__x)->internal->sockets[__i] && \
+ (__x)->internal->sockets[__i]->sock == (__fd)) \
+ (__sock) = (__x)->internal->sockets[__i]; \
+ } else \
+ (__sock) = (__x)->internal->conns[__i]->sock; \
+} while(0)
+
+/* Check whether rekey protocol is active */
+#define SILC_CLIENT_IS_REKEY(sock) \
+ (sock->protocol && sock->protocol->protocol && \
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
+
+/* Prototypes */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process);
+void silc_client_packet_send(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send);
+int silc_client_packet_send_real(SilcClient client,
+ SilcSocketConnection sock,
+ bool force_send);
+void silc_client_ftp_free_sessions(SilcClient client,
+ SilcClientConnection conn);
+void silc_client_ftp_session_free(SilcClientFtpSession session);
+void silc_client_ftp_session_free_client(SilcClientConnection conn,
+ SilcClientEntry client_entry);
+void silc_client_close_connection_real(SilcClient client,
+ SilcSocketConnection sock,
+ SilcClientConnection conn);
+void silc_client_disconnected_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet);
+void silc_client_error_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer message);
+void silc_client_receive_new_id(SilcClient client,
+ SilcSocketConnection sock,
+ SilcIDPayload idp);
+void silc_client_save_channel_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcBuffer key_payload,
+ SilcChannelEntry channel);
+void silc_client_receive_channel_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcBuffer packet);
+void silc_client_channel_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_remove_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry);
+void silc_client_replace_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry old,
+ SilcClientEntry newclient);
+void silc_client_process_failure(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_key_agreement(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_notify_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_private_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_private_message_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_connection_auth_request(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_ftp(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+SilcBuffer silc_client_get_detach_data(SilcClient client,
+ SilcClientConnection conn);
+bool silc_client_process_detach_data(SilcClient client,
+ SilcClientConnection conn,
+ unsigned char **old_id,
+ SilcUInt16 *old_id_len);
+void silc_client_resume_session(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientResumeSessionCallback callback,
+ void *context);
SilcBuffer silc_client_attributes_process(SilcClient client,
- SilcClientConnection conn,
- SilcDList attrs);
+ SilcSocketConnection sock,
+ SilcDList attrs);
+void silc_client_packet_queue_purge(SilcClient client,
+ SilcSocketConnection sock);
+SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback);
+void
+silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
+ SilcStatus status,
+ bool notify);
-#endif /* CLIENT_INTERNAL_H */
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 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
GNU General Public License for more details.
*/
-
-#include "silc.h"
+/* $Id$ */
+/* This file includes the Key Agreement packet processing and actual
+ key agreement routines. This file has nothing to do with the actual
+ connection key exchange protocol, it is implemented in the client.c
+ and in protocol.c. This file implements the client-to-client key
+ agreement as defined by the SILC protocol. */
+
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
+SILC_TASK_CALLBACK(silc_client_key_agreement_final);
+SILC_TASK_CALLBACK(silc_client_process_key_agreement);
+SILC_TASK_CALLBACK(silc_client_key_agreement_timeout);
+SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start);
-/* Key agreement context, used by responder */
+/* Key agreement context */
struct SilcClientKeyAgreementStruct {
- SilcClient client; /* Client */
- SilcClientConnection conn; /* Server connection */
- SilcClientListener listener; /* Listener */
+ SilcClient client;
+ SilcClientConnection conn;
+ int fd; /* Listening/connection socket */
+ SilcSocketConnection sock; /* Remote socket connection */
+ SilcClientEntry client_entry; /* Destination client */
SilcKeyAgreementCallback completion; /* Key agreement completion */
void *context; /* User context */
- SilcAsyncOperation op; /* Async operation, initiator */
+ SilcTask timeout; /* Timeout task */
+ SilcClientKEInternalContext *proto_ctx; /* Key Exchange protocol context */
};
-/************************ Static utility functions **************************/
-
-/* Destroyes key agreement session */
+/* Packet sending function used by the SKE in the key agreement process. */
-static void silc_client_keyagr_free(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry)
+static void silc_client_key_agreement_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
{
- SilcClientKeyAgreement ke = client_entry->internal.ke;
-
- silc_client_listener_free(ke->listener);
- silc_schedule_task_del_by_context(conn->internal->schedule, client_entry);
- if (ke->op)
- silc_async_abort(ke->op, NULL, NULL);
- client_entry->internal.ke = NULL;
- client_entry->internal.prv_resp = FALSE;
- silc_client_unref_client(client, conn, client_entry);
- silc_free(ke);
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ void *tmp;
+
+ /* Send the packet immediately. We will assure that the packet is not
+ encrypted by setting the socket's user_data pointer to NULL. The
+ silc_client_packet_send would take the keys (wrong keys that is,
+ because user_data is the current SilcClientConnection) from it and
+ we cannot allow that. The packets are never encrypted when doing SKE
+ with another client. */
+ tmp = ske->sock->user_data;
+ ske->sock->user_data = NULL;
+ silc_client_packet_send(ctx->client, ske->sock, type, NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ ske->sock->user_data = tmp;
}
-/* Key agreement timeout callback */
+/* Timeout callback that is called to close the connection and free the
+ socket connection data. */
-SILC_TASK_CALLBACK(silc_client_keyagr_timeout)
+SILC_TASK_CALLBACK(silc_client_key_agreement_close)
{
- SilcClientEntry client_entry = context;
- SilcClientKeyAgreement ke = client_entry->internal.ke;
+ SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
+
+ silc_schedule_unset_listen_fd(ke->client->schedule, ke->sock->sock);
+ silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
+ silc_net_close_connection(ke->sock->sock);
+ silc_net_close_connection(ke->fd);
+ silc_socket_free(ke->sock);
+ silc_free(ke);
+}
- SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
+/* This callback is called after the key agreement protocol has been
+ performed. This calls the final completion callback for the application. */
- ke->completion(ke->client, ke->conn, client_entry,
- SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
+SILC_TASK_CALLBACK(silc_client_key_agreement_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ ke->client_entry->ke = NULL;
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
+ silc_ske_free_key_material(ctx->keymat);
+ goto out;
+ }
- silc_client_keyagr_free(ke->client, ke->conn, client_entry);
+ /* Pass the negotiated key material to the application. The application
+ is responsible of freeing the key material. */
+ ke->client_entry->ke = NULL;
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_OK, ctx->keymat, ke->context);
+
+ out:
+ silc_protocol_free(protocol);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_schedule_task_del_by_fd(client->schedule, ke->fd);
+ silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
+ silc_net_close_connection(ke->fd);
+ if (ke->timeout)
+ silc_schedule_task_del(client->schedule, ke->timeout);
+ silc_client_del_socket(ke->client, ke->sock);
+
+ silc_schedule_task_add(client->schedule, 0,
+ silc_client_key_agreement_close,
+ (void *)ke, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ silc_free(ctx);
}
-/* Client resolving callback. Continues with the key agreement processing */
+/* Key agreement callback that is called when remote end has initiated
+ the key agreement protocol. This accepts the incoming TCP/IP connection
+ for the key agreement protocol. */
-static void silc_client_keyagr_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
+SILC_TASK_CALLBACK(silc_client_process_key_agreement)
{
- /* If no client found, ignore the packet, a silent error */
- if (!clients)
- silc_fsm_next(context, silc_client_key_agreement_error);
+ SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
+ SilcClient client = ke->client;
+ SilcClientConnection conn = ke->conn;
+ SilcSocketConnection newsocket;
+ SilcClientKEInternalContext *proto_ctx;
+ int sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ sock = silc_net_accept_connection(ke->fd);
+ if (sock < 0) {
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Could not accept key agreement connection: ",
+ strerror(errno));
+ ke->client_entry->ke = NULL;
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
+ silc_schedule_task_del_by_fd(client->schedule, ke->fd);
+ silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
+ silc_net_close_connection(ke->fd);
+ if (ke->timeout)
+ silc_schedule_task_del(client->schedule, ke->timeout);
+ silc_free(ke);
+ return;
+ }
- /* Continue processing the packet */
- SILC_FSM_CALL_CONTINUE(context);
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* Create socket for this connection (it is of type UNKNOWN since this
+ really is not a real SILC connection. It is only for the key
+ agreement protocol). */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &newsocket);
+ ke->sock = newsocket;
+
+ /* Perform name and address lookups for the remote host. */
+ silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
+ if (!newsocket->hostname && !newsocket->ip) {
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Could not resolve the remote IP or hostname");
+ ke->client_entry->ke = NULL;
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
+ silc_schedule_task_del_by_fd(client->schedule, ke->fd);
+ silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
+ silc_net_close_connection(ke->fd);
+ if (ke->timeout)
+ silc_schedule_task_del(client->schedule, ke->timeout);
+ silc_free(ke);
+ return;
+ }
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
+ newsocket->port = silc_net_get_remote_port(sock);
+ silc_client_add_socket(client, newsocket);
+
+ /* Allocate internal context for key exchange protocol. This is
+ sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = client;
+ proto_ctx->sock = silc_socket_dup(newsocket);
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = TRUE;
+ proto_ctx->context = context;
+ proto_ctx->send_packet = silc_client_key_agreement_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
+ ke->proto_ctx = proto_ctx;
+
+ /* Prepare the connection for key exchange protocol. We allocate the
+ protocol but will not start it yet. The connector will be the
+ initiator of the protocol thus we will wait for initiation from
+ there before we start the protocol. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &newsocket->protocol, proto_ctx,
+ silc_client_key_agreement_final);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it
+ will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)client;
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
}
-/* Key exchange completion callback. Called after connected to remote host
- and performed key exchange, when we are initiator. As responder, this is
- called after the remote has connected to us and have performed the key
- exchange. */
+/* Timeout occured during key agreement. This means that the key agreement
+ protocol was not completed in the specified timeout. We will call the
+ completion callback. */
-static void silc_client_keyagr_completion(SilcClient client,
- SilcClientConnection conn,
- SilcClientConnectionStatus status,
- SilcStatus error,
- const char *message,
- void *context)
+SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
{
- SilcClientEntry client_entry = context;
- SilcClientKeyAgreement ke = client_entry->internal.ke;
- SilcSKEKeyMaterial keymat;
-
- ke->op = NULL;
-
- switch (status) {
- case SILC_CLIENT_CONN_SUCCESS:
- SILC_LOG_DEBUG(("Key agreement %p successful", ke));
-
- keymat = silc_ske_get_key_material(conn->internal->ske);
- ke->completion(ke->client, ke->conn, client_entry, SILC_KEY_AGREEMENT_OK,
- keymat, ke->context);
- break;
-
- case SILC_CLIENT_CONN_ERROR_TIMEOUT:
- SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
- ke->completion(ke->client, ke->conn, client_entry,
- SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
- break;
-
- default:
- SILC_LOG_DEBUG(("Key agreement %p error %d", ke, status));
- ke->completion(ke->client, ke->conn, client_entry,
- SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
- break;
- }
+ SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
- /* Close the connection */
- if (conn)
- silc_client_close_connection(ke->client, conn);
+ ke->client_entry->ke = NULL;
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
- silc_client_keyagr_free(ke->client, ke->conn, client_entry);
+ if (ke->sock) {
+ silc_client_del_socket(ke->client, ke->sock);
+ silc_socket_free(ke->sock);
+ }
+ if (ke->proto_ctx && ke->proto_ctx->ske)
+ silc_ske_free(ke->proto_ctx->ske);
+ ke->client_entry->ke = NULL;
+ if (ke->fd)
+ silc_schedule_task_del_by_fd(ke->client->schedule, ke->fd);
+ silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
+ silc_net_close_connection(ke->fd);
+ silc_free(ke);
}
-/*************************** Key Agreement API ******************************/
-
-/* Sends key agreement packet to remote client. If IP addresses are provided
- creates also listener for íncoming key agreement connection. Supports
- both TCP and UDP transports. */
+/* Sends key agreement request to the remote client indicated by the
+ `client_entry'. If the caller provides the `hostname' and the `port'
+ arguments then the library will bind the client to that hostname and
+ that port for the key agreement protocol. It also sends the `hostname'
+ and the `port' in the key agreement packet to the remote client. This
+ would indicate that the remote client may initiate the key agreement
+ protocol to the `hostname' on the `port'. If port is zero then the
+ bound port is undefined (the operating system defines it).
+
+ If the `hostname' and `port' is not provided then empty key agreement
+ packet is sent to the remote client. The remote client may reply with
+ the same packet including its hostname and port. If the library receives
+ the reply from the remote client the `key_agreement' client operation
+ callback will be called to verify whether the user wants to perform the
+ key agreement or not.
+
+ NOTE: If the application provided the `hostname' and the `port' and the
+ remote side initiates the key agreement protocol it is not verified
+ from the user anymore whether the protocol should be executed or not.
+ By setting the `hostname' and `port' the user gives permission to
+ perform the protocol (we are responder in this case).
+
+ NOTE: If the remote side decides not to initiate the key agreement
+ or decides not to reply with the key agreement packet then we cannot
+ perform the key agreement at all. If the key agreement protocol is
+ performed the `completion' callback with the `context' will be called.
+ If remote side decides to ignore the request the `completion' will be
+ called after the specified timeout, `timeout_secs'.
+
+ NOTE: If the `hostname' and the `port' was not provided the `completion'
+ will not be called at all since this does nothing more than sending
+ a packet to the remote host.
+
+ NOTE: There can be only one active key agreement for one client entry.
+ Before setting new one, the old one must be finished (it is finished
+ after calling the completion callback) or the function
+ silc_client_abort_key_agreement must be called. */
void silc_client_send_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
+ const char *hostname,
+ const char *bindhost,
+ int port,
+ SilcUInt32 timeout_secs,
SilcKeyAgreementCallback completion,
void *context)
{
+ SilcSocketConnection sock = conn->sock;
SilcClientKeyAgreement ke = NULL;
SilcBuffer buffer;
- SilcUInt16 port = 0, protocol = 0;
- char *local_ip = NULL;
-
- SILC_LOG_DEBUG(("Sending key agreement"));
if (!client_entry)
return;
- if (conn->internal->disconnected)
- return;
- if (client_entry->internal.ke) {
+ if (client_entry->ke) {
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ALREADY_STARTED,
NULL, context);
return;
return;
}
- /* If local IP is provided, create listener. If this is not provided,
- we'll just send empty key agreement payload */
- if (params && (params->local_ip || params->bind_ip)) {
+ /* Create the listener if hostname and port was provided.
+ * also, use bindhost if it was specified.
+ */
+
+ if (hostname) {
ke = silc_calloc(1, sizeof(*ke));
- if (!ke) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
- NULL, context);
- return;
- }
- /* Create listener */
- ke->listener = silc_client_listener_add(client, conn->internal->schedule,
- params, public_key, private_key,
- silc_client_keyagr_completion,
- client_entry);
- if (!ke->listener) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
+ if (bindhost)
+ ke->fd = silc_net_create_server(port, bindhost);
+ else
+ ke->fd = silc_net_create_server(port, hostname);
+
+ if (ke->fd < 0) {
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot create listener on %s on port %d: %s",
+ (bindhost) ? bindhost:hostname, port, strerror(errno));
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
NULL, context);
+ silc_free(ke);
return;
}
- local_ip = params->local_ip;
- protocol = params->udp;
-
ke->client = client;
ke->conn = conn;
+ ke->client_entry = client_entry;
ke->completion = completion;
ke->context = context;
- silc_client_ref_client(client, conn, client_entry);
- client_entry->internal.ke = ke;
- client_entry->internal.prv_resp = TRUE;
+
+ /* Add listener task to the scheduler. This task receives the key
+ negotiations. */
+ silc_schedule_task_add(client->schedule, ke->fd,
+ silc_client_process_key_agreement,
+ (void *)ke, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+
+ /* Register a timeout task that will be executed if the connector
+ will not start the key exchange protocol within the specified
+ timeout. */
+ ke->timeout = silc_schedule_task_add(client->schedule, 0,
+ silc_client_key_agreement_timeout,
+ (void *)ke, timeout_secs, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
}
/* Encode the key agreement payload */
- buffer = silc_key_agreement_payload_encode(local_ip, protocol, port);
- if (!buffer) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
- NULL, context);
- silc_client_keyagr_free(client, conn, client_entry);
- return;
- }
+ buffer = silc_key_agreement_payload_encode(hostname,
+ !ke ? port :
+ silc_net_get_local_port(ke->fd));
/* Send the key agreement packet to the client */
- if (!silc_packet_send_ext(conn->stream, SILC_PACKET_KEY_AGREEMENT, 0,
- 0, NULL, SILC_ID_CLIENT, &client_entry->id,
- silc_buffer_datalen(buffer), NULL, NULL)) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
- NULL, context);
- silc_client_keyagr_free(client, conn, client_entry);
- silc_buffer_free(buffer);
+ silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
+ client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+ buffer->data, buffer->len, FALSE);
+ silc_buffer_free(buffer);
+}
+
+static int
+silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
+{
+ int sock;
+
+ /* Create connection to server asynchronously */
+ sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
+ if (sock < 0)
+ return -1;
+
+ /* Register task that will receive the async connect and will
+ read the result. */
+ ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
+ silc_client_perform_key_agreement_start,
+ (void *)ctx, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+ silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
+ FALSE);
+
+ ctx->sock = sock;
+
+ return sock;
+}
+
+/* Routine used by silc_client_perform_key_agreement to create connection
+ to the remote client on specified port. */
+
+static int
+silc_client_connect_to_client(SilcClient client,
+ SilcClientConnection conn, int port,
+ char *host, void *context)
+{
+ SilcClientInternalConnectContext *ctx;
+
+ /* Allocate internal context for connection process. This is
+ needed as we are doing async connecting. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->conn = conn;
+ ctx->host = strdup(host);
+ ctx->port = port;
+ ctx->tries = 0;
+ ctx->context = context;
+
+ /* Do the actual connecting process */
+ return silc_client_connect_to_client_internal(ctx);
+}
+
+/* Callback that is called after connection has been created. This actually
+ starts the key agreement protocol. This is initiator function. */
+
+SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
+{
+ SilcClientInternalConnectContext *ctx =
+ (SilcClientInternalConnectContext *)context;
+ SilcClient client = ctx->client;
+ SilcClientConnection conn = ctx->conn;
+ SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
+ int opt, opt_len = sizeof(opt);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Check the socket status as it might be in error */
+ silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
+ if (opt != 0) {
+ if (ctx->tries < 2) {
+ /* Connection failed but lets try again */
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of client %s resumed",
+ ctx->port, ctx->host);
+
+ /* Unregister old connection try */
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_net_close_connection(fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+
+ /* Try again */
+ silc_client_connect_to_client_internal(ctx);
+ ctx->tries++;
+ } else {
+ /* Connection failed and we won't try anymore */
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_net_close_connection(fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
+ silc_free(ctx->host);
+ silc_free(ctx);
+
+ /* Call the completion callback */
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
+ silc_free(ke);
+ }
return;
}
- /* Add key agreement timeout task */
- if (params && params->timeout_secs)
- silc_schedule_task_add_timeout(conn->internal->schedule,
- silc_client_keyagr_timeout,
- client_entry, params->timeout_secs, 0);
+ silc_schedule_unset_listen_fd(client->schedule, fd);
+ silc_schedule_task_del(client->schedule, ctx->task);
- silc_buffer_free(buffer);
+ ke->fd = fd;
+
+ /* Now actually perform the key agreement protocol */
+ silc_client_perform_key_agreement_fd(ke->client, ke->conn,
+ ke->client_entry, ke->fd, ctx->host,
+ ke->completion, ke->context);
+ silc_free(ke);
+ silc_free(ctx->host);
+ silc_free(ctx);
}
-/* Perform key agreement protocol as initiator. Conneects to remote host. */
+/* Performs the actual key agreement protocol. Application may use this
+ to initiate the key agreement protocol. This can be called for example
+ after the application has received the `key_agreement' client operation,
+ and did not return TRUE from it.
+
+ The `hostname' is the remote hostname (or IP address) and the `port'
+ is the remote port. The `completion' callback with the `context' will
+ be called after the key agreement protocol.
+
+ NOTE: If the application returns TRUE in the `key_agreement' client
+ operation the library will automatically start the key agreement. In this
+ case the application must not call this function. However, application
+ may choose to just ignore the `key_agreement' client operation (and
+ merely just print information about it on the screen) and call this
+ function when the user whishes to do so (by, for example, giving some
+ specific command). Thus, the API provides both, automatic and manual
+ initiation of the key agreement. Calling this function is the manual
+ initiation and returning TRUE in the `key_agreement' client operation
+ is the automatic initiation. */
void silc_client_perform_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *hostname, int port,
+ char *hostname,
+ int port,
SilcKeyAgreementCallback completion,
void *context)
{
SilcClientKeyAgreement ke;
- SILC_LOG_DEBUG(("Performing key agreement"));
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!client_entry)
+ return;
- if (!client_entry || !hostname || !port) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+ if (!hostname || !port) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
NULL, context);
return;
}
}
ke = silc_calloc(1, sizeof(*ke));
- if (!ke) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
- NULL, context);
- return;
- }
ke->client = client;
ke->conn = conn;
+ ke->client_entry = client_entry;
ke->completion = completion;
ke->context = context;
- silc_client_ref_client(client, conn, client_entry);
- client_entry->internal.ke = ke;
-
- if (params)
- params->no_authentication = TRUE;
-
- /* Connect to the remote client. Performs key exchange automatically. */
- ke->op = silc_client_connect_to_client(client, params, public_key,
- private_key, hostname, port,
- silc_client_keyagr_completion,
- client_entry);
- if (!ke->op) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+
+ /* Connect to the remote client */
+ ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
+ if (ke->fd < 0) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
NULL, context);
- silc_client_keyagr_free(client, conn, client_entry);
+ silc_free(ke);
return;
}
}
-/* Same as above but caller has created connection. */
-
-void
-silc_client_perform_key_agreement_stream(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcStream stream,
- SilcKeyAgreementCallback completion,
- void *context)
+/* Same as above but application has created already the connection to
+ the remote host. The `sock' is the socket to the remote connection.
+ Application can use this function if it does not want the client library
+ to create the connection. */
+
+void silc_client_perform_key_agreement_fd(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ int sock,
+ char *hostname,
+ SilcKeyAgreementCallback completion,
+ void *context)
{
SilcClientKeyAgreement ke;
+ SilcClientKEInternalContext *proto_ctx;
+ SilcProtocol protocol;
- SILC_LOG_DEBUG(("Performing key agreement"));
+ SILC_LOG_DEBUG(("Start"));
- if (!client_entry || !stream) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
- NULL, context);
+ if (!client_entry)
return;
- }
if (client_entry == conn->local_entry) {
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
}
ke = silc_calloc(1, sizeof(*ke));
- if (!ke) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
- NULL, context);
- return;
- }
ke->client = client;
ke->conn = conn;
+ ke->client_entry = client_entry;
+ ke->fd = sock;
ke->completion = completion;
ke->context = context;
- silc_client_ref_client(client, conn, client_entry);
- client_entry->internal.ke = ke;
-
- if (params)
- params->no_authentication = TRUE;
-
- /* Perform key exchange protocol */
- ke->op = silc_client_key_exchange(client, params, public_key,
- private_key, stream, SILC_CONN_CLIENT,
- silc_client_keyagr_completion,
- client_entry);
- if (!ke->op) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
- NULL, context);
- silc_client_keyagr_free(client, conn, client_entry);
- return;
- }
+
+ /* Allocate new socket connection object */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
+ silc_client_add_socket(client, ke->sock);
+ ke->sock->hostname = strdup(hostname);
+ ke->sock->port = silc_net_get_remote_port(sock);
+
+ /* Allocate internal context for key exchange protocol. This is
+ sent as context for the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = client;
+ proto_ctx->sock = silc_socket_dup(ke->sock);
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = FALSE;
+ proto_ctx->context = ke;
+ proto_ctx->send_packet = silc_client_key_agreement_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
+ ke->proto_ctx = proto_ctx;
+
+ /* Perform key exchange protocol. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &protocol, (void *)proto_ctx,
+ silc_client_key_agreement_final);
+ ke->sock->protocol = protocol;
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ However, this doesn't set the scheduler for outgoing traffic, it will
+ be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)client;
+ SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Execute the protocol */
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
}
/* This function can be called to unbind the hostname and the port for
SilcClientConnection conn,
SilcClientEntry client_entry)
{
- SilcClientKeyAgreement ke;
-
- if (!client_entry || !client_entry->internal.ke)
+ if (!client_entry)
return;
- ke = client_entry->internal.ke;
+ if (client_entry->ke) {
+ SilcClientKeyAgreement ke;
- SILC_LOG_DEBUG(("Abort key agreement %p"));
-
- ke->completion(client, conn, client_entry,
- SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
-
- silc_client_keyagr_free(client, conn, client_entry);
+ if (client_entry->ke->sock) {
+ silc_client_del_socket(client_entry->ke->client, client_entry->ke->sock);
+ silc_socket_free(client_entry->ke->sock);
+ }
+ silc_schedule_task_del_by_fd(client->schedule, client_entry->ke->fd);
+ if (client_entry->ke->timeout)
+ silc_schedule_task_del(client->schedule,
+ client_entry->ke->timeout);
+ ke = client_entry->ke;
+ client_entry->ke = NULL;
+ ke->completion(client, conn, client_entry,
+ SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
+ silc_free(ke);
+ }
}
-/* Key agreement packet received */
+/* Callback function that is called after we've resolved the client
+ information who sent us the key agreement packet from the server.
+ We actually call the key_agreement client operation now. */
-SILC_FSM_STATE(silc_client_key_agreement)
+static void
+silc_client_key_agreement_resolve_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
+ void *context)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcClientID remote_id;
- SilcClientEntry remote_client;
+ SilcPacketContext *packet = (SilcPacketContext *)context;
SilcKeyAgreementPayload payload;
+ int ret;
+ SilcKeyAgreementCallback completion;
+ void *completion_context;
- if (packet->src_id_type != SILC_ID_CLIENT) {
- /** Invalid packet */
- silc_fsm_next(fsm, silc_client_key_agreement_error);
- return SILC_FSM_CONTINUE;
- }
-
- if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
- &remote_id, sizeof(remote_id))) {
- /** Invalid source ID */
- silc_fsm_next(fsm, silc_client_key_agreement_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Check whether we know this client already */
- remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
- if (!remote_client || !remote_client->internal.valid) {
- /** Resolve client info */
- silc_client_unref_client(client, conn, remote_client);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &remote_id, NULL,
- silc_client_keyagr_resolved, fsm));
- /* NOT REACHED */
- }
+ if (!clients)
+ goto out;
/* Parse the key agreement payload */
- payload = silc_key_agreement_payload_parse(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer));
- if (!payload) {
- /** Malformed Payload */
- SILC_LOG_DEBUG(("Malformed key agreement payload"));
- silc_fsm_next(fsm, silc_client_key_agreement_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* If remote did not provide connection endpoint, we will assume that we
- will provide it and will be responder. */
- if (!silc_key_agreement_get_hostname(payload))
- remote_client->internal.prv_resp = TRUE;
- else
- remote_client->internal.prv_resp = FALSE;
-
- /* Notify application for key agreement request */
- client->internal->ops->key_agreement(
- client, conn, remote_client,
+ payload = silc_key_agreement_payload_parse(packet->buffer->data,
+ packet->buffer->len);
+ if (!payload)
+ goto out;
+
+ /* Call the key_agreement client operation */
+ ret = client->internal->ops->key_agreement(
+ client, conn, clients[0],
silc_key_agreement_get_hostname(payload),
- silc_key_agreement_get_protocol(payload),
- silc_key_agreement_get_port(payload));
+ silc_key_agreement_get_port(payload),
+ &completion, &completion_context);
+
+ /* If the user returned TRUE then we'll start the key agreement right
+ here and right now. */
+ if (ret == TRUE)
+ silc_client_perform_key_agreement(client, conn, clients[0],
+ silc_key_agreement_get_hostname(payload),
+ silc_key_agreement_get_port(payload),
+ completion, completion_context);
silc_key_agreement_payload_free(payload);
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
+ out:
+ silc_packet_context_free(packet);
}
-/* Key agreement packet processing error */
+/* Received Key Agreement packet from remote client. Process the packet
+ and resolve the client information from the server before actually
+ letting the application know that we've received this packet. Then
+ call the key_agreement client operation and let the user decide
+ whether we perform the key agreement protocol now or not. */
-SILC_FSM_STATE(silc_client_key_agreement_error)
+void silc_client_key_agreement(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcPacket packet = state_context;
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
+ SilcClientID *remote_id;
+
+ if (packet->src_id_type != SILC_ID_CLIENT)
+ return;
+
+ remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!remote_id)
+ return;
+
+ silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+ NULL,
+ silc_client_key_agreement_resolve_cb,
+ silc_packet_context_dup(packet));
+ silc_free(remote_id);
}
+++ /dev/null
-/*
-
- client_listener.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2007 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 "silcclient.h"
-#include "client_internal.h"
-
-/************************** Types and definitions ***************************/
-
-/* Listener context */
-struct SilcClientListenerStruct {
- SilcClient client; /* Client */
- SilcSchedule schedule; /* Scheduler */
- SilcClientConnectCallback callback; /* Connection callback */
- void *context; /* User context */
- SilcClientConnectionParams params; /* Connection parameters */
- SilcPublicKey public_key; /* Responder public key */
- SilcPrivateKey private_key; /* Responder private key */
- SilcNetListener tcp_listener; /* TCP listener */
- SilcPacketStream udp_listener; /* UDP listener */
-};
-
-/************************ Static utility functions **************************/
-
-/* Called after application has verified remote host's public key. */
-
-static void silc_client_listener_verify_key_cb(SilcBool success, void *context)
-{
- SilcVerifyKeyContext verify = context;
-
- /* Call the completion callback back to the SKE */
- verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
- SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
- verify->completion_context);
-
- silc_free(verify);
-}
-
-/* Verify remote host's public key. */
-
-static void
-silc_client_listener_verify_key(SilcSKE ske,
- SilcPublicKey public_key,
- void *context,
- SilcSKEVerifyCbCompletion completion,
- void *completion_context)
-{
- SilcClientConnection conn = context;
- SilcClient client = conn->client;
- SilcVerifyKeyContext verify;
-
- /* If we provided repository for SKE and we got here the key was not
- found from the repository. */
- if (conn->internal->params.repository &&
- !conn->internal->params.verify_notfound) {
- completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
- completion_context);
- return;
- }
-
- SILC_LOG_DEBUG(("Verify remote public key"));
-
- verify = silc_calloc(1, sizeof(*verify));
- if (!verify) {
- completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
- completion_context);
- return;
- }
- verify->ske = ske;
- verify->completion = completion;
- verify->completion_context = completion_context;
-
- /* Verify public key in application */
- client->internal->ops->verify_public_key(client, conn,
- SILC_CONN_CLIENT, public_key,
- silc_client_listener_verify_key_cb,
- verify);
-}
-
-/* Key exchange protocol completion callback. */
-
-static void silc_client_listener_completion(SilcSKE ske,
- SilcSKEStatus status,
- SilcSKESecurityProperties prop,
- SilcSKEKeyMaterial keymat,
- SilcSKERekeyMaterial rekey,
- void *context)
-{
- SilcClientConnection conn = context;
- SilcCipher send_key, receive_key;
- SilcHmac hmac_send, hmac_receive;
-
- SILC_LOG_DEBUG(("Key exchange completed"));
-
- if (status != SILC_SKE_STATUS_OK) {
- /* Key exchange failed */
- conn->callback(conn->client, conn,
- status == SILC_SKE_STATUS_TIMEOUT ?
- SILC_CLIENT_CONN_ERROR_TIMEOUT :
- SILC_CLIENT_CONN_ERROR_KE, conn->internal->error,
- conn->internal->disconnect_message,
- conn->callback_context);
- return;
- }
-
- /* Allocate the cipher and HMAC contexts */
- if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
- &hmac_send, &hmac_receive, &conn->internal->hash)) {
- conn->callback(conn->client, conn,
- SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
- conn->callback_context);
- return;
- }
-
- /* Set the keys into the packet stream. After this call packets will be
- encrypted with these keys. */
- if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
- hmac_receive, FALSE)) {
- conn->callback(conn->client, conn,
- SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
- conn->callback_context);
- return;
- }
-
- /* Key exchange successful */
- conn->callback(conn->client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
- conn->callback_context);
-}
-
-/* Starts key agreement as responder. */
-
-static void
-silc_client_listener_new_connection(SilcClientListener listener,
- SilcPacketStream stream)
-{
- SilcClient client = listener->client;
- SilcClientConnection conn;
- SilcSKEParamsStruct params;
- const char *hostname = NULL, *ip = NULL;
- SilcUInt16 port;
-
- /* Get remote information */
- silc_socket_stream_get_info(silc_packet_stream_get_stream(stream),
- NULL, &hostname, &ip, &port);
- if (!ip || !port) {
- listener->callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL,
- listener->context);
- silc_packet_stream_destroy(stream);
- return;
- }
- if (!hostname)
- hostname = ip;
-
- /* Add new connection */
- conn = silc_client_add_connection(client, SILC_CONN_CLIENT, FALSE,
- &listener->params,
- listener->public_key,
- listener->private_key,
- (char *)hostname, port,
- listener->callback, listener->context);
- if (!conn) {
- listener->callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL,
- listener->context);
- silc_packet_stream_destroy(stream);
- return;
- }
- conn->stream = stream;
- conn->internal->schedule = listener->schedule;
- silc_packet_set_context(conn->stream, conn);
-
- SILC_LOG_DEBUG(("Processing new incoming connection %p", conn));
-
- /* Allocate SKE */
- conn->internal->ske =
- silc_ske_alloc(client->rng, conn->internal->schedule,
- listener->params.repository, listener->public_key,
- listener->private_key, listener);
- if (!conn->internal->ske) {
- conn->callback(conn->client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
- conn->callback_context);
- return;
- }
-
- /* Set SKE parameters */
- params.version = client->internal->silc_client_version;
- params.flags = SILC_SKE_SP_FLAG_MUTUAL;
- if (listener->params.udp) {
- params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
- params.session_port = listener->params.local_port;
- }
-
- silc_ske_set_callbacks(conn->internal->ske, silc_client_listener_verify_key,
- silc_client_listener_completion, conn);
-
- /* Start key exchange as responder */
- conn->internal->op = silc_ske_responder(conn->internal->ske,
- conn->stream, ¶ms);
- if (!conn->internal->op)
- conn->callback(conn->client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
- conn->callback_context);
-}
-
-/* TCP network listener callback. Accepts new key agreement connection.
- Responder function. */
-
-static void silc_client_listener_tcp_accept(SilcNetStatus status,
- SilcStream stream,
- void *context)
-{
- SilcClientListener listener = context;
- SilcPacketStream packet_stream;
-
- SILC_LOG_DEBUG(("New incoming TCP connection"));
-
- /* Create packet stream */
- packet_stream =
- silc_packet_stream_create(listener->client->internal->packet_engine,
- listener->schedule, stream);
- if (!packet_stream) {
- silc_stream_destroy(stream);
- return;
- }
-
- /* Process session */
- silc_client_listener_new_connection(listener, packet_stream);
-}
-
-/* UDP network listener callback. Accepts new key agreement session.
- Responder function. */
-
-static SilcBool silc_client_udp_accept(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context)
-{
- SilcClientListener listener = callback_context;
- SilcPacketStream packet_stream;
- SilcUInt16 port;
- const char *ip;
-
- SILC_LOG_DEBUG(("New incoming UDP connection"));
-
- /* We want only key exchange packet. Eat other packets so that default
- packet callback doesn't get them. */
- if (packet->type != SILC_PACKET_KEY_EXCHANGE) {
- silc_packet_free(packet);
- return TRUE;
- }
-
- /* Create packet stream for this remote UDP session */
- if (!silc_packet_get_sender(packet, &ip, &port)) {
- silc_packet_free(packet);
- return TRUE;
- }
- packet_stream = silc_packet_stream_add_remote(stream, ip, port, packet);
- if (!packet_stream) {
- silc_packet_free(packet);
- return TRUE;
- }
-
- /* Process session */
- silc_client_listener_new_connection(listener, packet_stream);
- return TRUE;
-}
-
-/* Packet stream callbacks */
-static SilcPacketCallbacks silc_client_listener_stream_cb =
-{
- silc_client_udp_accept, NULL, NULL
-};
-
-/***************************** Listner routines *****************************/
-
-/* Adds network listener. The `callback' will be called after new conection
- has arrived and key exchange protocol has been completed. */
-
-SilcClientListener
-silc_client_listener_add(SilcClient client,
- SilcSchedule schedule,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcClientConnectCallback callback,
- void *context)
-{
- SilcClientListener listener;
- SilcStream stream;
-
- if (!client || !schedule ||
- !params || (!params->local_ip && !params->bind_ip))
- return NULL;
-
- SILC_LOG_DEBUG(("Adding new listener"));
-
- listener = silc_calloc(1, sizeof(*listener));
- if (!listener)
- return NULL;
- listener->client = client;
- listener->schedule = schedule;
- listener->callback = callback;
- listener->context = context;
- listener->params = *params;
- listener->public_key = public_key;
- listener->private_key = private_key;
-
- /* Create network listener */
- if (params->udp) {
- /* UDP listener */
- stream = silc_net_udp_connect(params->bind_ip ? params->bind_ip :
- params->local_ip, params->local_port,
- NULL, 0, schedule);
- listener->udp_listener =
- silc_packet_stream_create(client->internal->packet_engine,
- schedule, stream);
- if (!listener->udp_listener) {
- client->internal->ops->say(
- client, NULL, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot create UDP listener on %s on port %d: %s",
- params->bind_ip ? params->bind_ip :
- params->local_ip, params->local_port, strerror(errno));
- silc_client_listener_free(listener);
- if (stream)
- silc_stream_destroy(stream);
- return NULL;
- }
- silc_packet_stream_link(listener->udp_listener,
- &silc_client_listener_stream_cb, listener,
- 1000000, SILC_PACKET_ANY, -1);
-
- if (!params->local_port) {
- /* Get listener port */
- SilcSocket sock;
- silc_socket_stream_get_info(stream, &sock, NULL, NULL, NULL);
- listener->params.local_port = silc_net_get_local_port(sock);
- }
- } else {
- /* TCP listener */
- listener->tcp_listener =
- silc_net_tcp_create_listener(params->bind_ip ?
- (const char **)¶ms->bind_ip :
- (const char **)¶ms->local_ip,
- 1, params->local_port, TRUE, FALSE,
- schedule, silc_client_listener_tcp_accept,
- listener);
- if (!listener->tcp_listener) {
- client->internal->ops->say(
- client, NULL, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot create listener on %s on port %d: %s",
- params->bind_ip ? params->bind_ip :
- params->local_ip, params->local_port, strerror(errno));
-
- silc_client_listener_free(listener);
- return NULL;
- }
-
- if (!params->local_port) {
- /* Get listener port */
- SilcUInt16 *ports;
- ports = silc_net_listener_get_port(listener->tcp_listener, NULL);
- listener->params.local_port = ports[0];
- silc_free(ports);
- }
- }
-
- SILC_LOG_DEBUG(("Bound listener to %s:%d",
- params->bind_ip ? params->bind_ip : params->local_ip,
- listener->params.local_port));
-
- return listener;
-}
-
-/* Close and free listner */
-
-void silc_client_listener_free(SilcClientListener listener)
-{
- if (listener->tcp_listener)
- silc_net_close_listener(listener->tcp_listener);
- silc_packet_stream_destroy(listener->udp_listener);
- silc_free(listener);
-}
-
-/* Return listner bound port */
-
-SilcUInt16 silc_client_listener_get_local_port(SilcClientListener listener)
-{
- return listener->params.local_port;
-}
+++ /dev/null
-/*
-
- client_listener.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2007 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 CLIENT_LISTENER_H
-#define CLIENT_LISTENER_H
-
-/* Forward declarations */
-typedef struct SilcClientListenerStruct *SilcClientListener;
-
-SilcClientListener
-silc_client_listener_add(SilcClient client,
- SilcSchedule schedule,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcClientConnectCallback callback,
- void *context);
-void silc_client_listener_free(SilcClientListener listener);
-SilcUInt16 silc_client_listener_get_local_port(SilcClientListener listener);
-
-#endif /* CLIENT_LISTENER_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
+/* This file includes the Notify packet handling. Notify packets are
+ important packets sent by the server. They tell different things to the
+ client such as nick changes, mode changes etc. */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
-
-#define NOTIFY conn->client->internal->ops->notify
-
-/* Notify processing context */
+/* Context used for resolving client, channel and server info. */
typedef struct {
- SilcPacket packet; /* Notify packet */
- SilcNotifyPayload payload; /* Parsed notify payload */
- SilcFSMThread fsm; /* Notify FSM thread */
- SilcChannelEntry channel; /* Channel entry being resolved */
- SilcClientEntry client_entry; /* Client entry being resolved */
-} *SilcClientNotify;
-
-/************************ Static utility functions **************************/
-
-/* The client entires in notify processing are resolved if they do not exist,
- or they are not valid. We go to this callback after resolving where we
- check if the client entry has become valid. If resolving succeeded the
- entry is valid but remains invalid if resolving failed. This callback
- will continue processing the notify. We use this callback also with other
- entry resolving. */
-
-static void silc_client_notify_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList entries,
- void *context)
-{
- SilcClientNotify notify = context;
-
- /* If entry is still invalid, resolving failed. Finish notify processing. */
- if (notify->client_entry && !notify->client_entry->internal.valid) {
- silc_fsm_next(notify->fsm, silc_client_notify_processed);
- silc_client_unref_client(client, conn, notify->client_entry);
- }
-
- /* If no entries found, just finish the notify processing */
- if (!entries && !notify->client_entry)
- silc_fsm_next(notify->fsm, silc_client_notify_processed);
-
- if (notify->channel) {
- notify->channel->internal.resolve_cmd_ident = 0;
- silc_client_unref_channel(client, conn, notify->channel);
- }
+ void *packet;
+ void *context;
+ SilcSocketConnection sock;
+} *SilcClientNotifyResolve;
- /* Continue processing the notify */
- SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
+SILC_TASK_CALLBACK(silc_client_notify_check_client)
+{
+ SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+ SilcClient client = res->context;
+ SilcClientConnection conn = res->sock->user_data;
+ SilcClientID *client_id = res->packet;
+ silc_client_get_client_by_id_resolve(client, conn, client_id,
+ NULL, NULL, NULL);
+ silc_free(client_id);
+ silc_socket_free(res->sock);
+ silc_free(res);
}
-/* Continue notify processing after it was suspended while waiting for
- channel information being resolved. */
-
-static SilcBool silc_client_notify_wait_continue(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
+SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
{
- SilcClientNotify notify = context;
-
- /* Continue after last command reply received */
- if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
- status == SILC_STATUS_LIST_END)
- SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
-
- return TRUE;
+ SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+ SilcClient client = res->context;
+ SilcClientConnection conn = res->sock->user_data;
+ SilcClientID *client_id = res->packet;
+ SilcClientEntry client_entry;
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (client_entry)
+ silc_client_del_client(client, conn, client_entry);
+ silc_free(client_id);
+ silc_socket_free(res->sock);
+ silc_free(res);
}
-/********************************* Notify ***********************************/
-
-/* Process received notify packet */
+/* Called when notify is received and some async operation (such as command)
+ is required before processing the notify message. This calls again the
+ silc_client_notify_by_server and reprocesses the original notify packet. */
-SILC_FSM_STATE(silc_client_notify)
+static void silc_client_notify_by_server_pending(void *context, void *context2)
{
- SilcPacket packet = state_context;
- SilcClientNotify notify;
- SilcNotifyPayload payload;
-
- payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer));
- if (!payload) {
- SILC_LOG_DEBUG(("Malformed notify payload"));
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- }
-
- if (!silc_notify_get_args(payload)) {
- SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
- silc_notify_payload_free(payload);
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- }
-
- notify = silc_calloc(1, sizeof(*notify));
- if (!notify) {
- silc_notify_payload_free(payload);
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- }
-
- notify->packet = packet;
- notify->payload = payload;
- notify->fsm = fsm;
- silc_fsm_set_state_context(fsm, notify);
-
- /* Process the notify */
- switch (silc_notify_get_type(payload)) {
-
- case SILC_NOTIFY_TYPE_NONE:
- /** NONE */
- silc_fsm_next(fsm, silc_client_notify_none);
- break;
+ SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+ SilcClientCommandReplyContext reply =
+ (SilcClientCommandReplyContext)context2;
- case SILC_NOTIFY_TYPE_INVITE:
- /** INVITE */
- silc_fsm_next(fsm, silc_client_notify_invite);
- break;
-
- case SILC_NOTIFY_TYPE_JOIN:
- /** JOIN */
- silc_fsm_next(fsm, silc_client_notify_join);
- break;
-
- case SILC_NOTIFY_TYPE_LEAVE:
- /** LEAVE */
- silc_fsm_next(fsm, silc_client_notify_leave);
- break;
-
- case SILC_NOTIFY_TYPE_SIGNOFF:
- /** SIGNOFF */
- silc_fsm_next(fsm, silc_client_notify_signoff);
- break;
-
- case SILC_NOTIFY_TYPE_TOPIC_SET:
- /** TOPIC_SET */
- silc_fsm_next(fsm, silc_client_notify_topic_set);
- break;
-
- case SILC_NOTIFY_TYPE_NICK_CHANGE:
- /** NICK_CHANGE */
- silc_fsm_next(fsm, silc_client_notify_nick_change);
- break;
-
- case SILC_NOTIFY_TYPE_CMODE_CHANGE:
- /** CMODE_CHANGE */
- silc_fsm_next(fsm, silc_client_notify_cmode_change);
- break;
-
- case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
- /** CUMODE_CHANGE */
- silc_fsm_next(fsm, silc_client_notify_cumode_change);
- break;
-
- case SILC_NOTIFY_TYPE_MOTD:
- /** MOTD */
- silc_fsm_next(fsm, silc_client_notify_motd);
- break;
-
- case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
- /** CHANNEL_CHANGE */
- silc_fsm_next(fsm, silc_client_notify_channel_change);
- break;
+ SILC_LOG_DEBUG(("Start"));
- case SILC_NOTIFY_TYPE_KICKED:
- /** KICKED */
- silc_fsm_next(fsm, silc_client_notify_kicked);
- break;
-
- case SILC_NOTIFY_TYPE_KILLED:
- /** KILLED */
- silc_fsm_next(fsm, silc_client_notify_killed);
- break;
-
- case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
- /** SERVER_SIGNOFF */
- silc_fsm_next(fsm, silc_client_notify_server_signoff);
- break;
+ if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
+ goto out;
- case SILC_NOTIFY_TYPE_ERROR:
- /** ERROR */
- silc_fsm_next(fsm, silc_client_notify_error);
- break;
+ silc_client_notify_by_server(res->context, res->sock, res->packet);
- case SILC_NOTIFY_TYPE_WATCH:
- /** WATCH */
- silc_fsm_next(fsm, silc_client_notify_watch);
- break;
-
- default:
- /** Unknown notify */
- silc_notify_payload_free(payload);
- silc_packet_free(packet);
- silc_free(notify);
- return SILC_FSM_FINISH;
- break;
- }
-
- return SILC_FSM_CONTINUE;
+ out:
+ silc_socket_free(res->sock);
+ silc_packet_context_free(res->packet);
+ silc_free(res);
}
-/* Notify processed, finish the packet processing thread */
+/* Resets the channel entry's resolve_cmd_ident after whatever-thing
+ was resolved is completed. */
-SILC_FSM_STATE(silc_client_notify_processed)
+static void silc_client_channel_cond(void *context, void *context2)
{
- SilcClientNotify notify = state_context;
- SilcPacket packet = notify->packet;
- SilcNotifyPayload payload = notify->payload;
-
- silc_notify_payload_free(payload);
- silc_packet_free(packet);
- silc_free(notify);
- return SILC_FSM_FINISH;
+ SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
+ SilcClient client = res->context;
+ SilcClientConnection conn = res->sock->user_data;
+ SilcChannelID *channel_id = res->packet;
+ SilcChannelEntry channel;
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (channel)
+ channel->resolve_cmd_ident = 0;
+ silc_free(channel_id);
+ silc_socket_free(res->sock);
+ silc_free(res);
}
-/********************************** NONE ************************************/
+/* Function that starts waiting for the `cmd_ident' to arrive and
+ marks the channel info being resolved. */
-SILC_FSM_STATE(silc_client_notify_none)
+static void silc_client_channel_set_wait(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcUInt16 cmd_ident)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
-
- SILC_LOG_DEBUG(("Notify: NONE"));
-
- /* Notify application */
- NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
-
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
-
-/********************************* INVITE ***********************************/
-
-/* Someone invite me to a channel */
-
-SILC_FSM_STATE(silc_client_notify_invite)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry;
- SilcChannelEntry channel = NULL;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
- SilcID id;
-
- SILC_LOG_DEBUG(("Notify: INVITE"));
-
- /* Get Channel ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
-
- /* Get the channel name */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (!tmp)
- goto out;
-
- /* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
-
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
-
- /* Get sender Client ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
-
- /* Find Client entry and if not found query it */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry || !client_entry->internal.valid) {
- /** Resolve client */
- silc_client_unref_client(client, conn, client_entry);
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
+ SilcClientNotifyResolve res;
+
+ if (!channel->resolve_cmd_ident) {
+ res = silc_calloc(1, sizeof(*res));
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
+ silc_client_channel_cond, res);
+ channel->resolve_cmd_ident = cmd_ident;
}
-
- /* Notify application */
- NOTIFY(client, conn, type, channel, tmp, client_entry);
-
- silc_client_unref_client(client, conn, client_entry);
-
- out:
- /** Notify processed */
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
}
-/********************************** JOIN ************************************/
-
-/* Someone joined a channel */
+/* Attaches to the channel's resolving cmd ident and calls the
+ notify handling with `packet' after it's received. */
-SILC_FSM_STATE(silc_client_notify_join)
+static void silc_client_channel_wait(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry;
- SilcChannelEntry channel = NULL;
- SilcID id;
-
- SILC_LOG_DEBUG(("Notify: JOIN"));
-
- /* Get Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
-
- /* Get channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
-
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
+ SilcClientNotifyResolve res;
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
-
- /* Find client entry and if not found query it. If we just queried it
- don't do it again, unless some data (like username) is missing. */
- client_entry = notify->client_entry;
- if (!client_entry)
- client_entry = silc_client_get_client(client, conn, &id.u.client_id);
- if (!client_entry || !client_entry->internal.valid ||
- !client_entry->username[0]) {
- /** Resolve client */
- notify->channel = channel;
- notify->client_entry = client_entry;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_client_by_id_resolve(
- client, conn, client_entry ?
- &client_entry->id : &id.u.client_id,
- NULL, silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
-
- silc_rwlock_wrlock(client_entry->internal.lock);
- silc_rwlock_wrlock(channel->internal.lock);
-
- if (client_entry != conn->local_entry)
- silc_client_nickname_format(client, conn, client_entry, FALSE);
-
- /* Join the client to channel */
- if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0)) {
- silc_rwlock_unlock(channel->internal.lock);
- silc_rwlock_unlock(client_entry->internal.lock);
- goto out;
- }
+ if (!channel->resolve_cmd_ident)
+ return;
- silc_rwlock_unlock(channel->internal.lock);
- silc_rwlock_unlock(client_entry->internal.lock);
+ res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
- /* Notify application. */
- NOTIFY(client, conn, type, client_entry, channel);
-
- silc_client_unref_client(client, conn, client_entry);
-
- out:
- /** Notify processed */
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ channel->resolve_cmd_ident,
+ silc_client_notify_by_server_pending, res);
}
-/********************************** LEAVE ***********************************/
-
-/* Someone left a channel */
+/* Resolve client, channel or server information. */
-SILC_FSM_STATE(silc_client_notify_leave)
+static void silc_client_notify_by_server_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcPacketContext *packet,
+ SilcIdType id_type,
+ void *id)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcPacket packet = notify->packet;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL;
- SilcChannelEntry channel = NULL;
- SilcID id;
-
- SILC_LOG_DEBUG(("Notify: LEAVE"));
-
- /* Get channel entry */
- if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id)))
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
-
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ SilcBuffer idp = silc_id_payload_encode(id, id_type);
+
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+
+ /* For client resolving use WHOIS, and otherwise use IDENTIFY */
+ if (id_type == SILC_ID_CLIENT) {
+ silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ ++conn->cmd_ident);
+ silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ 1, 4, idp->data, idp->len);
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ silc_client_notify_by_server_pending, res);
+ } else {
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 5, idp->data, idp->len);
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+ silc_client_notify_by_server_pending, res);
}
-
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
-
- /* Find Client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry)
- goto out;
-
- /* Remove client from channel */
- if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
- goto out;
-
- /* Notify application. */
- NOTIFY(client, conn, type, client_entry, channel);
-
- silc_client_unref_client(client, conn, client_entry);
-
- out:
- /** Notify processed */
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
+ silc_buffer_free(idp);
}
-/********************************* SIGNOFF **********************************/
-
-/* Someone quit SILC network */
+/* Received notify message from server */
-SILC_FSM_STATE(silc_client_notify_signoff)
+void silc_client_notify_by_server(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcPacket packet = notify->packet;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry;
+ SilcBuffer buffer = packet->buffer;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcNotifyPayload payload;
+ SilcNotifyType type;
+ SilcArgumentPayload args;
+
+ void *id;
+ SilcIdType id_type;
+ SilcClientID *client_id = NULL;
+ SilcChannelID *channel_id = NULL;
+ SilcServerID *server_id = NULL;
+ SilcClientEntry client_entry = NULL;
+ SilcClientEntry client_entry2 = NULL;
SilcChannelEntry channel;
+ SilcChannelUser chu;
+ SilcServerEntry server;
unsigned char *tmp;
- SilcUInt32 tmp_len;
- SilcID id;
+ SilcUInt32 tmp_len, mode;
- SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+ SILC_LOG_DEBUG(("Start"));
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
+ payload = silc_notify_payload_parse(buffer->data, buffer->len);
+ if (!payload)
goto out;
- /* Find Client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry)
+ type = silc_notify_get_type(payload);
+ args = silc_notify_get_args(payload);
+ if (!args)
goto out;
- /* Get signoff message */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (tmp && tmp_len > 128)
- tmp[128] = '\0';
-
- /* Notify application */
- if (client_entry->internal.valid)
- NOTIFY(client, conn, type, client_entry, tmp);
-
- /* Remove from channel */
- if (packet->dst_id_type == SILC_ID_CHANNEL) {
- if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id))) {
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (channel) {
- silc_client_remove_from_channel(client, conn, channel, client_entry);
- silc_client_unref_channel(client, conn, channel);
- }
- }
- }
-
- /* Delete client */
- client_entry->internal.valid = FALSE;
- silc_client_del_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry);
-
- out:
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
-
-/******************************** TOPIC_SET *********************************/
+ switch(type) {
+ case SILC_NOTIFY_TYPE_NONE:
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type,
+ silc_argument_get_arg_type(args, 1, NULL));
+ break;
-/* Someone set topic on a channel */
+ case SILC_NOTIFY_TYPE_INVITE:
+ /*
+ * Someone invited me to a channel. Find Client and Channel entries
+ * for the application.
+ */
-SILC_FSM_STATE(silc_client_notify_topic_set)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcPacket packet = notify->packet;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL;
- SilcChannelEntry channel = NULL, channel_entry = NULL;
- SilcServerEntry server = NULL;
- void *entry;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
- SilcID id;
+ SILC_LOG_DEBUG(("Notify: INVITE"));
- SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get channel entry */
- if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id)))
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!channel_id)
+ goto out;
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
+ /* Get the channel entry */
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
- /* Get ID of topic changer */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ /* Get sender Client ID */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get topic */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (!tmp)
- goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- if (id.type == SILC_ID_CLIENT) {
- /* Find Client entry */
- client_entry = notify->client_entry;
+ /* Find Client entry and if not found query it */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- client_entry = silc_client_get_client(client, conn, &id.u.client_id);
- if (!client_entry || !client_entry->internal.valid) {
- /** Resolve client */
- notify->channel = channel;
- notify->client_entry = client_entry;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
- }
-
- /* If client is not on channel, ignore this notify */
- if (!silc_client_on_channel(channel, client_entry))
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
goto out;
-
- entry = client_entry;
- } else if (id.type == SILC_ID_SERVER) {
- /* Find Server entry */
- server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
- if (!server) {
- /** Resolve server */
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_server_by_id_resolve(
- client, conn, &id.u.server_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
- entry = server;
- } else {
- /* Find Channel entry */
- channel_entry = silc_client_get_channel_by_id(client, conn,
- &id.u.channel_id);
- if (!channel_entry) {
- /** Resolve channel */
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_channel_by_id_resolve(
- client, conn, &id.u.channel_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
}
- entry = channel_entry;
- }
-
- silc_rwlock_wrlock(channel->internal.lock);
- silc_free(channel->topic);
- channel->topic = silc_memdup(tmp, strlen(tmp));
- silc_rwlock_unlock(channel->internal.lock);
- /* Notify application. */
- NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
-
- if (client_entry)
- silc_client_unref_client(client, conn, client_entry);
- if (server)
- silc_client_unref_server(client, conn, server);
- if (channel_entry)
- silc_client_unref_channel(client, conn, channel_entry);
-
- out:
- /** Notify processed */
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
-
-/****************************** NICK_CHANGE *********************************/
-
-/* Someone changed their nickname on a channel */
-
-SILC_FSM_STATE(silc_client_notify_nick_change)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL;
- unsigned char *tmp, oldnick[128 + 1];
- SilcUInt32 tmp_len;
- SilcID id, id2;
- SilcBool valid;
-
- SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
-
- /* Get ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
-
- /* Ignore my ID */
- if (conn->local_id &&
- SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
- goto out;
-
- /* Get new Client ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
- goto out;
-
- /* Ignore my ID */
- if (conn->local_id &&
- SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
- goto out;
-
- /* Find old client entry. If we don't have the entry, we ignore this
- notify. */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry)
- goto out;
- valid = client_entry->internal.valid;
-
- /* Take the new nickname */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (!tmp)
- goto out;
-
- silc_rwlock_wrlock(client_entry->internal.lock);
-
- /* Check whether nickname changed at all. It is possible that nick
- change notify is received but nickname didn't change, only the
- ID changes. If Client ID hash match, nickname didn't change. */
- if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
- silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
- /* Nickname didn't change. Update only Client ID. We don't notify
- application because nickname didn't change. */
- silc_mutex_lock(conn->internal->lock);
- silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
- &id2.u.client_id, NULL, FALSE);
- silc_mutex_unlock(conn->internal->lock);
- silc_rwlock_unlock(client_entry->internal.lock);
- goto out;
- }
-
- /* Change the nickname */
- memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
- if (!silc_client_change_nickname(client, conn, client_entry, tmp,
- &id2.u.client_id, NULL, 0)) {
- silc_rwlock_unlock(client_entry->internal.lock);
- goto out;
- }
-
- silc_rwlock_unlock(client_entry->internal.lock);
-
- /* Notify application, if client entry is valid. We do not send nick change
- notify for entries that were invalid (application doesn't know them). */
- if (valid)
- NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
-
- out:
- /** Notify processed */
- silc_client_unref_client(client, conn, client_entry);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Get the channel name */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
-/****************************** CMODE_CHANGE ********************************/
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type, channel, tmp,
+ client_entry);
+ break;
-/* Someone changed channel mode */
+ case SILC_NOTIFY_TYPE_JOIN:
+ /*
+ * Someone has joined to a channel. Get their ID and nickname and
+ * cache them for later use.
+ */
-SILC_FSM_STATE(silc_client_notify_cmode_change)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcPacket packet = notify->packet;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL;
- SilcChannelEntry channel = NULL, channel_entry = NULL;
- SilcServerEntry server = NULL;
- void *entry;
- unsigned char *tmp;
- SilcUInt32 tmp_len, mode;
- SilcID id;
- char *passphrase, *cipher, *hmac;
- SilcPublicKey founder_key = NULL;
- SilcDList chpks = NULL;
+ SILC_LOG_DEBUG(("Notify: JOIN"));
- SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get channel entry */
- if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id)))
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!channel_id)
+ goto out;
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
+ /* Get channel entry */
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ break;
- /* Get the mode */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (!tmp)
- goto out;
- SILC_GET32_MSB(mode, tmp);
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get ID of who changed the mode */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- if (id.type == SILC_ID_CLIENT) {
- /* Find Client entry */
- client_entry = notify->client_entry;
+ /* Find Client entry and if not found query it */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- client_entry = silc_client_get_client(client, conn, &id.u.client_id);
- if (!client_entry || !client_entry->internal.valid) {
- /** Resolve client */
- notify->channel = channel;
- notify->client_entry = client_entry;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
}
- /* If client is not on channel, ignore this notify */
- if (!silc_client_on_channel(channel, client_entry))
+ /* If nickname or username hasn't been resolved, do so */
+ if (!client_entry->nickname || !client_entry->username) {
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to existing resolving */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Do new resolving */
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ client_entry->resolve_cmd_ident = conn->cmd_ident;
goto out;
+ } else {
+ if (client_entry != conn->local_entry)
+ silc_client_nickname_format(client, conn, client_entry);
+ }
- entry = client_entry;
- } else if (id.type == SILC_ID_SERVER) {
- /* Find Server entry */
- server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
- if (!server) {
- /** Resolve server */
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_server_by_id_resolve(
- client, conn, &id.u.server_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
+ /* If information is being resolved for this channel, wait for it */
+ if (channel->resolve_cmd_ident) {
+ silc_client_channel_wait(client, conn, channel, packet);
+ goto out;
}
- entry = server;
- } else {
- /* Find Channel entry */
- channel_entry = silc_client_get_channel_by_id(client, conn,
- &id.u.channel_id);
- if (!channel_entry) {
- /** Resolve channel */
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_channel_by_id_resolve(
- client, conn, &id.u.channel_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
+
+ /* Join the client to channel */
+ if (!silc_client_on_channel(channel, client_entry)) {
+ chu = silc_calloc(1, sizeof(*chu));
+ chu->client = client_entry;
+ chu->channel = channel;
+ silc_hash_table_add(channel->user_list, client_entry, chu);
+ silc_hash_table_add(client_entry->channels, channel, chu);
}
- entry = channel_entry;
- }
- silc_rwlock_wrlock(channel->internal.lock);
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->internal->ops->notify(client, conn, type, client_entry, channel);
+ break;
- /* Get the channel founder key if it was set */
- tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
- if (tmp) {
- if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
- silc_rwlock_unlock(channel->internal.lock);
+ case SILC_NOTIFY_TYPE_LEAVE:
+ /*
+ * Someone has left a channel. We will remove it from the channel but
+ * we'll keep it in the cache in case we'll need it later.
+ */
+
+ SILC_LOG_DEBUG(("Notify: LEAVE"));
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
goto out;
- }
- if (!channel->founder_key) {
- channel->founder_key = founder_key;
- founder_key = NULL;
- }
- }
- /* Get the cipher */
- cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- /* Get the hmac */
- hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (hmac) {
- unsigned char hash[SILC_HASH_MAXLEN];
- SilcHmac newhmac;
+ /* Find Client entry */
+ client_entry =
+ silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
- if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
- silc_rwlock_unlock(channel->internal.lock);
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
goto out;
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ break;
+
+ /* Remove client from channel */
+ chu = silc_client_on_channel(channel, client_entry);
+ if (chu) {
+ silc_hash_table_del(client_entry->channels, channel);
+ silc_hash_table_del(channel->user_list, client_entry);
+ silc_free(chu);
}
- /* Get HMAC key from the old HMAC context, and update it to the new one */
- tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
- if (tmp) {
- silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
- silc_hmac_set_key(newhmac, hash,
- silc_hash_len(silc_hmac_get_hash(newhmac)));
- if (channel->internal.hmac)
- silc_hmac_free(channel->internal.hmac);
- channel->internal.hmac = newhmac;
- memset(hash, 0, sizeof(hash));
+ /* Some client implementations actually quit network by first doing
+ LEAVE and then immediately SIGNOFF. We'll check for this by doing
+ check for the client after 5 - 34 seconds. If it is not valid after
+ that we'll remove the client from cache. */
+ if (!silc_hash_table_count(client_entry->channels)) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
+ silc_client_notify_check_client, res,
+ (5 + (silc_rng_get_rn16(client->rng) % 29)),
+ 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
- }
-
- /* Get the passphrase if it was set */
- passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
- /* Get user limit */
- tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
- if (tmp && tmp_len == 4)
- SILC_GET32_MSB(channel->user_limit, tmp);
- if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
- channel->user_limit = 0;
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->internal->ops->notify(client, conn, type, client_entry, channel);
+ break;
- /* Save the new mode */
- channel->mode = mode;
+ case SILC_NOTIFY_TYPE_SIGNOFF:
+ /*
+ * Someone left SILC. We'll remove it from all channels and from cache.
+ */
- /* Get the channel public key that was added or removed */
- tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
- if (tmp)
- silc_client_channel_save_public_keys(channel, tmp, tmp_len);
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
- silc_rwlock_unlock(channel->internal.lock);
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Notify application. */
- NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
- passphrase, channel->founder_key, chpks, channel);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- out:
- if (founder_key)
- silc_pkcs_public_key_free(founder_key);
- if (chpks)
- silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
- if (client_entry)
- silc_client_unref_client(client, conn, client_entry);
- if (server)
- silc_client_unref_server(client, conn, server);
- if (channel_entry)
- silc_client_unref_channel(client, conn, channel_entry);
- silc_client_unref_channel(client, conn, channel);
-
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Find Client entry */
+ client_entry =
+ silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
-/***************************** CUMODE_CHANGE ********************************/
+ /* Get signoff message */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
-/* Someone changed a user's mode on a channel */
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type, client_entry, tmp);
-SILC_FSM_STATE(silc_client_notify_cumode_change)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcPacket packet = notify->packet;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL, client_entry2 = NULL;
- SilcChannelEntry channel = NULL, channel_entry = NULL;
- SilcServerEntry server = NULL;
- SilcChannelUser chu;
- void *entry;
- unsigned char *tmp;
- SilcUInt32 tmp_len, mode;
- SilcID id, id2;
+ /* Remove from all channels */
+ silc_client_remove_from_channels(client, conn, client_entry);
- SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
+ /* Remove from cache */
+ silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
- /* Get channel entry */
- if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id)))
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
+ /* Free data */
+ silc_client_del_client_entry(client, conn, client_entry);
+ break;
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
+ case SILC_NOTIFY_TYPE_TOPIC_SET:
+ /*
+ * Someone set the topic on a channel.
+ */
- /* Get target Client ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
- goto out;
+ SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
- /* Find target Client entry */
- client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
- if (!client_entry2 || !client_entry2->internal.valid) {
- /** Resolve client */
- silc_client_unref_client(client, conn, client_entry2);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &id2.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ break;
- /* If target client is not on channel, ignore this notify */
- if (!silc_client_on_channel(channel, client_entry2))
- goto out;
+ /* Get ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+ if (!id)
+ goto out;
- /* Get the mode */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (!tmp)
- goto out;
- SILC_GET32_MSB(mode, tmp);
+ /* Find Client entry */
+ if (id_type == SILC_ID_CLIENT) {
+ /* Find Client entry */
+ client_id = id;
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ }
+ } else if (id_type == SILC_ID_SERVER) {
+ /* Find Server entry */
+ server_id = id;
+ server = silc_client_get_server_by_id(client, conn, server_id);
+ if (!server) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_SERVER, server_id);
+ server = silc_client_add_server(client, conn, NULL, NULL, server_id);
+ if (!server)
+ goto out;
+
+ server->resolve_cmd_ident = conn->cmd_ident;
+ server_id = NULL;
+ goto out;
+ }
- /* Get ID of mode changer */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ /* If entry being resoled, wait for it before processing this notify */
+ if (server->resolve_cmd_ident) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ server->resolve_cmd_ident,
+ silc_client_notify_by_server_pending, res);
+ goto out;
+ }
- if (id.type == SILC_ID_CLIENT) {
- /* Find Client entry */
- client_entry = notify->client_entry;
- if (!client_entry) {
- client_entry = silc_client_get_client(client, conn, &id.u.client_id);
- if (!client_entry || !client_entry->internal.valid) {
- /** Resolve client */
- notify->channel = channel;
- notify->client_entry = client_entry;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
+ /* Save the pointer to the client_entry pointer */
+ client_entry = (SilcClientEntry)server;
+ } else {
+ /* Find Channel entry */
+ silc_free(channel_id);
+ channel_id = id;
+ client_entry = (SilcClientEntry)
+ silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CHANNEL, channel_id);
+ goto out;
}
}
- /* If client is not on channel, ignore this notify */
- if (!silc_client_on_channel(channel, client_entry))
+ /* Get topic */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
goto out;
- entry = client_entry;
- } else if (id.type == SILC_ID_SERVER) {
- /* Find Server entry */
- server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
- if (!server) {
- /** Resolve server */
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_server_by_id_resolve(
- client, conn, &id.u.server_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
- entry = server;
- } else {
- /* Find Channel entry */
- channel_entry = silc_client_get_channel_by_id(client, conn,
- &id.u.channel_id);
- if (!channel_entry) {
- /** Resolve channel */
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_channel_by_id_resolve(
- client, conn, &id.u.channel_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
+ /* If information is being resolved for this channel, wait for it */
+ if (channel->resolve_cmd_ident) {
+ silc_client_channel_wait(client, conn, channel, packet);
+ goto out;
}
- entry = channel_entry;
- }
-
- /* Save the mode */
- silc_rwlock_wrlock(channel->internal.lock);
- chu = silc_client_on_channel(channel, client_entry2);
- if (chu)
- chu->mode = mode;
- silc_rwlock_unlock(channel->internal.lock);
- /* Notify application. */
- NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
+ if (tmp) {
+ silc_free(channel->topic);
+ channel->topic = silc_memdup(tmp, strlen(tmp));
+ }
- out:
- silc_client_unref_client(client, conn, client_entry2);
- if (client_entry)
- silc_client_unref_client(client, conn, client_entry);
- if (server)
- silc_client_unref_server(client, conn, server);
- if (channel_entry)
- silc_client_unref_channel(client, conn, channel_entry);
- silc_client_unref_channel(client, conn, channel);
-
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->internal->ops->notify(client, conn, type, id_type,
+ client_entry, tmp, channel);
-/********************************* MOTD *************************************/
+ break;
-/* Received Message of the day */
+ case SILC_NOTIFY_TYPE_NICK_CHANGE:
+ /*
+ * Someone changed their nickname. If we don't have entry for the new
+ * ID we will query it and return here after it's done. After we've
+ * returned we fetch the old entry and free it and notify the
+ * application.
+ */
+
+ SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
+
+ /* Get old Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
-SILC_FSM_STATE(silc_client_notify_motd)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- unsigned char *tmp;
- SilcUInt32 tmp_len;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- SILC_LOG_DEBUG(("Notify: MOTD"));
+ /* Ignore my ID */
+ if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
+ break;
- /* Get motd */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp)
- goto out;
+ /* Find old Client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
+ silc_free(client_id);
+ client_id = NULL;
+
+ /* Wait for resolving if necessary */
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending, res);
+ goto out;
+ }
- /* Notify application */
- NOTIFY(client, conn, type, tmp);
+ client_entry->valid = FALSE;
- out:
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Get new Client ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
-/**************************** CHANNEL CHANGE ********************************/
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
-/* Router has enforced a new ID to a channel, change it */
+ /* Take the nickname */
+ tmp = silc_argument_get_arg_type(args, 3, NULL);
+ if (!tmp)
+ goto out;
-SILC_FSM_STATE(silc_client_notify_channel_change)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcChannelEntry channel = NULL;
- SilcID id;
-
- SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
-
- /* Get the old ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ /* Check whether nickname changed at all. It is possible that nick
+ change notify is received but nickname didn't change, only the
+ ID changes. Check whether the hashes in the Client ID match, if
+ they do nickname didn't change. */
+ if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
+ silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
+ /* Nickname didn't change. Update only Client ID. */
+
+ /* Normalize nickname */
+ tmp = silc_identifier_check(tmp, strlen(tmp),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!tmp)
+ goto out;
+
+ silc_idcache_del_by_context(conn->internal->client_cache,
+ client_entry);
+ silc_free(client_entry->id);
+ client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
+ silc_idcache_add(conn->internal->client_cache, tmp,
+ client_entry->id, client_entry, 0, NULL);
+
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type,
+ client_entry, client_entry);
+ break;
+ }
- /* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
+ /* Create new client entry, and save all old information with the
+ new nickname and client ID */
+ client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
+ client_entry->realname,
+ silc_id_dup(client_id,
+ SILC_ID_CLIENT), 0);
+ if (!client_entry2)
+ goto out;
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
+ if (client_entry->server)
+ client_entry2->server = strdup(client_entry->server);
+ if (client_entry->username)
+ client_entry2->username = strdup(client_entry->username);
+ if (client_entry->hostname)
+ client_entry2->hostname = strdup(client_entry->hostname);
+ client_entry2->fingerprint = client_entry->fingerprint;
+ client_entry2->fingerprint_len = client_entry->fingerprint_len;
+ client_entry->fingerprint = NULL;
+ client_entry->fingerprint_len = 0;
+ silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
+ client_entry->mode);
+
+ /* Remove the old from cache */
+ silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
+
+ /* Replace old ID entry with new one on all channels. */
+ silc_client_replace_from_channels(client, conn, client_entry,
+ client_entry2);
+
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type,
+ client_entry, client_entry2);
+
+ /* Free old client entry */
+ silc_client_del_client_entry(client, conn, client_entry);
- /* Get the new ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ break;
- /* Replace the Channel ID */
- if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
- goto out;
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ {
+ /*
+ * Someone changed a channel mode
+ */
+ char *passphrase, *cipher, *hmac;
+ SilcPublicKey founder_key = NULL;
+ SilcBufferStruct chpks;
+
+ SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ goto out;
+
+ /* Get ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+ if (!id)
+ goto out;
+
+ /* Find Client entry */
+ if (id_type == SILC_ID_CLIENT) {
+ /* Find Client entry */
+ client_id = id;
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ }
+
+ if (!client_entry->nickname) {
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to existing resolving */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Do new resolving */
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ client_entry->resolve_cmd_ident = conn->cmd_ident;
+ goto out;
+ }
+ } else if (id_type == SILC_ID_SERVER) {
+ /* Find Server entry */
+ server_id = id;
+ server = silc_client_get_server_by_id(client, conn, server_id);
+ if (!server) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_SERVER, server_id);
+ server = silc_client_add_server(client, conn, NULL, NULL, server_id);
+ if (!server)
+ goto out;
+
+ server->resolve_cmd_ident = conn->cmd_ident;
+ server_id = NULL;
+ goto out;
+ }
+
+ /* If entry being resoled, wait for it before processing this notify */
+ if (server->resolve_cmd_ident) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ server->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Save the pointer to the client_entry pointer */
+ client_entry = (SilcClientEntry)server;
+ } else {
+ /* Find Channel entry */
+ silc_free(channel_id);
+ channel_id = id;
+ client_entry = (SilcClientEntry)
+ silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CHANNEL, channel_id);
+ goto out;
+ }
+ }
- /* Notify application */
- NOTIFY(client, conn, type, channel, channel);
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
- out:
- /** Notify processed */
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ SILC_GET32_MSB(mode, tmp);
-/******************************** KICKED ************************************/
+ /* If information is being resolved for this channel, wait for it */
+ if (channel->resolve_cmd_ident) {
+ silc_client_channel_wait(client, conn, channel, packet);
+ goto out;
+ }
-/* Some client was kicked from a channel */
+ /* Save the new mode */
+ channel->mode = mode;
-SILC_FSM_STATE(silc_client_notify_kicked)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcPacket packet = notify->packet;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry, client_entry2;
- SilcChannelEntry channel = NULL;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
- SilcID id;
+ /* Get the cipher */
+ cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
- SILC_LOG_DEBUG(("Notify: KICKED"));
+ /* Get the hmac */
+ hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (hmac) {
+ unsigned char hash[SILC_HASH_MAXLEN];
- /* Get channel entry */
- if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
- &id.u.channel_id, sizeof(id.u.channel_id)))
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel)
- goto out;
+ if (channel->hmac)
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
+ goto out;
- /* If channel is being resolved handle notify after resolving */
- if (channel->internal.resolve_cmd_ident) {
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_command_pending(
- conn, SILC_COMMAND_NONE,
- channel->internal.resolve_cmd_ident,
- silc_client_notify_wait_continue,
- notify));
- /* NOT REACHED */
- }
+ silc_hash_make(silc_hmac_get_hash(channel->hmac),
+ channel->key, channel->key_len / 8,
+ hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+ memset(hash, 0, sizeof(hash));
+ }
- /* Get the kicked Client ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ /* Get the passphrase if it was set */
+ passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
- /* Find client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry)
- goto out;
+ /* Get the channel founder key if it was set */
+ tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+ if (tmp) {
+ if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
+ founder_key = NULL;
+ }
- /* Get kicker's Client ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ /* Get user limit */
+ tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
+ if (tmp && tmp_len == 4)
+ SILC_GET32_MSB(channel->user_limit, tmp);
+ if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
+ channel->user_limit = 0;
+
+ /* Get the channel public key that was added or removed */
+ tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+ if (tmp)
+ silc_buffer_set(&chpks, tmp, tmp_len);
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->internal->ops->notify(client, conn, type, id_type,
+ client_entry, mode, cipher, hmac,
+ passphrase, founder_key,
+ tmp ? &chpks : NULL, channel);
+
+ if (founder_key)
+ silc_pkcs_public_key_free(founder_key);
+ }
+ break;
- /* Find kicker's client entry and if not found resolve it */
- client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry2 || !client_entry2->internal.valid) {
- /** Resolve client */
- silc_client_unref_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry2);
- notify->channel = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ /*
+ * Someone changed user's mode on a channel
+ */
- /* Get comment */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
- /* Remove kicked client from channel */
- if (client_entry != conn->local_entry) {
- if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
goto out;
- }
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ break;
- /* Notify application. */
- NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
+ /* Get ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+ if (!id)
+ goto out;
- /* If I was kicked from channel, remove the channel */
- if (client_entry == conn->local_entry) {
- if (conn->current_channel == channel)
- conn->current_channel = NULL;
- silc_client_empty_channel(client, conn, channel);
- silc_client_del_channel(client, conn, channel);
- }
+ /* Find Client entry */
+ if (id_type == SILC_ID_CLIENT) {
+ /* Find Client entry */
+ client_id = id;
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ }
- silc_client_unref_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry2);
+ if (!client_entry->nickname) {
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to existing resolving */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Do new resolving */
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ client_entry->resolve_cmd_ident = conn->cmd_ident;
+ goto out;
+ }
+ } else if (id_type == SILC_ID_SERVER) {
+ /* Find Server entry */
+ server_id = id;
+ server = silc_client_get_server_by_id(client, conn, server_id);
+ if (!server) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_SERVER, server_id);
+ server = silc_client_add_server(client, conn, NULL, NULL, server_id);
+ if (!server)
+ goto out;
+
+ server->resolve_cmd_ident = conn->cmd_ident;
+ server_id = NULL;
+ goto out;
+ }
- out:
- /** Notify processed */
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* If entry being resoled, wait for it before processing this notify */
+ if (server->resolve_cmd_ident) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ server->resolve_cmd_ident,
+ silc_client_notify_by_server_pending, res);
+ goto out;
+ }
-/******************************** KILLED ************************************/
+ /* Save the pointer to the client_entry pointer */
+ client_entry = (SilcClientEntry)server;
+ } else {
+ /* Find Channel entry */
+ silc_free(channel_id);
+ channel_id = id;
+ client_entry = (SilcClientEntry)
+ silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CHANNEL, channel_id);
+ goto out;
+ }
+ }
-/* Some client was killed from the network */
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
-SILC_FSM_STATE(silc_client_notify_killed)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL, client_entry2 = NULL;
- SilcChannelEntry channel_entry = NULL;
- SilcServerEntry server = NULL;
- void *entry;
- char *comment;
- SilcUInt32 comment_len;
- SilcID id;
-
- SILC_LOG_DEBUG(("Notify: KILLED"));
-
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ SILC_GET32_MSB(mode, tmp);
- /* Find Client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry)
- goto out;
+ /* If information is being resolved for this channel, wait for it */
+ if (channel->resolve_cmd_ident) {
+ silc_client_channel_wait(client, conn, channel, packet);
+ goto out;
+ }
- /* Get comment */
- comment = silc_argument_get_arg_type(args, 2, &comment_len);
+ /* Get target Client ID */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get killer's ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ silc_free(client_id);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- if (id.type == SILC_ID_CLIENT) {
- /* Find Client entry */
- client_entry2 = silc_client_get_client_by_id(client, conn,
- &id.u.client_id);
- if (!client_entry2 || !client_entry2->internal.valid) {
- /** Resolve client */
- silc_client_unref_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry2);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
- entry = client_entry2;
- } else if (id.type == SILC_ID_SERVER) {
- /* Find Server entry */
- server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
- if (!server) {
- /** Resolve server */
- SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
- client, conn, &id.u.server_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
- entry = server;
- } else {
- /* Find Channel entry */
- channel_entry = silc_client_get_channel_by_id(client, conn,
- &id.u.channel_id);
- if (!channel_entry) {
- /** Resolve channel */
- SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
- client, conn, &id.u.channel_id,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
+ /* Find target Client entry */
+ client_entry2 =
+ silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry2) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
}
- entry = channel_entry;
- }
- /* Notify application. */
- NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
-
- /* Delete the killed client */
- if (client_entry != conn->local_entry) {
- silc_client_remove_from_channels(client, conn, client_entry);
- client_entry->internal.valid = FALSE;
- silc_client_del_client(client, conn, client_entry);
- }
-
- out:
- silc_client_unref_client(client, conn, client_entry);
- if (client_entry2)
- silc_client_unref_client(client, conn, client_entry2);
- if (server)
- silc_client_unref_server(client, conn, server);
- if (channel_entry)
- silc_client_unref_channel(client, conn, channel_entry);
-
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Save the mode */
+ chu = silc_client_on_channel(channel, client_entry2);
+ if (chu)
+ chu->mode = mode;
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->internal->ops->notify(client, conn, type,
+ id_type, client_entry, mode,
+ client_entry2, channel);
+ break;
-/**************************** SERVER SIGNOFF ********************************/
+ case SILC_NOTIFY_TYPE_MOTD:
+ /*
+ * Received Message of the day
+ */
-/* Some server quit SILC network. Remove its clients from channels. */
+ SILC_LOG_DEBUG(("Notify: MOTD"));
-SILC_FSM_STATE(silc_client_notify_server_signoff)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry;
- SilcServerEntry server_entry = NULL;
- SilcDList clients;
- SilcID id;
- int i;
+ /* Get motd */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
- SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type, tmp);
+ break;
- clients = silc_dlist_init();
- if (!clients)
- goto out;
+ case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+ /*
+ * Router has enforced a new ID to a channel. Let's change the old
+ * ID to the one provided here.
+ */
- /* Get server ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
- /* Get server, in case we have it cached */
- server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
+ /* Get the old ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!channel_id)
+ goto out;
- for (i = 1; i < silc_argument_get_arg_num(args); i++) {
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
+ /* Get the channel entry */
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
goto out;
- /* Get the client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry && client_entry->internal.valid)
- silc_dlist_add(clients, client_entry);
- }
+ silc_free(channel_id);
+ channel_id = NULL;
- /* Notify application. */
- NOTIFY(client, conn, type, server_entry, clients);
+ /* Get the new ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!channel_id)
+ goto out;
- /* Delete the clients */
- silc_dlist_start(clients);
- while ((client_entry = silc_dlist_get(clients))) {
- silc_client_remove_from_channels(client, conn, client_entry);
- client_entry->internal.valid = FALSE;
- silc_client_del_client(client, conn, client_entry);
- }
+ /* Replace the Channel ID */
+ if (silc_client_replace_channel_id(client, conn, channel, channel_id))
+ channel_id = NULL;
- out:
- /** Notify processed */
- silc_client_unref_server(client, conn, server_entry);
- silc_client_list_free(client, conn, clients);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type, channel, channel);
+ break;
-/******************************** ERROR *************************************/
+ case SILC_NOTIFY_TYPE_KICKED:
+ /*
+ * A client (maybe me) was kicked from a channel
+ */
-/* Some error occurred */
+ SILC_LOG_DEBUG(("Notify: KICKED"));
-SILC_FSM_STATE(silc_client_notify_error)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
- SilcID id;
- SilcStatus error;
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get error */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp && tmp_len != 1)
- goto out;
- error = (SilcStatus)tmp[0];
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
+ /* Find Client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
- /* Handle the error */
- if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
goto out;
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry) {
- silc_client_remove_from_channels(client, conn, client_entry);
- silc_client_del_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry);
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ break;
+
+ /* From protocol version 1.1 we get the kicker's client ID as well */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ silc_free(client_id);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+
+ /* Find kicker's client entry and if not found resolve it */
+ client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry2) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ } else {
+ if (client_entry2 != conn->local_entry)
+ silc_client_nickname_format(client, conn, client_entry2);
+ }
}
- }
- /* Notify application. */
- NOTIFY(client, conn, type, error);
+ /* Get comment */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- out:
- /** Notify processed */
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
-}
+ /* Remove kicked client from channel */
+ if (client_entry != conn->local_entry) {
+ chu = silc_client_on_channel(channel, client_entry);
+ if (chu) {
+ silc_hash_table_del(client_entry->channels, channel);
+ silc_hash_table_del(channel->user_list, client_entry);
+ silc_free(chu);
+ }
+ }
-/******************************** WATCH *************************************/
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->internal->ops->notify(client, conn, type, client_entry, tmp,
+ client_entry2, channel);
+
+ /* Remove kicked client (us) from channel */
+ if (client_entry == conn->local_entry) {
+ /* If I was kicked from channel, remove the channel */
+ if (conn->current_channel == channel)
+ conn->current_channel = NULL;
+ silc_client_del_channel(client, conn, channel);
+ } else {
+ if (!silc_hash_table_count(client_entry->channels)) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
+ silc_client_notify_check_client, res,
+ (5 + (silc_rng_get_rn16(client->rng) % 529)),
+ 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ }
+ }
+ break;
-/* Received notify about some client we are watching */
+ case SILC_NOTIFY_TYPE_KILLED:
+ {
+ /*
+ * A client (maybe me) was killed from the network.
+ */
+ char *comment;
+ SilcUInt32 comment_len;
+
+ SILC_LOG_DEBUG(("Notify: KILLED"));
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+
+ /* Find Client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
+
+ /* Get comment */
+ comment = silc_argument_get_arg_type(args, 2, &comment_len);
+
+ /* From protocol version 1.1 we get killer's client ID as well */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ silc_free(client_id);
+ client_id = NULL;
+ id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+ if (!id)
+ goto out;
+
+ /* Find Client entry */
+ if (id_type == SILC_ID_CLIENT) {
+ /* Find Client entry */
+ client_id = id;
+ client_entry2 = silc_client_get_client_by_id(client, conn,
+ client_id);
+ if (!client_entry) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ }
+ } else if (id_type == SILC_ID_SERVER) {
+ /* Find Server entry */
+ server_id = id;
+ server = silc_client_get_server_by_id(client, conn, server_id);
+ if (!server) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_SERVER, server_id);
+ server = silc_client_add_server(client, conn, NULL, NULL,
+ server_id);
+ if (!server)
+ goto out;
+
+ server->resolve_cmd_ident = conn->cmd_ident;
+ server_id = NULL;
+ goto out;
+ }
+
+ if (server->resolve_cmd_ident) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ server->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Save the pointer to the client_entry pointer */
+ client_entry2 = (SilcClientEntry)server;
+ } else {
+ /* Find Channel entry */
+ channel_id = id;
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CHANNEL, channel_id);
+ goto out;
+ }
+
+ /* Save the pointer to the client_entry pointer */
+ client_entry2 = (SilcClientEntry)channel;
+ silc_free(channel_id);
+ channel_id = NULL;
+ }
+ }
-SILC_FSM_STATE(silc_client_notify_watch)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientNotify notify = state_context;
- SilcNotifyPayload payload = notify->payload;
- SilcNotifyType type = silc_notify_get_type(payload);
- SilcArgumentPayload args = silc_notify_get_args(payload);
- SilcClientEntry client_entry = NULL;
- SilcNotifyType ntype = 0;
- unsigned char *pk, *tmp;
- SilcUInt32 mode, pk_len, tmp_len;
- SilcPublicKey public_key = NULL;
- SilcID id;
+ /* Notify application. */
+ client->internal->ops->notify(client, conn, type, client_entry,
+ comment, id_type, client_entry2);
- SILC_LOG_DEBUG(("Notify: WATCH"));
+ if (client_entry != conn->local_entry)
+ /* Remove the client from all channels and free it */
+ silc_client_del_client(client, conn, client_entry);
+ }
+ break;
- /* Get sender Client ID */
- if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
- goto out;
+ case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+ {
+ /*
+ * A server quit the SILC network and some clients must be removed
+ * from channels as they quit as well.
+ */
+ SilcClientEntry *clients = NULL;
+ SilcUInt32 clients_count = 0;
+ int i;
+
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
+ for (i = 1; i < silc_argument_get_arg_num(args); i++) {
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
+ if (tmp) {
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+
+ /* Get the client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (client_entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count] = client_entry;
+ clients_count++;
+ }
+ silc_free(client_id);
+ }
+ }
+ client_id = NULL;
+
+ /* Notify application. We don't keep server entries so the server
+ entry is returned as NULL. The client's are returned as array
+ of SilcClientEntry pointers. */
+ client->internal->ops->notify(client, conn, type, NULL,
+ clients, clients_count);
+
+ for (i = 0; i < clients_count; i++) {
+ /* Remove client from all channels */
+ client_entry = clients[i];
+ if (client_entry == conn->local_entry)
+ continue;
+
+ /* Remove the client from all channels and free it */
+ silc_client_del_client(client, conn, client_entry);
+ }
+ silc_free(clients);
- /* Find client entry and if not found resolve it */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry || !client_entry->internal.valid) {
- /** Resolve client */
- silc_client_unref_client(client, conn, client_entry);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &id.u.client_id, NULL,
- silc_client_notify_resolved,
- notify));
- /* NOT REACHED */
- }
+ }
+ break;
- /* Get user mode */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (!tmp || tmp_len != 4)
- goto out;
- SILC_GET32_MSB(mode, tmp);
+ case SILC_NOTIFY_TYPE_ERROR:
+ {
+ /*
+ * Some has occurred and server is notifying us about it.
+ */
+ SilcStatus error;
+
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp && tmp_len != 1)
+ goto out;
+ error = (SilcStatus)tmp[0];
+
+ SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
+
+ if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp) {
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+ client_entry = silc_client_get_client_by_id(client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(client, conn, client_entry);
+ }
+ }
- /* Get notify type */
- tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (tmp && tmp_len != 2)
- goto out;
- if (tmp)
- SILC_GET16_MSB(ntype, tmp);
+ /* Notify application. */
+ client->internal->ops->notify(client, conn, type, error);
+ }
+ break;
- /* Get nickname */
- tmp = silc_argument_get_arg_type(args, 2, NULL);
- if (tmp) {
- char *tmp_nick = NULL;
+ case SILC_NOTIFY_TYPE_WATCH:
+ {
+ /*
+ * Received notify about some client we are watching
+ */
+ SilcNotifyType notify = 0;
+ bool del_client = FALSE;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+ SilcPublicKey public_key = NULL;
+
+ SILC_LOG_DEBUG(("Notify: WATCH"));
+
+ /* Get sender Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+
+ /* Find Client entry and if not found query it */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ }
- silc_client_nickname_parse(client, conn, client_entry->nickname,
- &tmp_nick);
+ /* Get user mode */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp || tmp_len != 4)
+ goto out;
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get notify type */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp && tmp_len != 2)
+ goto out;
+ if (tmp)
+ SILC_GET16_MSB(notify, tmp);
+
+ /* Get nickname */
+ tmp = silc_argument_get_arg_type(args, 2, NULL);
+ if (tmp) {
+ char *tmp_nick = NULL;
+
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(client_entry->nickname,
+ &tmp_nick);
+ else
+ tmp_nick = strdup(tmp);
+
+ /* If same nick, the client was new to us and has become "present"
+ to network. Send NULL as nick to application. */
+ if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
+ tmp = NULL;
+
+ silc_free(tmp_nick);
+ }
- /* If same nick, the client was new to us and has become "present"
- to network. Send NULL as nick to application. */
- if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
- tmp = NULL;
+ /* Get public key, if present */
+ pk = silc_argument_get_arg_type(args, 5, &pk_len);
+ if (pk && !client_entry->public_key) {
+ if (silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key)) {
+ client_entry->public_key = public_key;
+ public_key = NULL;
+ }
+ }
- silc_free(tmp_nick);
- }
+ /* Notify application. */
+ client->internal->ops->notify(client, conn, type, client_entry,
+ tmp, mode, notify,
+ client_entry->public_key);
+
+ client_entry->mode = mode;
+
+ /* If nickname was changed, remove the client entry unless the
+ client is on some channel */
+ if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
+ !silc_hash_table_count(client_entry->channels))
+ del_client = TRUE;
+ else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
+ notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
+ notify == SILC_NOTIFY_TYPE_KILLED)
+ del_client = TRUE;
+
+ if (del_client) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ res->packet = client_id;
+ client_id = NULL;
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
+ silc_client_notify_del_client_cb, res,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ }
- /* Get public key, if present */
- pk = silc_argument_get_arg_type(args, 5, &pk_len);
- if (pk && !client_entry->public_key) {
- if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
- client_entry->public_key = public_key;
- public_key = NULL;
+ silc_pkcs_public_key_free(public_key);
}
- }
-
- /* Notify application. */
- NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
- client_entry->public_key);
-
- client_entry->mode = mode;
+ break;
- /* Remove client that left the network. */
- if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
- ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
- ntype == SILC_NOTIFY_TYPE_KILLED) {
- silc_client_remove_from_channels(client, conn, client_entry);
- client_entry->internal.valid = FALSE;
- silc_client_del_client(client, conn, client_entry);
+ default:
+ break;
}
- if (public_key)
- silc_pkcs_public_key_free(public_key);
-
out:
- /** Notify processed */
- silc_client_unref_client(client, conn, client_entry);
- silc_fsm_next(fsm, silc_client_notify_processed);
- return SILC_FSM_CONTINUE;
+ silc_notify_payload_free(payload);
+ silc_free(client_id);
+ silc_free(channel_id);
+ silc_free(server_id);
}
+++ /dev/null
-/*
-
- client_notify.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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 CLIENT_NOTIFY_H
-#define CLIENT_NOTIFY_H
-
-SILC_FSM_STATE(silc_client_notify);
-SILC_FSM_STATE(silc_client_notify_processed);
-SILC_FSM_STATE(silc_client_notify_wait);
-SILC_FSM_STATE(silc_client_notify_none);
-SILC_FSM_STATE(silc_client_notify_invite);
-SILC_FSM_STATE(silc_client_notify_join);
-SILC_FSM_STATE(silc_client_notify_leave);
-SILC_FSM_STATE(silc_client_notify_signoff);
-SILC_FSM_STATE(silc_client_notify_topic_set);
-SILC_FSM_STATE(silc_client_notify_nick_change);
-SILC_FSM_STATE(silc_client_notify_cmode_change);
-SILC_FSM_STATE(silc_client_notify_cumode_change);
-SILC_FSM_STATE(silc_client_notify_motd);
-SILC_FSM_STATE(silc_client_notify_channel_change);
-SILC_FSM_STATE(silc_client_notify_kicked);
-SILC_FSM_STATE(silc_client_notify_killed);
-SILC_FSM_STATE(silc_client_notify_server_signoff);
-SILC_FSM_STATE(silc_client_notify_error);
-SILC_FSM_STATE(silc_client_notify_watch);
-
-#endif /* CLIENT_NOTIFY_H */
message to a specific connection. `conn', however, may be NULL.
The `type' indicates the type of the message sent by the library.
The application can for example filter the message according the
- type. The variable argument list is arguments to the formatted
- message that `msg' may be. */
-void silc_say(SilcClient client, SilcClientConnection conn,
- SilcClientMessageType type, char *msg, ...);
+ type. */
+
+static void
+silc_say(SilcClient client, SilcClientConnection conn,
+ SilcClientMessageType type, char *msg, ...)
+{
+
+}
+
/* Message for a channel. The `sender' is the sender of the message
The `channel' is the channel. The `message' is the message. Note
that `message' maybe NULL. The `flags' indicates message flags
and it is used to determine how the message can be interpreted
(like it may tell the message is multimedia message). */
-void silc_channel_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessagePayload payload,
- SilcChannelPrivateKey key, SilcMessageFlags flags,
- const unsigned char *message,
- SilcUInt32 message_len);
+
+static void
+silc_channel_message(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry sender, SilcChannelEntry channel,
+ SilcMessagePayload payload, SilcChannelPrivateKey key,
+ SilcMessageFlags flags, const unsigned char *message,
+ SilcUInt32 message_len)
+{
+
+}
+
/* Private message to the client. The `sender' is the sender of the
message. The message is `message'and maybe NULL. The `flags'
indicates message flags and it is used to determine how the message
can be interpreted (like it may tell the message is multimedia
message). */
-void silc_private_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcMessagePayload payload,
- SilcMessageFlags flags, const unsigned char *message,
- SilcUInt32 message_len);
+
+static void
+silc_private_message(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry sender, SilcMessagePayload payload,
+ SilcMessageFlags flags, const unsigned char *message,
+ SilcUInt32 message_len)
+{
+
+}
+
/* Notify message to the client. The notify arguments are sent in the
same order as servers sends them. The arguments are same as received
for channel the channel entry is sent to application (even if server
does not send it because client library gets the channel entry from
the Channel ID in the packet's header). */
-void silc_notify(SilcClient client, SilcClientConnection conn,
- SilcNotifyType type, ...);
-
-/* Command handler. This function is called always after application has
- called a command. It will be called to indicate that the command
- was processed. It will also be called if error occurs while processing
- the command. The `success' indicates whether the command was sent
- or if error occurred. The `status' indicates the actual error.
- The `argc' and `argv' are the command line arguments sent to the
- command by application. Note that, this is not reply to the command
- from server, this is merely and indication to application that the
- command was processed. */
-void silc_command(SilcClient client, SilcClientConnection conn,
- SilcBool success, SilcCommand command, SilcStatus status,
- SilcUInt32 argc, unsigned char **argv);
+
+static void
+silc_notify(SilcClient client, SilcClientConnection conn,
+ SilcNotifyType type, ...)
+{
+
+}
+
+
+/* Command handler. This function is called always in the command function.
+ If error occurs it will be called as well. `conn' is the associated
+ client connection. `cmd_context' is the command context that was
+ originally sent to the command. `success' is FALSE if error occurred
+ during command. `command' is the command being processed. It must be
+ noted that this is not reply from server. This is merely called just
+ after application has called the command. Just to tell application
+ that the command really was processed. */
+
+static void
+silc_command(SilcClient client, SilcClientConnection conn,
+ SilcClientCommandContext cmd_context, bool success,
+ SilcCommand command, SilcStatus status)
+{
+
+}
+
/* Command reply handler. This function is called always in the command reply
function. If error occurs it will be called as well. Normal scenario
the command reply status server returned. The `command' is the command
reply being processed. The function has variable argument list and each
command defines the number and type of arguments it passes to the
- application (on error they are not sent).
+ application (on error they are not sent). */
+
+static void
+silc_command_reply(SilcClient client, SilcClientConnection conn,
+ SilcCommandPayload cmd_payload, bool success,
+ SilcCommand command, SilcStatus status, ...)
+{
+
+}
+
+
+/* Called to indicate that connection was either successfully established
+ or connecting failed. This is also the first time application receives
+ the SilcClientConnection objecet which it should save somewhere.
+ If the `success' is FALSE the application must always call the function
+ silc_client_close_connection. */
+
+static void
+silc_connected(SilcClient client, SilcClientConnection conn,
+ SilcClientConnectionStatus status)
+{
+
+}
+
+
+/* Called to indicate that connection was disconnected to the server.
+ The `status' may tell the reason of the disconnection, and if the
+ `message' is non-NULL it may include the disconnection message
+ received from server. */
+
+static void
+silc_disconnected(SilcClient client, SilcClientConnection conn,
+ SilcStatus status, const char *message)
+{
+
+}
- The arguments are sent in the same order as servers sends them. The
- arguments are same as received from the server except for ID's. If
- ID is received application receives the corresponding entry to the
- ID. For example, if Client ID is receives application receives
- SilcClientEntry. */
-void silc_command_reply(SilcClient client, SilcClientConnection conn,
- SilcCommand command, SilcStatus status,
- SilcStatus error, va_list ap);
/* Find authentication method and authentication data by hostname and
- port. The hostname may be IP address as well. The `auth_method' is
- the authentication method the remote connection requires. It is
- however possible that remote accepts also some other authentication
- method. Application should use the method that may have been
- configured for this connection. If none has been configured it should
- use the required `auth_method'. If the `auth_method' is
- SILC_AUTH_NONE, server does not require any authentication or the
- required authentication method is not known. The `completion'
- callback must be called to deliver the chosen authentication method
- and data. The `conn' may be NULL. */
-void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, SilcUInt16 port,
- SilcAuthMethod auth_method,
- SilcGetAuthMeth completion, void *context);
+ port. The hostname may be IP address as well. When the authentication
+ method has been resolved the `completion' callback with the found
+ authentication method and authentication data is called. The `conn'
+ may be NULL. */
+
+static void
+silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+ char *hostname, SilcUInt16 port, SilcGetAuthMeth completion,
+ void *context)
+{
+
+}
+
/* Verifies received public key. The `conn_type' indicates which entity
- (server or client) has sent the public key. If user decides to trust
- the key the application may save the key as trusted public key for
- later use. The `completion' must be called after the public key has
- been verified. */
-void silc_verify_public_key(SilcClient client, SilcClientConnection conn,
- SilcConnectionType conn_type,
- SilcPublicKey public_key,
- SilcVerifyPublicKey completion, void *context);
+ (server, client etc.) has sent the public key. If user decides to trust
+ the application may save the key as trusted public key for later
+ use. The `completion' must be called after the public key has been
+ verified. */
+
+static void
+silc_verify_public_key(SilcClient client, SilcClientConnection conn,
+ SilcSocketType conn_type, unsigned char *pk,
+ SilcUInt32 pk_len, SilcSKEPKType pk_type,
+ SilcVerifyPublicKey completion, void *context)
+{
+
+}
+
/* Ask (interact, that is) a passphrase from user. The passphrase is
returned to the library by calling the `completion' callback with
the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
if not then the library will attempt to encode. */
-void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
- SilcAskPassphrase completion, void *context);
-
-/* Called to indicate that incoming key agreement request has been
- received. If the application wants to perform key agreement it may
- call silc_client_perform_key_agreement to initiate key agreementn or
- silc_client_send_key_agreement to provide connection point to the
- remote client in case the `hostname' is NULL. If key agreement is
- not desired this request can be ignored. The `protocol' is either
- value 0 for TCP or value 1 for UDP. */
-void silc_key_agreement(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *hostname, SilcUInt16 protocol,
- SilcUInt16 port);
+
+static void
+silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
+ SilcAskPassphrase completion, void *context)
+{
+
+}
+
+
+/* Notifies application that failure packet was received. This is called
+ if there is some protocol active in the client. The `protocol' is the
+ protocol context. The `failure' is opaque pointer to the failure
+ indication. Note, that the `failure' is protocol dependant and
+ application must explicitly cast it to correct type. Usually `failure'
+ is 32 bit failure type (see protocol specs for all protocol failure
+ types). */
+
+static void
+silc_failure(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure)
+{
+
+}
+
+
+/* Asks whether the user would like to perform the key agreement protocol.
+ This is called after we have received an key agreement packet or an
+ reply to our key agreement packet. This returns TRUE if the user wants
+ the library to perform the key agreement protocol and FALSE if it is not
+ desired (application may start it later by calling the function
+ silc_client_perform_key_agreement). If TRUE is returned also the
+ `completion' and `context' arguments must be set by the application. */
+
+static bool
+silc_key_agreement(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry, const char *hostname,
+ SilcUInt16 port, SilcKeyAgreementCallback *completion,
+ void **context)
+{
+
+}
+
/* Notifies application that file transfer protocol session is being
requested by the remote client indicated by the `client_entry' from
session and it can be used to either accept or reject the file
transfer request, by calling the silc_client_file_receive or
silc_client_file_close, respectively. */
-void silc_ftp(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry, SilcUInt32 session_id,
- const char *hostname, SilcUInt16 port);
+
+static void
+silc_ftp(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry, SilcUInt32 session_id,
+ const char *hostname, SilcUInt16 port)
+{
+
+}
+
+
+/* Delivers SILC session detachment data indicated by `detach_data' to the
+ application. If application has issued SILC_COMMAND_DETACH command
+ the client session in the SILC network is not quit. The client remains
+ in the network but is detached. The detachment data may be used later
+ to resume the session in the SILC Network. The appliation is
+ responsible of saving the `detach_data', to for example in a file.
+
+ The detachment data can be given as argument to the functions
+ silc_client_connect_to_server, or silc_client_add_connection when
+ creating connection to remote server, inside SilcClientConnectionParams
+ structure. If it is provided the client library will attempt to resume
+ the session in the network. After the connection is created
+ successfully, the application is responsible of setting the user
+ interface for user into the same state it was before detaching (showing
+ same channels, channel modes, etc). It can do this by fetching the
+ information (like joined channels) from the client library. */
+
+static void
+silc_detach(SilcClient client, SilcClientConnection conn,
+ const unsigned char *detach_data, SilcUInt32 detach_data_len)
+{
+
+}
+
/* The SilcClientOperation structure containing the operation functions.
You will give this as an argument to silc_client_alloc function. */
silc_notify,
silc_command,
silc_command_reply,
+ silc_connected,
+ silc_disconnected,
silc_get_auth_method,
silc_verify_public_key,
silc_ask_passphrase,
+ silc_failure,
silc_key_agreement,
- silc_ftp
+ silc_ftp,
+ silc_detach
};
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2004 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
*/
/* $Id$ */
+/* This file includes the private message sending and receiving routines
+ and private message key handling routines. */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Private Message Send ****************************/
+/* Sends private message to remote client. If private message key has
+ not been set with this client then the message will be encrypted using
+ normal session keys. Private messages are special packets in SILC
+ network hence we need this own function for them. This is similiar
+ to silc_client_packet_send_to_channel except that we send private
+ message. The `data' is the private message. If the `force_send' is
+ TRUE the packet is sent immediately. */
-/* Sends private message to remote client. */
-
-SilcBool silc_client_send_private_message(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcMessageFlags flags,
- SilcHash hash,
- unsigned char *data,
- SilcUInt32 data_len)
+bool silc_client_send_private_message(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ SilcMessageFlags flags,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send)
{
+ SilcSocketConnection sock;
SilcBuffer buffer;
- SilcBool ret;
- SilcID sid, rid;
-
- if (silc_unlikely(!client || !conn || !client_entry))
- return FALSE;
- if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
- return FALSE;
- if (silc_unlikely(conn->internal->disconnected))
- return FALSE;
-
+ SilcPacketContext packetdata;
+ const SilcBufferStruct packet;
+ SilcCipher cipher;
+ SilcHmac hmac;
+ int block_len;
+ bool ret = FALSE;
+
+ assert(client && conn && client_entry);
+ sock = conn->sock;
SILC_LOG_DEBUG(("Sending private message"));
- sid.type = SILC_ID_CLIENT;
- sid.u.client_id = conn->local_entry->id;
- rid.type = SILC_ID_CLIENT;
- rid.u.client_id = client_entry->id;
-
/* Encode private message payload */
- buffer =
- silc_message_payload_encode(flags, data, data_len,
- (!client_entry->internal.send_key ? FALSE :
- !client_entry->internal.generated),
- TRUE, client_entry->internal.send_key,
- client_entry->internal.hmac_send,
- client->rng, NULL, conn->private_key,
- hash, &sid, &rid, NULL);
- if (silc_unlikely(!buffer)) {
+ buffer = silc_message_payload_encode(flags, data, data_len,
+ !client_entry->send_key ? FALSE :
+ !client_entry->generated,
+ TRUE, client_entry->send_key,
+ client_entry->hmac_send,
+ client->rng, NULL, client->private_key,
+ client->sha1hash);
+ if (!buffer) {
SILC_LOG_ERROR(("Error encoding private message"));
return FALSE;
}
- /* Send the private message packet */
- ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
- client_entry->internal.send_key ?
- SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
- 0, NULL, SILC_ID_CLIENT, &client_entry->id,
- silc_buffer_datalen(buffer), NULL, NULL);
+ /* If we don't have private message specific key then private messages
+ are just as any normal packet thus call normal packet sending. If
+ the key exist then the encryption process is a bit different and
+ will be done in the rest of this function. */
+ if (!client_entry->send_key) {
+ silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
+ client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+ buffer->data, buffer->len, force_send);
+ ret = TRUE;
+ goto out;
+ }
+
+ /* We have private message specific key */
+
+ /* Get data used in the encryption */
+ cipher = conn->internal->send_key;
+ hmac = conn->internal->hmac_send;
+ block_len = silc_cipher_get_block_len(cipher);
+
+ /* Set the packet context pointers. */
+ data = buffer->data;
+ data_len = buffer->len;
+ packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY;
+ packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
+ packetdata.src_id = conn->local_id_data;
+ packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
+ packetdata.src_id_type = SILC_ID_CLIENT;
+ packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
+ packetdata.dst_id_len = silc_id_get_len(client_entry->id, SILC_ID_CLIENT);
+ packetdata.dst_id_type = SILC_ID_CLIENT;
+ data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len);
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len), block_len, packetdata.padlen);
+
+ /* Create the outgoing packet */
+ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
+ data, data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Error assembling packet"));
+ goto out;
+ }
+
+ /* Encrypt the header and padding of the packet. */
+ silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
+ (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len +
+ packetdata.padlen);
+
+ SILC_LOG_HEXDUMP(("Private message packet, len %d", packet.len),
+ packet.data, packet.len);
+
+ /* Now actually send the packet */
+ silc_client_packet_send_real(client, sock, force_send);
+
+ /* Check for mandatory rekey */
+ if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_rekey_callback, sock, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_free(packetdata.dst_id);
+
+ ret = TRUE;
+
+ out:
silc_buffer_free(buffer);
+
return ret;
}
-/************************* Private Message Receive **************************/
-
-/* Client resolving callback. Continues with the private message processing */
-
-static void silc_client_private_message_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
+static void silc_client_private_message_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
+ void *context)
{
- /* If no client found, ignore the private message, a silent error */
- if (!clients)
- silc_fsm_next(context, silc_client_private_message_error);
+ SilcPacketContext *packet = (SilcPacketContext *)context;
+
+ if (!clients) {
+ silc_packet_context_free(packet);
+ return;
+ }
- /* Continue processing the private message packet */
- SILC_FSM_CALL_CONTINUE(context);
+ silc_client_private_message(client, conn->sock, packet);
+ silc_packet_context_free(packet);
}
-/* Private message received. */
+/* Private message received. This processes the private message and
+ finally displays it on the screen. */
-SILC_FSM_STATE(silc_client_private_message)
+void silc_client_private_message(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcMessagePayload payload = NULL;
- SilcClientID remote_id;
- SilcClientEntry remote_client = NULL;
+ SilcClientID *remote_id = NULL;
+ SilcClientEntry remote_client;
SilcMessageFlags flags;
unsigned char *message;
SilcUInt32 message_len;
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
- SILC_LOG_DEBUG(("Received private message"));
-
- if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
- /** Invalid packet */
- silc_fsm_next(fsm, silc_client_private_message_error);
- return SILC_FSM_CONTINUE;
- }
+ if (packet->src_id_type != SILC_ID_CLIENT)
+ goto out;
- if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
- SILC_ID_CLIENT, &remote_id,
- sizeof(remote_id)))) {
- /** Invalid source ID */
- silc_fsm_next(fsm, silc_client_private_message_error);
- return SILC_FSM_CONTINUE;
- }
+ remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!remote_id)
+ goto out;
/* Check whether we know this client already */
- remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
- if (!remote_client || !remote_client->nickname[0]) {
- /** Resolve client info */
- silc_client_unref_client(client, conn, remote_client);
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &remote_id, NULL,
- silc_client_private_message_resolved,
- fsm));
- /* NOT REACHED */
+ remote_client = silc_client_get_client_by_id(client, conn, remote_id);
+ if (!remote_client || !remote_client->nickname) {
+ if (remote_client) {
+ if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
+ remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+ goto out;
+ }
+ remote_client->status |= SILC_CLIENT_STATUS_RESOLVING;
+ remote_client->resolve_cmd_ident = conn->cmd_ident + 1;
+ }
+
+ /* Resolve the client info */
+ silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
+ silc_client_private_message_cb,
+ silc_packet_context_dup(packet));
+ return;
}
- if (silc_unlikely(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
- !remote_client->internal.receive_key &&
- !remote_client->internal.hmac_receive))
- goto out;
+ cipher = remote_client->receive_key;
+ hmac = remote_client->hmac_receive;
+ if (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY && !cipher && !hmac) {
+ silc_free(remote_id);
+ return;
+ }
/* Parse the payload and decrypt it also if private message key is set */
- payload =
- silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
- TRUE, !remote_client->internal.generated,
- remote_client->internal.receive_key,
- remote_client->internal.hmac_receive,
- packet->src_id, packet->src_id_len,
- packet->dst_id, packet->dst_id_len,
- NULL, FALSE, NULL);
- if (silc_unlikely(!payload))
- goto out;
+ payload = silc_message_payload_parse(packet->buffer->data,
+ packet->buffer->len, TRUE,
+ !remote_client->generated,
+ cipher, hmac);
+ if (!payload) {
+ silc_free(remote_id);
+ return;
+ }
- /* Pass the private message to application */
flags = silc_message_get_flags(payload);
+
+ /* Pass the private message to application */
message = silc_message_get_data(payload, &message_len);
client->internal->ops->private_message(client, conn, remote_client, payload,
flags, message, message_len);
/* See if we are away (gone). If we are away we will reply to the
sender with the set away message. */
- if (conn->internal->away_message &&
+ if (conn->internal->away && conn->internal->away->away &&
!(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
/* If it's me, ignore */
- if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
+ if (SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
goto out;
/* Send the away message */
silc_client_send_private_message(client, conn, remote_client,
SILC_MESSAGE_FLAG_AUTOREPLY |
- SILC_MESSAGE_FLAG_NOREPLY, NULL,
- conn->internal->away_message,
- strlen(conn->internal->away_message));
+ SILC_MESSAGE_FLAG_NOREPLY,
+ conn->internal->away->away,
+ strlen(conn->internal->away->away), TRUE);
}
out:
- /** Packet processed */
- silc_packet_free(packet);
- silc_client_unref_client(client, conn, remote_client);
if (payload)
silc_message_payload_free(payload);
- return SILC_FSM_FINISH;
-}
-
-/* Private message error. */
-
-SILC_FSM_STATE(silc_client_private_message_error)
-{
- SilcPacket packet = state_context;
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
-}
-
-/* Initialize private message waiter for the `conn' connection. */
-
-SilcBool silc_client_private_message_wait_init(SilcClient client,
- SilcClientConnection conn)
-{
- if (conn->internal->prv_waiter)
- return TRUE;
-
- conn->internal->prv_waiter =
- silc_packet_wait_init(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, -1);
- if (!conn->internal->prv_waiter)
- return FALSE;
-
- return TRUE;
-}
-
-/* Uninitializes private message waiter. */
-
-void silc_client_private_message_wait_uninit(SilcClient client,
- SilcClientConnection conn)
-{
- if (!conn->internal->prv_waiter)
- return;
- silc_packet_wait_uninit(conn->internal->prv_waiter, conn->stream);
- conn->internal->prv_waiter = NULL;
-}
-
-/* Blocks the calling process or thread until private message has been
- received from the specified client. */
-
-SilcBool silc_client_private_message_wait(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcMessagePayload *payload)
-{
- SilcPacket packet;
- SilcClientID remote_id;
- SilcFSMThread thread;
-
- if (!conn->internal->prv_waiter)
- return FALSE;
-
- /* Block until private message arrives */
- do {
- if ((silc_packet_wait(conn->internal->prv_waiter, 0, &packet)) < 0)
- return FALSE;
-
- /* Parse sender ID */
- if (!silc_id_str2id(packet->src_id, packet->src_id_len,
- SILC_ID_CLIENT, &remote_id,
- sizeof(remote_id))) {
- silc_packet_free(packet);
- continue;
- }
-
- /* If the private message is not for the requested client, pass it to
- normal private message processing. */
- if (!SILC_ID_CLIENT_COMPARE(&remote_id, &client_entry->id)) {
- thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
- silc_client_fsm_destructor, NULL, FALSE);
- if (!thread) {
- silc_packet_free(packet);
- continue;
- }
-
- /* The packet will be processed in the connection thread, after this
- FSM thread is started. */
- silc_fsm_set_state_context(thread, packet);
- silc_fsm_start(thread, silc_client_private_message);
- continue;
- }
-
- /* Parse the payload and decrypt it also if private message key is set */
- *payload =
- silc_message_payload_parse(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer),
- TRUE, !client_entry->internal.generated,
- client_entry->internal.receive_key,
- client_entry->internal.hmac_receive,
- packet->src_id, packet->src_id_len,
- packet->dst_id, packet->dst_id_len,
- NULL, FALSE, NULL);
- if (!(*payload)) {
- silc_packet_free(packet);
- continue;
- }
-
- break;
- } while (1);
-
- silc_packet_free(packet);
- return TRUE;
+ silc_free(remote_id);
}
-/*************************** Private Message Key ****************************/
-
-/* Sends private message key request. Sender of this packet is initiator
- when setting the private message key. */
-
-static SilcBool
-silc_client_send_private_message_key_request(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry)
-{
- const char *cipher, *hmac;
-
- SILC_LOG_DEBUG(("Sending private message key request"));
-
- cipher = silc_cipher_get_name(client_entry->internal.send_key);
- hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
-
- /* Send the packet */
- return silc_packet_send_va_ext(conn->stream,
- SILC_PACKET_PRIVATE_MESSAGE_KEY,
- 0, 0, NULL, SILC_ID_CLIENT,
- &client_entry->id, NULL, NULL,
- SILC_STR_UI_SHORT(strlen(cipher)),
- SILC_STR_DATA(cipher, strlen(cipher)),
- SILC_STR_UI_SHORT(strlen(hmac)),
- SILC_STR_DATA(hmac, strlen(hmac)),
- SILC_STR_END);
-}
-
-/* Client resolving callback. Here we simply mark that we are the responder
- side of this private message key request. */
+/* Function that actually employes the received private message key */
static void silc_client_private_message_key_cb(SilcClient client,
SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
void *context)
{
- SilcFSMThread thread = context;
- SilcPacket packet = silc_fsm_get_state_context(thread);
+ SilcPacketContext *packet = (SilcPacketContext *)context;
+ unsigned char *key;
+ SilcUInt16 key_len;
unsigned char *cipher = NULL, *hmac = NULL;
- SilcClientEntry client_entry;
int ret;
- if (!clients) {
- silc_packet_free(packet);
- silc_fsm_finish(thread);
- return;
- }
+ if (!clients)
+ goto out;
/* Parse the private message key payload */
- ret = silc_buffer_unformat(&packet->buffer,
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI16_NSTRING(&key, &key_len),
SILC_STR_UI16_STRING_ALLOC(&cipher),
SILC_STR_UI16_STRING_ALLOC(&hmac),
SILC_STR_END);
if (!ret)
goto out;
- /* Mark that we are responder */
- client_entry = silc_dlist_get(clients);
- client_entry->internal.prv_resp = TRUE;
+ if (key_len > packet->buffer->len)
+ goto out;
- /* XXX we should notify application that remote wants to set up the
- static key. And we should tell if we already have key with remote.
- Application should return status telling whether to delete the key
- or not. */
+ /* Mark that we are responder */
+ clients[0]->prv_resp = TRUE;
out:
silc_free(cipher);
silc_free(hmac);
- silc_packet_free(packet);
- silc_fsm_finish(thread);
+ silc_packet_context_free(packet);
}
/* Processes incoming Private Message Key payload to indicate that the
sender whishes to set up a static private message key. */
-SILC_FSM_STATE(silc_client_private_message_key)
+void silc_client_private_message_key(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcClientID remote_id;
-
- if (packet->src_id_type != SILC_ID_CLIENT) {
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- }
+ SilcClientID *remote_id;
- if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
- &remote_id, sizeof(remote_id))) {
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
- }
+ if (packet->src_id_type != SILC_ID_CLIENT)
+ return;
+
+ remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!remote_id)
+ return;
- /* Always resolve the remote client. The actual packet is processed
- in the resolving callback. */
- SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
- client, conn, &remote_id, NULL,
+ silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+ NULL,
silc_client_private_message_key_cb,
- fsm));
+ silc_packet_context_dup(packet));
+ silc_free(remote_id);
}
-/* Adds new private message key to `client_entry'. If we are setting this
- before receiving request for it from `client_entry' we will send the
- request to the client. Otherwise, we are responder side. */
-
-SilcBool silc_client_add_private_message_key(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *cipher,
- const char *hmac,
- unsigned char *key,
- SilcUInt32 key_len)
+/* Adds private message key to the client library. The key will be used to
+ encrypt all private message between the client and the remote client
+ indicated by the `client_entry'. If the `key' is NULL and the boolean
+ value `generate_key' is TRUE the library will generate random key.
+ The `key' maybe for example pre-shared-key, passphrase or similar.
+ The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
+ that the requirements of the SILC protocol are met. The API, however,
+ allows to allocate any cipher and HMAC.
+
+ If `responder' is TRUE then the sending and receiving keys will be
+ set according the client being the receiver of the private key. If
+ FALSE the client is being the sender (or negotiator) of the private
+ key.
+
+ It is not necessary to set key for normal private message usage. If the
+ key is not set then the private messages are encrypted using normal
+ session keys. Setting the private key, however, increases the security.
+
+ Returns FALSE if the key is already set for the `client_entry', TRUE
+ otherwise. */
+
+bool silc_client_add_private_message_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *cipher,
+ const char *hmac,
+ unsigned char *key,
+ SilcUInt32 key_len,
+ bool generate_key,
+ bool responder)
{
- SilcSKEKeyMaterial keymat;
- SilcBool ret;
+ unsigned char private_key[32];
+ SilcUInt32 len;
+ int i;
+ SilcSKEKeyMaterial *keymat;
- if (!client || !client_entry)
- return FALSE;
+ assert(client && client_entry);
/* Return FALSE if key already set */
- if (client_entry->internal.send_key && client_entry->internal.receive_key)
+ if (client_entry->send_key && client_entry->receive_key)
return FALSE;
if (!cipher)
if (!silc_hmac_is_supported(hmac))
return FALSE;
+ /* Generate key if not provided */
+ if (generate_key == TRUE) {
+ len = 32;
+ for (i = 0; i < len; i++)
+ private_key[i] = silc_rng_get_byte_fast(client->rng);
+ key = private_key;
+ key_len = len;
+ client_entry->generated = TRUE;
+ }
+
/* Save the key */
- client_entry->internal.key = silc_memdup(key, key_len);
- client_entry->internal.key_len = key_len;
+ client_entry->key = silc_memdup(key, key_len);
+ client_entry->key_len = key_len;
/* Produce the key material as the protocol defines */
- keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
- conn->internal->sha1hash);
- if (!keymat)
+ keymat = silc_calloc(1, sizeof(*keymat));
+ if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
+ client->sha1hash, keymat)
+ != SILC_SKE_STATUS_OK)
return FALSE;
- /* Set the key into use */
- ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
- cipher, hmac, keymat);
- client_entry->internal.generated = FALSE;
+ /* Allocate the cipher and HMAC */
+ silc_cipher_alloc(cipher, &client_entry->send_key);
+ silc_cipher_alloc(cipher, &client_entry->receive_key);
+ silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
+ silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
+
+ /* Set the keys */
+ if (responder == TRUE) {
+ silc_cipher_set_key(client_entry->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, keymat->receive_iv);
+ silc_cipher_set_key(client_entry->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, keymat->send_iv);
+ silc_hmac_set_key(client_entry->hmac_send, keymat->receive_hmac_key,
+ keymat->hmac_key_len);
+ silc_hmac_set_key(client_entry->hmac_receive, keymat->send_hmac_key,
+ keymat->hmac_key_len);
+ } else {
+ silc_cipher_set_key(client_entry->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, keymat->send_iv);
+ silc_cipher_set_key(client_entry->receive_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, keymat->receive_iv);
+ silc_hmac_set_key(client_entry->hmac_send, keymat->send_hmac_key,
+ keymat->hmac_key_len);
+ silc_hmac_set_key(client_entry->hmac_receive, keymat->receive_hmac_key,
+ keymat->hmac_key_len);
+ }
/* Free the key material */
silc_ske_free_key_material(keymat);
- /* If we are setting the key without a request from the remote client,
- we will send request to remote. */
- if (!client_entry->internal.prv_resp)
- silc_client_send_private_message_key_request(client, conn, client_entry);
-
- return ret;
+ return TRUE;
}
/* Same as above but takes the key material from the SKE key material
- structure. */
-
-SilcBool silc_client_add_private_message_key_ske(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *cipher,
- const char *hmac,
- SilcSKEKeyMaterial keymat)
+ structure. This structure is received if the application uses the
+ silc_client_send_key_agreement to negotiate the key material. The
+ `cipher' and `hmac' SHOULD be provided as it is negotiated also in
+ the SKE protocol. */
+
+bool silc_client_add_private_message_key_ske(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *cipher,
+ const char *hmac,
+ SilcSKEKeyMaterial *key,
+ bool responder)
{
- if (!client || !client_entry)
- return FALSE;
+ assert(client && client_entry);
/* Return FALSE if key already set */
- if (client_entry->internal.send_key && client_entry->internal.receive_key)
+ if (client_entry->send_key && client_entry->receive_key)
return FALSE;
if (!cipher)
if (!silc_hmac_is_supported(hmac))
return FALSE;
- client_entry->internal.generated = TRUE;
+ client_entry->generated = TRUE;
/* Allocate the cipher and HMAC */
- if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
- return FALSE;
- if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
- return FALSE;
- if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
- return FALSE;
- if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
- return FALSE;
+ silc_cipher_alloc(cipher, &client_entry->send_key);
+ silc_cipher_alloc(cipher, &client_entry->receive_key);
+ silc_hmac_alloc(hmac, NULL, &client_entry->hmac_send);
+ silc_hmac_alloc(hmac, NULL, &client_entry->hmac_receive);
/* Set the keys */
- if (client_entry->internal.prv_resp) {
- silc_cipher_set_key(client_entry->internal.send_key,
- keymat->receive_enc_key,
- keymat->enc_key_len, TRUE);
- silc_cipher_set_iv(client_entry->internal.send_key,
- keymat->receive_iv);
- silc_cipher_set_key(client_entry->internal.receive_key,
- keymat->send_enc_key,
- keymat->enc_key_len, FALSE);
- silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
- silc_hmac_set_key(client_entry->internal.hmac_send,
- keymat->receive_hmac_key,
- keymat->hmac_key_len);
- silc_hmac_set_key(client_entry->internal.hmac_receive,
- keymat->send_hmac_key,
- keymat->hmac_key_len);
+ if (responder == TRUE) {
+ silc_cipher_set_key(client_entry->send_key, key->receive_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, key->receive_iv);
+ silc_cipher_set_key(client_entry->receive_key, key->send_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, key->send_iv);
+ silc_hmac_set_key(client_entry->hmac_send, key->receive_hmac_key,
+ key->hmac_key_len);
+ silc_hmac_set_key(client_entry->hmac_receive, key->send_hmac_key,
+ key->hmac_key_len);
} else {
- silc_cipher_set_key(client_entry->internal.send_key,
- keymat->send_enc_key,
- keymat->enc_key_len, TRUE);
- silc_cipher_set_iv(client_entry->internal.send_key,
- keymat->send_iv);
- silc_cipher_set_key(client_entry->internal.receive_key,
- keymat->receive_enc_key,
- keymat->enc_key_len, FALSE);
- silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
- silc_hmac_set_key(client_entry->internal.hmac_send,
- keymat->send_hmac_key,
- keymat->hmac_key_len);
- silc_hmac_set_key(client_entry->internal.hmac_receive,
- keymat->receive_hmac_key,
- keymat->hmac_key_len);
+ silc_cipher_set_key(client_entry->send_key, key->send_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->send_key, key->send_iv);
+ silc_cipher_set_key(client_entry->receive_key, key->receive_enc_key,
+ key->enc_key_len);
+ silc_cipher_set_iv(client_entry->receive_key, key->receive_iv);
+ silc_hmac_set_key(client_entry->hmac_send, key->send_hmac_key,
+ key->hmac_key_len);
+ silc_hmac_set_key(client_entry->hmac_receive, key->receive_hmac_key,
+ key->hmac_key_len);
}
return TRUE;
}
+/* Sends private message key indicator. The sender of this packet is
+ going to be the initiator, if and when, the users set up a static
+ private message key (not Key Agreement). */
+
+bool silc_client_send_private_message_key_request(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SilcSocketConnection sock;
+ SilcBuffer buffer;
+ int cipher_len, hmac_len;
+ const char *cipher, *hmac;
+
+ assert(client && conn && client_entry);
+
+ sock = conn->sock;
+ if (!client_entry->send_key || !client_entry->key)
+ return FALSE;
+
+ SILC_LOG_DEBUG(("Sending private message key indicator"));
+
+ cipher = silc_cipher_get_name(client_entry->send_key);
+ cipher_len = strlen(cipher);
+ hmac = silc_hmac_get_name(client_entry->hmac_send);
+ hmac_len = strlen(hmac);
+
+ /* Create private message key payload */
+ buffer = silc_buffer_alloc_size(4 + cipher_len + hmac_len);
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(cipher_len),
+ SILC_STR_UI_XNSTRING(cipher,
+ cipher_len),
+ SILC_STR_UI_SHORT(hmac_len),
+ SILC_STR_UI_XNSTRING(hmac,
+ hmac_len),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE_KEY,
+ client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_free(buffer);
+
+ return TRUE;
+}
+
/* Removes the private message from the library. The key won't be used
after this to protect the private messages with the remote `client_entry'
client. Returns FALSE on error, TRUE otherwise. */
-SilcBool silc_client_del_private_message_key(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry)
+bool silc_client_del_private_message_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
{
- if (!client || !client_entry)
- return FALSE;
+ assert(client && client_entry);
- if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
+ if (!client_entry->send_key && !client_entry->receive_key)
return FALSE;
- silc_cipher_free(client_entry->internal.send_key);
- silc_cipher_free(client_entry->internal.receive_key);
+ silc_cipher_free(client_entry->send_key);
+ silc_cipher_free(client_entry->receive_key);
- if (client_entry->internal.key) {
- memset(client_entry->internal.key, 0, client_entry->internal.key_len);
- silc_free(client_entry->internal.key);
+ if (client_entry->key) {
+ memset(client_entry->key, 0, client_entry->key_len);
+ silc_free(client_entry->key);
}
- client_entry->internal.send_key = NULL;
- client_entry->internal.receive_key = NULL;
- client_entry->internal.key = NULL;
- client_entry->internal.prv_resp = FALSE;
+ client_entry->send_key = NULL;
+ client_entry->receive_key = NULL;
+ client_entry->key = NULL;
return TRUE;
}
{
SilcPrivateMessageKeys keys;
SilcUInt32 count = 0;
- SilcList list;
SilcIDCacheEntry id_cache;
+ SilcIDCacheList list;
SilcClientEntry entry;
- if (!client || !conn)
- return NULL;
+ assert(client && conn);
- silc_mutex_lock(conn->internal->lock);
- if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
- silc_mutex_unlock(conn->internal->lock);
+ if (!silc_idcache_get_all(conn->internal->client_cache, &list))
return NULL;
- }
- keys = silc_calloc(silc_list_count(list), sizeof(*keys));
- if (!keys) {
- silc_mutex_unlock(conn->internal->lock);
+ if (!silc_idcache_list_count(list)) {
+ silc_idcache_list_free(list);
return NULL;
}
- silc_list_start(list);
- while ((id_cache = silc_list_get(list))) {
- entry = id_cache->context;
- if (entry->internal.send_key) {
+ keys = silc_calloc(silc_idcache_list_count(list), sizeof(*keys));
+
+ silc_idcache_list_first(list, &id_cache);
+ while (id_cache) {
+ entry = (SilcClientEntry)id_cache->context;
+
+ if (entry->send_key) {
keys[count].client_entry = entry;
- keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
- send_key);
- keys[count].key = (entry->internal.generated == FALSE ?
- entry->internal.key : NULL);
- keys[count].key_len = (entry->internal.generated == FALSE ?
- entry->internal.key_len : 0);
+ keys[count].cipher = (char *)silc_cipher_get_name(entry->send_key);
+ keys[count].key = entry->generated == FALSE ? entry->key : NULL;
+ keys[count].key_len = entry->generated == FALSE ? entry->key_len : 0;
count++;
}
- }
- silc_mutex_unlock(conn->internal->lock);
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
if (key_count)
*key_count = count;
new one. If `message' is NULL the old away message is removed.
The sender may freely free the memory of the `message'. */
-SilcBool silc_client_set_away_message(SilcClient client,
- SilcClientConnection conn,
- char *message)
+void silc_client_set_away_message(SilcClient client,
+ SilcClientConnection conn,
+ char *message)
{
- if (!client || !conn)
- return FALSE;
+ assert(client && conn);
- if (!message) {
- silc_free(conn->internal->away_message);
- conn->internal->away_message = NULL;
- return TRUE;
+ if (!message && conn->internal->away) {
+ silc_free(conn->internal->away->away);
+ silc_free(conn->internal->away);
+ conn->internal->away = NULL;
}
- if (conn->internal->away_message)
- silc_free(conn->internal->away_message);
-
- conn->internal->away_message = strdup(message);
- if (!conn->internal->away_message)
- return FALSE;
-
- return TRUE;
+ if (message) {
+ if (!conn->internal->away)
+ conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
+ if (conn->internal->away->away)
+ silc_free(conn->internal->away->away);
+ conn->internal->away->away = strdup(message);
+ }
}
+++ /dev/null
-/*
-
- client_prvmsg.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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 CLIENT_PRVMSG_H
-#define CLIENT_PRVMSG_H
-
-SILC_FSM_STATE(silc_client_private_message);
-SILC_FSM_STATE(silc_client_private_message_error);
-SILC_FSM_STATE(silc_client_private_message_key);
-
-#endif /* CLIENT_PRVMSG_H */
+++ /dev/null
-/*
-
- client_register.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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 "silcclient.h"
-#include "client_internal.h"
-
-/************************** Types and definitions ***************************/
-
-/* Resume session context */
-typedef struct {
- SilcClient client;
- SilcClientConnection conn;
- SilcBufferStruct detach;
- char *nickname;
- SilcUInt32 channel_count;
-} *SilcClientResumeSession;
-
-/************************ Static utility functions **************************/
-
-/* Continues resuming after resolving. Continue after last reply. */
-
-static SilcBool
-silc_client_resume_continue(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END ||
- SILC_STATUS_IS_ERROR(status)) {
- silc_fsm_continue(&conn->internal->event_thread);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Function used to call command replies back to application in resuming. */
-
-static void
-silc_client_resume_command_callback(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command, ...)
-{
- va_list ap;
- va_start(ap, command);
- client->internal->ops->command_reply(client, conn, command,
- SILC_STATUS_OK, SILC_STATUS_OK, ap);
- va_end(ap);
-}
-
-
-/****************************** NEW_ID packet *******************************/
-
-/* Received new ID packet from server during registering to SILC network */
-
-SILC_FSM_STATE(silc_client_new_id)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
- SilcID id;
-
- if (conn->local_id)
- goto out;
-
- SILC_LOG_DEBUG(("New ID received from server"));
-
- if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
- silc_buffer_len(&packet->buffer), &id))
- goto out;
-
- SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
- SILC_ID_CLIENT)));
-
- /* Create local client entry */
- conn->local_entry = silc_client_add_client(client, conn,
- client->username,
- client->username,
- client->realname,
- &id.u.client_id, 0);
- if (!conn->local_entry)
- goto out;
-
- /* Save the ID. Take reference to conn->local_id. */
- conn->local_id = &conn->local_entry->id;
- conn->internal->local_idp = silc_buffer_copy(&packet->buffer);
-
- /* Save remote ID */
- if (packet->src_id_len) {
- conn->internal->remote_idp =
- silc_id_payload_encode_data(packet->src_id,
- packet->src_id_len,
- packet->src_id_type);
- if (!conn->internal->remote_idp)
- goto out;
- silc_id_payload_parse_id(silc_buffer_data(conn->internal->remote_idp),
- silc_buffer_len(conn->internal->remote_idp),
- &conn->remote_id);
- }
-
- /* Set IDs to the packet stream */
- silc_packet_set_ids(conn->stream, SILC_ID_CLIENT, conn->local_id,
- conn->remote_id.type, SILC_ID_GET_ID(conn->remote_id));
-
- /* Signal connection that new ID was received so it can continue
- with the registering. */
- if (conn->internal->registering)
- silc_fsm_continue_sync(&conn->internal->event_thread);
-
- out:
- /** Packet processed */
- silc_packet_free(packet);
- return SILC_FSM_FINISH;
-}
-
-
-/************************ Register to SILC network **************************/
-
-/* Register to network */
-
-SILC_FSM_STATE(silc_client_st_register)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- char *nick = NULL;
-
- SILC_LOG_DEBUG(("Register to network"));
-
- /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */
- if (conn->internal->remote_version >= 13)
- nick = (conn->internal->params.nickname ?
- conn->internal->params.nickname : client->username);
-
- /* Send NEW_CLIENT packet to register to network */
- if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0,
- SILC_STR_UI_SHORT(strlen(client->username)),
- SILC_STR_DATA(client->username,
- strlen(client->username)),
- SILC_STR_UI_SHORT(strlen(client->realname)),
- SILC_STR_DATA(client->realname,
- strlen(client->realname)),
- SILC_STR_UI_SHORT(nick ? strlen(nick) : 0),
- SILC_STR_DATA(nick, nick ? strlen(nick) : 0),
- SILC_STR_END)) {
- /** Error sending packet */
- silc_fsm_next(fsm, silc_client_st_register_error);
- return SILC_FSM_CONTINUE;
- }
-
- /** Wait for new ID */
- conn->internal->registering = TRUE;
- silc_fsm_next_later(fsm, silc_client_st_register_complete,
- conn->internal->retry_timer, 0);
- return SILC_FSM_WAIT;
-}
-
-/* Wait for NEW_ID packet to arrive */
-
-SILC_FSM_STATE(silc_client_st_register_complete)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_register_error);
- return SILC_FSM_CONTINUE;
- }
-
- if (!conn->local_id) {
- if (conn->internal->retry_count++ >= SILC_CLIENT_RETRY_COUNT) {
- /** Timeout, ID not received */
- conn->internal->registering = FALSE;
- conn->internal->retry_count = 0;
- conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN;
- silc_fsm_next(fsm, silc_client_st_register_error);
- return SILC_FSM_CONTINUE;
- }
-
- /** Resend registering packet */
- silc_fsm_next(fsm, silc_client_st_register);
- conn->internal->retry_timer = ((conn->internal->retry_timer *
- SILC_CLIENT_RETRY_MUL) +
- (silc_rng_get_rn16(client->rng) %
- SILC_CLIENT_RETRY_RAND));
- return SILC_FSM_CONTINUE;
- }
-
- SILC_LOG_DEBUG(("Registered to network"));
-
- /* Issue IDENTIFY command for itself to get resolved hostname
- correctly from server. */
- silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_command_called_dummy, NULL,
- 1, 5, silc_buffer_data(conn->internal->local_idp),
- silc_buffer_len(conn->internal->local_idp));
-
- /* With SILC protocol version 1.2 call NICK command if the nickname was
- set by the application. */
- if (conn->internal->params.nickname && conn->internal->remote_version < 13 &&
- !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
- silc_client_command_call(client, conn, NULL,
- "NICK", conn->internal->params.nickname, NULL);
-
- /* Issue INFO command to fetch the real server name and server
- information and other stuff. */
- silc_client_command_send(client, conn, SILC_COMMAND_INFO,
- silc_client_command_called_dummy, NULL,
- 1, 2, silc_buffer_data(conn->internal->remote_idp),
- silc_buffer_len(conn->internal->remote_idp));
-
- /* Call connection callback. We are now inside SILC network. */
- conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
- conn->callback_context);
-
- conn->internal->registering = FALSE;
- silc_schedule_task_del_by_all(conn->internal->schedule, 0,
- silc_client_connect_timeout, conn);
- silc_async_free(conn->internal->cop);
- conn->internal->cop = NULL;
-
- return SILC_FSM_FINISH;
-}
-
-/* Error registering to network */
-
-SILC_FSM_STATE(silc_client_st_register_error)
-{
- SilcClientConnection conn = fsm_context;
-
- SILC_LOG_DEBUG(("Error registering to network"));
-
- /* Signal to close connection */
- conn->internal->status = SILC_CLIENT_CONN_ERROR;
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
-
- silc_schedule_task_del_by_all(conn->internal->schedule, 0,
- silc_client_connect_timeout, conn);
-
- return SILC_FSM_FINISH;
-}
-
-/************************* Resume detached session **************************/
-
-/* Resume detached session */
-
-SILC_FSM_STATE(silc_client_st_resume)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientResumeSession resume;
- SilcBuffer auth;
- unsigned char *id;
- SilcUInt16 id_len;
- SilcClientID client_id;
- int ret;
-
- SILC_LOG_DEBUG(("Resuming detached session"));
-
- resume = silc_calloc(1, sizeof(*resume));
- if (!resume) {
- /** Out of memory */
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
- silc_fsm_set_state_context(fsm, resume);
-
- silc_buffer_set(&resume->detach, conn->internal->params.detach_data,
- conn->internal->params.detach_data_len);
- SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(&resume->detach),
- silc_buffer_len(&resume->detach));
-
- /* Take the old client ID from the detachment data */
- ret = silc_buffer_unformat(&resume->detach,
- SILC_STR_ADVANCE,
- SILC_STR_UI16_NSTRING_ALLOC(&resume->nickname,
- NULL),
- SILC_STR_UI16_NSTRING(&id, &id_len),
- SILC_STR_UI_INT(NULL),
- SILC_STR_UI_INT(&resume->channel_count),
- SILC_STR_END);
- if (ret < 0) {
- /** Malformed detach data */
- SILC_LOG_DEBUG(("Malformed detachment data"));
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &client_id,
- sizeof(client_id))) {
- /** Malformed ID */
- SILC_LOG_DEBUG(("Malformed ID"));
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Generate authentication data that server will verify */
- auth = silc_auth_public_key_auth_generate(conn->public_key,
- conn->private_key,
- client->rng,
- conn->internal->hash,
- &client_id, SILC_ID_CLIENT);
- if (!auth) {
- /** Out of memory */
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Send RESUME_CLIENT packet to resume to network */
- if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_DATA(id, id_len),
- SILC_STR_DATA(silc_buffer_data(auth),
- silc_buffer_len(auth)),
- SILC_STR_END)) {
- /** Error sending packet */
- SILC_LOG_DEBUG(("Error sending packet"));
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- /** Wait for new ID */
- conn->internal->registering = TRUE;
- silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0);
- return SILC_FSM_WAIT;
-}
-
-/* Resolve the old session information, user mode and joined channels. */
-
-SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientResumeSession resume = state_context;
- SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
- unsigned char **res_argv = NULL;
- int i;
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- if (!conn->local_id) {
- /** Timeout, ID not received */
- conn->internal->registering = FALSE;
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- /** Wait for channels */
- silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
-
- /* Change our nickname */
- silc_client_change_nickname(client, conn, conn->local_entry,
- resume->nickname, NULL, NULL, 0);
-
- /* Send UMODE command to get our own user mode in the network */
- SILC_LOG_DEBUG(("Resolving user mode"));
- silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
- silc_client_command_called_dummy, NULL,
- 1, 1, silc_buffer_data(conn->internal->local_idp),
- silc_buffer_len(conn->internal->local_idp));
-
- if (!resume->channel_count)
- return SILC_FSM_YIELD;
-
- /* Send IDENTIFY command for all channels we know about. These are the
- channels we've joined to according our detachment data. */
- for (i = 0; i < resume->channel_count; i++) {
- SilcChannelEntry channel;
- unsigned char *chid;
- SilcUInt16 chid_len;
- SilcBuffer idp;
- SilcChannelID channel_id;
- char *name;
-
- if (silc_buffer_unformat(&resume->detach,
- SILC_STR_ADVANCE,
- SILC_STR_UI16_NSTRING(&name, NULL),
- SILC_STR_UI16_NSTRING(&chid, &chid_len),
- SILC_STR_UI_INT(NULL),
- SILC_STR_END) < 0)
- continue;
-
- if (!silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL, &channel_id,
- sizeof(channel_id)))
- continue;
- idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
- if (!idp)
- continue;
-
- /* Add the channel to cache */
- channel = silc_client_get_channel_by_id(client, conn, &channel_id);
- if (!channel)
- silc_client_add_channel(client, conn, name, 0, &channel_id);
-
- res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
- res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
- (res_argc + 1));
- res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
- (res_argc + 1));
- res_argv[res_argc] = silc_buffer_steal(idp, &res_argv_lens[res_argc]);
- res_argv_types[res_argc] = res_argc + 5;
- res_argc++;
- silc_buffer_free(idp);
- }
-
- /* Send IDENTIFY command */
- SILC_LOG_DEBUG(("Resolving joined channels"));
- silc_client_command_send_argv(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_resume_continue, conn,
- res_argc, res_argv, res_argv_lens,
- res_argv_types);
-
- for (i = 0; i < resume->channel_count; i++)
- silc_free(res_argv[i]);
- silc_free(res_argv);
- silc_free(res_argv_lens);
- silc_free(res_argv_types);
-
- return SILC_FSM_WAIT;
-}
-
-/* Resolve joined channel modes, users and topics. */
-
-SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientResumeSession resume = state_context;
- SilcIDCacheEntry entry;
- SilcChannelEntry channel;
- SilcList channels;
- SilcBuffer idp;
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- SILC_LOG_DEBUG(("Resolving channel details"));
-
- /** Wait for channel modes */
- silc_fsm_next(fsm, silc_client_st_resume_completed);
-
- if (!silc_idcache_get_all(conn->internal->channel_cache, &channels))
- return SILC_FSM_YIELD;
-
- /* Resolve channels' mode, users and topic */
- resume->channel_count = silc_list_count(channels) * 3;
- silc_list_start(channels);
- while ((entry = silc_list_get(channels))) {
- channel = entry->context;
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- if (!idp)
- continue;
-
- silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
- silc_client_resume_continue, conn, 1,
- 1, silc_buffer_data(idp),
- silc_buffer_len(idp));
- silc_client_command_send(client, conn, SILC_COMMAND_USERS,
- silc_client_resume_continue, conn, 1,
- 1, silc_buffer_data(idp),
- silc_buffer_len(idp));
- silc_client_command_send(client, conn, SILC_COMMAND_TOPIC,
- silc_client_resume_continue, conn, 1,
- 1, silc_buffer_data(idp),
- silc_buffer_len(idp));
- silc_buffer_free(idp);
- }
-
- return SILC_FSM_WAIT;
-}
-
-/* Resuming completed */
-
-SILC_FSM_STATE(silc_client_st_resume_completed)
-{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcClientResumeSession resume = state_context;
- SilcIDCacheEntry entry;
- SilcChannelEntry channel;
- SilcList channels;
-
- if (conn->internal->disconnected) {
- /** Disconnected */
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
-
- if (resume->channel_count > 0) {
- resume->channel_count--;
- if (resume->channel_count)
- return SILC_FSM_WAIT;
- }
-
- SILC_LOG_DEBUG(("Resuming completed"));
-
- /* Issue IDENTIFY command for itself to get resolved hostname
- correctly from server. */
- silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_command_called_dummy, NULL,
- 1, 5, silc_buffer_data(conn->internal->local_idp),
- silc_buffer_len(conn->internal->local_idp));
-
- /* Issue INFO command to fetch the real server name and server
- information and other stuff. */
- silc_client_command_send(client, conn, SILC_COMMAND_INFO,
- silc_client_command_called_dummy, NULL,
- 1, 2, silc_buffer_data(conn->internal->remote_idp),
- silc_buffer_len(conn->internal->remote_idp));
-
- /* Call connection callback. We have now resumed to SILC network. */
- conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS_RESUME, 0, NULL,
- conn->callback_context);
-
- /* Call UMODE command reply. */
- if (conn->local_entry->mode)
- silc_client_resume_command_callback(client, conn, SILC_COMMAND_UMODE,
- conn->local_entry->mode);
-
- /* Call NICK command reply. */
- silc_client_resume_command_callback(client, conn, SILC_COMMAND_NICK,
- conn->local_entry,
- conn->local_entry->nickname,
- &conn->local_entry->id);
-
- /* Call JOIN command replies for all joined channel */
- silc_idcache_get_all(conn->internal->channel_cache, &channels);
- silc_list_start(channels);
- while ((entry = silc_list_get(channels))) {
- SilcHashTableList htl;
- const char *cipher, *hmac;
-
- channel = entry->context;
- cipher = (channel->internal.send_key ?
- silc_cipher_get_name(channel->internal.send_key) : NULL);
- hmac = (channel->internal.hmac ?
- silc_hmac_get_name(channel->internal.hmac) : NULL);
- silc_hash_table_list(channel->user_list, &htl);
- silc_client_resume_command_callback(client, conn, SILC_COMMAND_JOIN,
- channel->channel_name, channel,
- channel->mode, &htl, channel->topic,
- cipher, hmac, channel->founder_key,
- channel->channel_pubkeys,
- channel->user_limit);
- silc_hash_table_list_reset(&htl);
- }
-
- conn->internal->registering = FALSE;
- silc_schedule_task_del_by_all(conn->internal->schedule, 0,
- silc_client_connect_timeout, conn);
- silc_free(resume->nickname);
- silc_free(resume);
- silc_async_free(conn->internal->cop);
- conn->internal->cop = NULL;
-
- return SILC_FSM_FINISH;
-}
-
-/* Error resuming to network */
-
-SILC_FSM_STATE(silc_client_st_resume_error)
-{
- SilcClientConnection conn = fsm_context;
- SilcClientResumeSession resume = state_context;
-
- if (conn->internal->disconnected) {
- if (resume) {
- silc_free(resume->nickname);
- silc_free(resume);
- }
- return SILC_FSM_FINISH;
- }
-
- SILC_LOG_DEBUG(("Error resuming to network"));
-
- /* Signal to close connection */
- conn->internal->status = SILC_CLIENT_CONN_ERROR;
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
-
- silc_schedule_task_del_by_all(conn->internal->schedule, 0,
- silc_client_connect_timeout, conn);
-
- if (resume) {
- silc_free(resume->nickname);
- silc_free(resume);
- }
-
- return SILC_FSM_FINISH;
-}
-
-/* Generates the session detachment data. This data can be used later
- to resume back to the server. */
-
-SilcBuffer silc_client_get_detach_data(SilcClient client,
- SilcClientConnection conn)
-{
- SilcBuffer detach;
- SilcHashTableList htl;
- SilcChannelUser chu;
- unsigned char id[64];
- SilcUInt32 id_len;
- int ret, ch_count;
-
- SILC_LOG_DEBUG(("Creating detachment data"));
-
- ch_count = silc_hash_table_count(conn->local_entry->channels);
- silc_id_id2str(conn->local_id, SILC_ID_CLIENT, id, sizeof(id), &id_len);
-
- /* Save the nickname, Client ID and user mode in SILC network */
- detach = silc_buffer_alloc(0);
- if (!detach)
- return NULL;
- ret =
- silc_buffer_format(detach,
- SILC_STR_ADVANCE,
- SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)),
- SILC_STR_DATA(conn->local_entry->nickname,
- strlen(conn->local_entry->nickname)),
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_DATA(id, id_len),
- SILC_STR_UI_INT(conn->local_entry->mode),
- SILC_STR_UI_INT(ch_count),
- SILC_STR_END);
- if (ret < 0) {
- silc_buffer_free(detach);
- return NULL;
- }
-
- /* Save all joined channels */
- silc_hash_table_list(conn->local_entry->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
- unsigned char chid[32];
- SilcUInt32 chid_len;
-
- silc_id_id2str(&chu->channel->id, SILC_ID_CHANNEL, chid, sizeof(chid),
- &chid_len);
- silc_buffer_format(detach,
- SILC_STR_ADVANCE,
- SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
- SILC_STR_DATA(chu->channel->channel_name,
- strlen(chu->channel->channel_name)),
- SILC_STR_UI_SHORT(chid_len),
- SILC_STR_DATA(chid, chid_len),
- SILC_STR_UI_INT(chu->channel->mode),
- SILC_STR_END);
- }
- silc_hash_table_list_reset(&htl);
-
- silc_buffer_start(detach);
- SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(detach),
- silc_buffer_len(detach));
-
- return detach;
-}
+++ /dev/null
-/*
-
- client_register.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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 CLIENT_REGISTER_H
-#define CLIENT_REGISTER_H
-
-SILC_FSM_STATE(silc_client_new_id);
-SILC_FSM_STATE(silc_client_st_register);
-SILC_FSM_STATE(silc_client_st_register_complete);
-SILC_FSM_STATE(silc_client_st_register_error);
-SILC_FSM_STATE(silc_client_st_resume);
-SILC_FSM_STATE(silc_client_st_resume_resolve_channels);
-SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes);
-SILC_FSM_STATE(silc_client_st_resume_completed);
-SILC_FSM_STATE(silc_client_st_resume_error);
-
-SilcBuffer silc_client_get_detach_data(SilcClient client,
- SilcClientConnection conn);
-
-#endif /* CLIENT_REGISTER_H */
--- /dev/null
+/*
+
+ client_resume.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2002, 2004 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 "silcincludes.h"
+#include "silcclient.h"
+#include "client_internal.h"
+
+SILC_CLIENT_CMD_REPLY_FUNC(resume);
+SILC_CLIENT_CMD_FUNC(resume_identify);
+SILC_CLIENT_CMD_FUNC(resume_cmode);
+SILC_CLIENT_CMD_FUNC(resume_users);
+
+#define RESUME_CALL_COMPLETION(client, session, s) \
+do { \
+ SILC_LOG_DEBUG(("Calling completion")); \
+ session->success = s; \
+ silc_schedule_task_add(client->schedule, 0, \
+ silc_client_resume_call_completion, session, \
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); \
+} while(0)
+
+/* Generates the session detachment data. This data can be used later
+ to resume back to the server. */
+
+SilcBuffer silc_client_get_detach_data(SilcClient client,
+ SilcClientConnection conn)
+{
+ SilcBuffer detach;
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+ int ch_count;
+
+ SILC_LOG_DEBUG(("Creating detachment data"));
+
+ ch_count = silc_hash_table_count(conn->local_entry->channels);
+
+ /* Save the nickname, Client ID and user mode in SILC network */
+ detach = silc_buffer_alloc_size(2 + strlen(conn->nickname) +
+ 2 + conn->local_id_data_len + 4 + 4);
+ silc_buffer_format(detach,
+ SILC_STR_UI_SHORT(strlen(conn->nickname)),
+ SILC_STR_UI_XNSTRING(conn->nickname,
+ strlen(conn->nickname)),
+ SILC_STR_UI_SHORT(conn->local_id_data_len),
+ SILC_STR_UI_XNSTRING(conn->local_id_data,
+ conn->local_id_data_len),
+ SILC_STR_UI_INT(conn->local_entry->mode),
+ SILC_STR_UI_INT(ch_count),
+ SILC_STR_END);
+
+ /* Save all joined channels */
+ silc_hash_table_list(conn->local_entry->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ unsigned char *chid = silc_id_id2str(chu->channel->id, SILC_ID_CHANNEL);
+ SilcUInt16 chid_len = silc_id_get_len(chu->channel->id, SILC_ID_CHANNEL);
+
+ detach = silc_buffer_realloc(detach, detach->truelen + 2 +
+ strlen(chu->channel->channel_name) +
+ 2 + chid_len + 4);
+ silc_buffer_pull(detach, detach->len);
+ silc_buffer_pull_tail(detach, 2 + strlen(chu->channel->channel_name) +
+ 2 + chid_len + 4);
+ silc_buffer_format(detach,
+ SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
+ SILC_STR_UI_XNSTRING(chu->channel->channel_name,
+ strlen(chu->channel->channel_name)),
+ SILC_STR_UI_SHORT(chid_len),
+ SILC_STR_UI_XNSTRING(chid, chid_len),
+ SILC_STR_UI_INT(chu->channel->mode),
+ SILC_STR_END);
+ silc_free(chid);
+ }
+ silc_hash_table_list_reset(&htl);
+
+ silc_buffer_push(detach, detach->data - detach->head);
+
+ SILC_LOG_HEXDUMP(("Detach data"), detach->data, detach->len);
+
+ return detach;
+}
+
+/* Processes the detachment data. This creates channels and other
+ stuff according the data found in the the connection parameters.
+ This doesn't actually resolve any detailed information from the
+ server. To do that call silc_client_resume_session function.
+ This returns the old detached session client ID. */
+
+bool silc_client_process_detach_data(SilcClient client,
+ SilcClientConnection conn,
+ unsigned char **old_id,
+ SilcUInt16 *old_id_len)
+{
+ SilcBufferStruct detach;
+ SilcUInt32 ch_count;
+ int i, len;
+ char *newnick;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ silc_buffer_set(&detach, conn->internal->params.detach_data,
+ conn->internal->params.detach_data_len);
+
+ SILC_LOG_HEXDUMP(("Detach data"), detach.data, detach.len);
+
+ *old_id = NULL;
+ *old_id_len = 0;
+
+ /* Take the old client ID from the detachment data */
+ len = silc_buffer_unformat(&detach,
+ SILC_STR_UI16_NSTRING_ALLOC(&newnick,
+ NULL),
+ SILC_STR_UI16_NSTRING_ALLOC(old_id, old_id_len),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(&ch_count),
+ SILC_STR_END);
+ if (len == -1)
+ return FALSE;
+ if (!newnick || !(*old_id) || !(*old_id_len))
+ return FALSE;
+
+ silc_free(conn->nickname);
+ conn->nickname = newnick;
+
+ silc_buffer_pull(&detach, len);
+
+ for (i = 0; i < ch_count; i++) {
+ char *channel;
+ unsigned char *chid;
+ SilcUInt16 chid_len;
+ SilcUInt32 ch_mode;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel_entry;
+
+ len = silc_buffer_unformat(&detach,
+ SILC_STR_UI16_NSTRING_ALLOC(&channel, NULL),
+ SILC_STR_UI16_NSTRING(&chid, &chid_len),
+ SILC_STR_UI_INT(&ch_mode),
+ SILC_STR_END);
+ if (len == -1)
+ return FALSE;
+
+ /* Add new channel */
+ channel_id = silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL);
+ channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel_entry) {
+ channel_entry = silc_client_add_channel(client, conn, channel, ch_mode,
+ channel_id);
+ } else {
+ silc_free(channel);
+ silc_free(channel_id);
+ }
+
+ silc_buffer_pull(&detach, len);
+ }
+ silc_buffer_push(&detach, detach.data - detach.head);
+
+ return TRUE;
+}
+
+
+/* Resume session context */
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcClientResumeSessionCallback callback;
+ void *context;
+ SilcUInt32 channel_count;
+ SilcUInt32 *cmd_idents;
+ SilcUInt32 cmd_idents_count;
+ bool success;
+} *SilcClientResumeSession;
+
+/* Generic command reply callback. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(resume)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SILC_LOG_DEBUG(("Start"));
+ SILC_CLIENT_PENDING_EXEC(cmd, silc_command_get(cmd->payload));
+}
+
+/* Special command reply callback for IDENTIFY callbacks. This calls
+ the pending callback for every returned command entry. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(resume_special)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+ for (i = 0; i < cmd->callbacks_count; i++)
+ if (cmd->callbacks[i].callback)
+ (*cmd->callbacks[i].callback)(cmd->callbacks[i].context, cmd);
+}
+
+/* Completion calling callback */
+
+SILC_TASK_CALLBACK(silc_client_resume_call_completion)
+{
+ SilcClientResumeSession session = context;
+ int i;
+
+ SILC_LOG_DEBUG(("Session completed"));
+
+ for (i = 0; i < session->cmd_idents_count; i++)
+ silc_client_command_pending_del(session->conn, SILC_COMMAND_IDENTIFY,
+ session->cmd_idents[i]);
+ silc_free(session->cmd_idents);
+
+ session->callback(session->client, session->conn, session->success,
+ session->context);
+
+ memset(session, 'F', sizeof(*session));
+ silc_free(session);
+}
+
+/* This function is used to perform the resuming procedure after the
+ client has connected to the server properly and has received the
+ Client ID for the resumed session. This resolves all channels
+ that the resumed client is joined, joined users, users modes
+ and channel modes. The `callback' is called after this procedure
+ is completed. */
+
+void silc_client_resume_session(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientResumeSessionCallback callback,
+ void *context)
+{
+ SilcClientResumeSession session;
+ SilcIDCacheList list;
+ SilcIDCacheEntry entry;
+ SilcChannelEntry channel;
+ SilcBuffer tmp;
+ int i;
+ bool ret;
+
+ SILC_LOG_DEBUG(("Resuming detached session"));
+
+ session = silc_calloc(1, sizeof(*session));
+ if (!session) {
+ callback(client, conn, FALSE, context);
+ return;
+ }
+ session->client = client;
+ session->conn = conn;
+ session->callback = callback;
+ session->context = context;
+
+ /* First, send UMODE commandto get our own user mode in the network */
+ SILC_LOG_DEBUG(("Sending UMODE"));
+ tmp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
+ silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
+ conn->cmd_ident, 1, 1, tmp->data, tmp->len);
+ silc_buffer_free(tmp);
+
+ /* Second, send IDENTIFY command of all channels we know about. These
+ are the channels we've joined to according our detachment data. */
+ if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
+ unsigned char **res_argv = NULL;
+ SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+
+ session->channel_count = silc_idcache_list_count(list);
+
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ channel = entry->context;
+ tmp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
+ res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+ (res_argc + 1));
+ res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+ (res_argc + 1));
+ res_argv[res_argc] = silc_memdup(tmp->data, tmp->len);
+ res_argv_lens[res_argc] = tmp->len;
+ res_argv_types[res_argc] = res_argc + 5;
+ res_argc++;
+ silc_buffer_free(tmp);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+
+ if (res_argc) {
+ /* Send the IDENTIFY command */
+ SILC_LOG_DEBUG(("Sending IDENTIFY"));
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_resume_special,
+ 0, ++conn->cmd_ident);
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_resume_identify,
+ session);
+
+ tmp = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
+ res_argc, res_argv, res_argv_lens,
+ res_argv_types, conn->cmd_ident);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, tmp->data, tmp->len, TRUE);
+
+ session->cmd_idents = silc_realloc(session->cmd_idents,
+ sizeof(*session->cmd_idents) *
+ (session->cmd_idents_count + 1));
+ session->cmd_idents[session->cmd_idents_count] = conn->cmd_ident;
+ session->cmd_idents_count++;
+
+ for (i = 0; i < res_argc; i++)
+ silc_free(res_argv[i]);
+ silc_free(res_argv);
+ silc_free(res_argv_lens);
+ silc_free(res_argv_types);
+ silc_buffer_free(tmp);
+ }
+ }
+
+ if (!session->channel_count)
+ RESUME_CALL_COMPLETION(client, session, TRUE);
+
+ /* Now, we wait for replies to come back and then continue with USERS,
+ CMODE and TOPIC commands. */
+}
+
+/* Received identify reply for a channel entry */
+
+SILC_CLIENT_CMD_FUNC(resume_identify)
+{
+ SilcClientResumeSession session = context;
+ SilcClientCommandReplyContext cmd = context2;
+ SilcClient client = session->client;
+ SilcClientConnection conn = session->conn;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+ SilcChannelEntry channel = NULL;
+ SilcChannelID *channel_id;
+ SilcIDPayload idp;
+ SilcIdType id_type;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp)
+ goto err;
+
+ if (cmd->error != SILC_STATUS_OK) {
+ /* Delete unknown channel from our cache */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (channel_id) {
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (channel)
+ silc_client_del_channel(client, conn, channel);
+ silc_free(channel_id);
+ }
+ }
+ goto err;
+ }
+
+ idp = silc_id_payload_parse(tmp, tmp_len);
+ if (!idp) {
+ return;
+ }
+ id_type = silc_id_payload_get_type(idp);
+
+ switch (id_type) {
+ case SILC_ID_CHANNEL:
+ channel_id = silc_id_payload_get_id(idp);
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ silc_free(channel_id);
+ break;
+ default:
+ silc_id_payload_free(idp);
+ goto err;
+ break;
+ }
+
+ /* Now, send CMODE command for this channel. We send only this one
+ because this will return also error if we are not currently joined
+ on this channel, plus we get the channel mode. USERS and TOPIC
+ commands are called after this returns. */
+ if (channel) {
+ SILC_LOG_DEBUG(("Sending CMODE"));
+ silc_client_command_register(client, SILC_COMMAND_CMODE, NULL, NULL,
+ silc_client_command_reply_resume, 0,
+ ++conn->cmd_ident);
+ silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
+ conn->cmd_ident, 1, 1, tmp, tmp_len);
+ silc_client_command_pending(conn, SILC_COMMAND_CMODE, conn->cmd_ident,
+ silc_client_command_resume_cmode, session);
+ }
+
+ silc_id_payload_free(idp);
+
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END)
+ return;
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(client, SILC_COMMAND_IDENTIFY, NULL,
+ silc_client_command_reply_resume,
+ cmd->ident);
+ return;
+
+ err:
+ session->channel_count--;
+ if (!session->channel_count)
+ RESUME_CALL_COMPLETION(client, session, FALSE);
+}
+
+/* Received cmode to channel entry */
+
+SILC_CLIENT_CMD_FUNC(resume_cmode)
+{
+ SilcClientResumeSession session = context;
+ SilcClientCommandReplyContext cmd = context2;
+ SilcClient client = session->client;
+ SilcClientConnection conn = session->conn;
+ unsigned char *tmp;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel;
+ SilcUInt32 len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(client, SILC_COMMAND_CMODE, NULL,
+ silc_client_command_reply_resume,
+ cmd->ident);
+
+ if (cmd->error != SILC_STATUS_OK)
+ goto err;
+
+ /* Take Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto err;
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
+ goto err;
+
+ /* Get the channel entry */
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+ if (channel) {
+
+ /* Get channel mode */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (tmp)
+ SILC_GET32_MSB(channel->mode, tmp);
+
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+
+ /* And now, we will send USERS to get users on the channel */
+ SILC_LOG_DEBUG(("Sending USERS"));
+ silc_client_command_register(client, SILC_COMMAND_USERS, NULL, NULL,
+ silc_client_command_reply_users_i, 0,
+ ++conn->cmd_ident);
+ silc_client_command_send(client, conn, SILC_COMMAND_USERS,
+ conn->cmd_ident, 1, 1, tmp, len);
+ silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
+ silc_client_command_resume_users, session);
+ }
+
+ silc_free(channel_id);
+ return;
+
+ err:
+ session->channel_count--;
+ if (!session->channel_count)
+ RESUME_CALL_COMPLETION(client, session, FALSE);
+}
+
+/* Received users reply to a channel entry */
+
+SILC_CLIENT_CMD_FUNC(resume_users)
+{
+ SilcClientResumeSession session = context;
+ SilcClientCommandReplyContext cmd = context2;
+ SilcClient client = session->client;
+ SilcClientConnection conn = session->conn;
+ SilcBufferStruct client_id_list, client_mode_list;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len, list_count;
+ SilcChannelEntry channel;
+ SilcChannelID *channel_id = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(client, SILC_COMMAND_USERS, NULL,
+ silc_client_command_reply_users_i,
+ cmd->ident);
+
+ if (cmd->error != SILC_STATUS_OK)
+ goto err;
+
+ /* Get channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto err;
+ }
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!channel_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto err;
+ }
+
+ /* Get the list count */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto err;
+ }
+ SILC_GET32_MSB(list_count, tmp);
+
+ /* Get Client ID list */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto err;
+ }
+ silc_buffer_set(&client_id_list, tmp, tmp_len);
+
+ /* Get client mode list */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto err;
+ }
+ silc_buffer_set(&client_mode_list, tmp, tmp_len);
+
+ /* Get channel entry */
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+ if (!channel)
+ goto err;
+
+ /* Send fake JOIN command reply to application */
+ client->internal->ops->command_reply(client, conn, cmd->payload, TRUE,
+ SILC_COMMAND_JOIN, cmd->status,
+ channel->channel_name, channel,
+ channel->mode, 0,
+ NULL, NULL, NULL, NULL,
+ channel->hmac, list_count,
+ &client_id_list, client_mode_list);
+
+ /* Send TOPIC for this channel to get the topic */
+ SILC_LOG_DEBUG(("Sending TOPIC"));
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ silc_client_command_send(client, conn, SILC_COMMAND_TOPIC,
+ ++conn->cmd_ident, 1, 1, tmp, tmp_len);
+
+ /* Call the completion callback after we've got reply to all of
+ our channels */
+ session->channel_count--;
+ if (!session->channel_count)
+ RESUME_CALL_COMPLETION(client, session, TRUE);
+
+ silc_free(channel_id);
+ return;
+
+ err:
+ silc_free(channel_id);
+ session->channel_count--;
+ if (!session->channel_count)
+ RESUME_CALL_COMPLETION(client, session, FALSE);
+}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
+#define SILC_NOT_CONNECTED(x, c) \
+ x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
+ "You are not connected to a server, please connect to server");
/* Command operation that is called at the end of all commands.
Usage: COMMAND(status); */
-#define COMMAND(status) cmd->conn->client->internal->ops->command( \
- cmd->conn->client, cmd->conn, TRUE, cmd->cmd, (status), cmd->argc, cmd->argv)
+#define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
+ cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
/* Error to application. Usage: COMMAND_ERROR(status); */
-#define COMMAND_ERROR(status) \
- cmd->conn->client->internal->ops->command(cmd->conn->client, \
- cmd->conn, FALSE, cmd->cmd, (status), cmd->argc, cmd->argv)
+#define COMMAND_ERROR(status) \
+ cmd->client->internal->ops->command(cmd->client, \
+ cmd->conn, cmd, FALSE, cmd->command->cmd, (status))
-/* Used to register new command */
-#define SILC_CLIENT_CMD(func, cmd, name, args) \
-silc_client_command_register(client, SILC_COMMAND_##cmd, name, \
- silc_client_command_##func, \
- silc_client_command_reply_##func, args)
+#define SAY cmd->client->internal->ops->say
-/* Used to unregister command */
-#define SILC_CLIENT_CMDU(func, cmd, name) \
-silc_client_command_unregister(client, SILC_COMMAND_##cmd, \
- silc_client_command_##func, \
- silc_client_command_reply_##func)
-
-#define SAY cmd->conn->client->internal->ops->say
-
-/************************ Static utility functions **************************/
-
-/* Return next available command identifier. */
-
-static SilcUInt16 silc_client_cmd_ident(SilcClientConnection conn)
-{
- SilcUInt16 cmd_ident;
-
- cmd_ident = silc_atomic_add_int16(&conn->internal->cmd_ident, 1);
- if (!cmd_ident)
- cmd_ident = silc_atomic_add_int16(&conn->internal->cmd_ident, 1);
-
- return cmd_ident;
-}
-
-/* State to finish command thread after an error in resolving command */
-
-SILC_FSM_STATE(silc_client_command_continue_error)
-{
- /* Destructor will free all resources */
- return SILC_FSM_FINISH;
-}
-
-/* Command reply callback to continue with the execution of a command.
- This will continue when first successful reply is received, and ignores
- the rest. On the other hand, if only errors are received it will
- wait for all errors before continuing. */
-
-static SilcBool silc_client_command_continue(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- SilcClientCommandContext cmd = context;
-
- /* Continue immediately when successful reply is received */
- if (status == SILC_STATUS_OK || !SILC_STATUS_IS_ERROR(error)) {
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
- return FALSE;
- }
-
- /* Error */
- COMMAND_ERROR(error);
-
- /* Continue after last error is received */
- if (SILC_STATUS_IS_ERROR(status) ||
- (status == SILC_STATUS_LIST_END && SILC_STATUS_IS_ERROR(error))) {
- silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Continues after resolving completed. */
-
-static void silc_client_command_resolve_continue(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- SilcClientCommandContext cmd = context;
-
- if (status != SILC_STATUS_OK)
- silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
-
- /* Continue with the command */
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-/* Dummy command callback. Nothing interesting to do here. Use this when
- you just send command but don't care about reply. */
-
-SilcBool silc_client_command_called_dummy(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- return FALSE;
-}
-
-/* Dummy resolving callback. Nothing interesting to do here. Use this
- when you just resolve entires but don't care about reply. */
-
-void silc_client_command_resolve_dummy(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- /* Nothing */
-}
-
-/* Register command to client */
+/* Generic function to send any command. The arguments must be sent already
+ encoded into correct form and in correct order. */
-static SilcBool
-silc_client_command_register(SilcClient client,
- SilcCommand command,
- const char *name,
- SilcFSMStateCallback command_func,
- SilcFSMStateCallback command_reply_func,
- SilcUInt8 max_args)
+void silc_client_command_send(SilcClient client, SilcClientConnection conn,
+ SilcCommand command, SilcUInt16 ident,
+ SilcUInt32 argc, ...)
{
- SilcClientCommand cmd;
-
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return FALSE;
- cmd->cmd = command;
- cmd->command = command_func;
- cmd->reply = command_reply_func;
- cmd->max_args = max_args;
- cmd->name = name ? strdup(name) : NULL;
- if (!cmd->name) {
- silc_free(cmd);
- return FALSE;
- }
-
- silc_list_add(client->internal->commands, cmd);
-
- return TRUE;
-}
-
-/* Unregister command from client */
+ SilcBuffer packet;
+ va_list ap;
-static SilcBool
-silc_client_command_unregister(SilcClient client,
- SilcCommand command,
- SilcFSMStateCallback command_func,
- SilcFSMStateCallback command_reply_func)
-{
- SilcClientCommand cmd;
+ assert(client && conn);
- silc_list_start(client->internal->commands);
- while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
- if (cmd->cmd == command && cmd->command == command_func &&
- cmd->reply == command_reply_func) {
- silc_list_del(client->internal->commands, cmd);
- silc_free(cmd->name);
- silc_free(cmd);
- return TRUE;
- }
- }
+ va_start(ap, argc);
- return FALSE;
+ packet = silc_command_payload_encode_vap(command, ident, argc, ap);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, packet->data,
+ packet->len, TRUE);
+ silc_buffer_free(packet);
}
/* Finds and returns a pointer to the command list. Return NULL if the
command is not found. */
-static SilcClientCommand silc_client_command_find(SilcClient client,
- const char *name)
+SilcClientCommand silc_client_command_find(SilcClient client,
+ const char *name)
{
SilcClientCommand cmd;
+ assert(client);
+
silc_list_start(client->internal->commands);
while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
if (cmd->name && !strcasecmp(cmd->name, name))
return NULL;
}
-/* Command thread destructor */
-
-static void silc_client_command_destructor(SilcFSMThread thread,
- void *fsm_context,
- void *destructor_context)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
-
- /* Removes commands that aren't waiting for reply but are waiting
- for something. They may not have been removed yet. */
- silc_list_del(conn->internal->pending_commands, cmd);
-
- silc_client_command_free(cmd);
-}
-
-/* Add a command pending a command reply. Used internally by the library. */
-
-static SilcBool
-silc_client_command_add_pending(SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcClientCommandReply reply,
- void *context)
-{
- SilcClientCommandReplyCallback cb;
-
- silc_mutex_lock(conn->internal->lock);
-
- /* Add pending callback, if defined */
- if (reply) {
- cb = silc_calloc(1, sizeof(*cb));
- if (!cb) {
- silc_mutex_unlock(conn->internal->lock);
- return FALSE;
- }
- cb->reply = reply;
- cb->context = context;
- silc_list_add(cmd->reply_callbacks, cb);
- }
-
- /* Add pending reply */
- silc_list_add(conn->internal->pending_commands, cmd);
-
- silc_mutex_unlock(conn->internal->lock);
-
- return TRUE;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. Arguments come from
- variable argument list pointer. */
-
-static SilcUInt16 silc_client_command_send_vap(SilcClient client,
- SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, va_list ap)
-{
- SilcBuffer packet;
-
- SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
-
- if (conn->internal->disconnected)
- return 0;
-
- if (!cmd->cmd_ident)
- cmd->cmd_ident = silc_client_cmd_ident(conn);
-
- /* Encode command payload */
- packet = silc_command_payload_encode_vap(command, cmd->cmd_ident, argc, ap);
- if (!packet)
- return 0;
-
- /* Send the command */
- if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
- silc_buffer_datalen(packet))) {
- silc_buffer_free(packet);
- return 0;
- }
-
- /* Add the command pending command reply */
- silc_client_command_add_pending(conn, cmd, reply, reply_context);
-
- silc_buffer_free(packet);
-
- return cmd->cmd_ident;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. Arguments come from
- arrays. */
-
-static SilcUInt16
-silc_client_command_send_arg_array(SilcClient client,
- SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc,
- unsigned char **argv,
- SilcUInt32 *argv_lens,
- SilcUInt32 *argv_types)
-{
- SilcBuffer packet;
-
- SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
-
- if (conn->internal->disconnected)
- return 0;
-
- if (!cmd->cmd_ident)
- cmd->cmd_ident = silc_client_cmd_ident(conn);
-
- /* Encode command payload */
- packet = silc_command_payload_encode(command, argc, argv, argv_lens,
- argv_types, cmd->cmd_ident);
- if (!packet)
- return 0;
-
- /* Send the command */
- if (!silc_packet_send(conn->stream, SILC_PACKET_COMMAND, 0,
- silc_buffer_datalen(packet))) {
- silc_buffer_free(packet);
- return 0;
- }
-
- /* Add the command pending command reply */
- silc_client_command_add_pending(conn, cmd, reply, reply_context);
-
- silc_buffer_free(packet);
-
- return cmd->cmd_ident;
-}
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. This is used internally
- by the library. */
-
-static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
- SilcClientCommandContext cmd,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, ...)
-{
- va_list ap;
- SilcUInt16 cmd_ident;
-
- va_start(ap, argc);
- cmd_ident = silc_client_command_send_vap(conn->client, conn, cmd, command,
- reply, reply_context, argc, ap);
- va_end(ap);
-
- return cmd_ident;
-}
-
-/****************************** Command API *********************************/
-
-/* Free command context and its internals */
-
-void silc_client_command_free(SilcClientCommandContext cmd)
-{
- SilcClientCommandReplyCallback cb;
- int i;
-
- for (i = 0; i < cmd->argc; i++)
- silc_free(cmd->argv[i]);
- silc_free(cmd->argv);
- silc_free(cmd->argv_lens);
- silc_free(cmd->argv_types);
-
- silc_list_start(cmd->reply_callbacks);
- while ((cb = silc_list_get(cmd->reply_callbacks)))
- silc_free(cb);
-
- silc_free(cmd);
-}
-
/* Executes a command */
-SilcUInt16 silc_client_command_call(SilcClient client,
- SilcClientConnection conn,
- const char *command_line, ...)
+bool silc_client_command_call(SilcClient client,
+ SilcClientConnection conn,
+ const char *command_line, ...)
{
va_list va;
SilcUInt32 argc = 0;
unsigned char **argv = NULL;
SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
- SilcClientCommand command;
- SilcClientCommandContext cmd;
+ SilcClientCommand cmd;
+ SilcClientCommandContext ctx;
char *arg;
- if (!conn) {
- client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "You are not connected to a server, please connect to server");
- return 0;
- }
+ assert(client);
/* Parse arguments */
va_start(va, command_line);
/* Get command name */
command_name = silc_memdup(command_line, strcspn(command_line, " "));
if (!command_name)
- return 0;
+ return FALSE;
/* Find command by name */
- command = silc_client_command_find(client, command_name);
- if (!command) {
+ cmd = silc_client_command_find(client, command_name);
+ if (!cmd) {
silc_free(command_name);
- return 0;
+ return FALSE;
}
/* Parse command line */
silc_parse_command_line((char *)command_line, &argv, &argv_lens,
- &argv_types, &argc, command->max_args);
+ &argv_types, &argc, cmd->max_args);
silc_free(command_name);
} else {
arg = va_arg(va, char *);
if (!arg)
- return 0;
+ return FALSE;
/* Find command by name */
- command = silc_client_command_find(client, arg);
- if (!command)
- return 0;
+ cmd = silc_client_command_find(client, arg);
+ if (!cmd)
+ return FALSE;
while (arg) {
argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
- if (!argv || !argv_lens || !argv_types)
- return 0;
argv[argc] = silc_memdup(arg, strlen(arg));
- if (!argv[argc])
- return 0;
argv_lens[argc] = strlen(arg);
argv_types[argc] = argc;
argc++;
arg = va_arg(va, char *);
}
}
+
+ /* Allocate command context. */
+ ctx = silc_client_command_alloc();
+ ctx->client = client;
+ ctx->conn = conn;
+ ctx->command = cmd;
+ ctx->argc = argc;
+ ctx->argv = argv;
+ ctx->argv_lens = argv_lens;
+ ctx->argv_types = argv_types;
+
+ /* Call the command */
+ cmd->command(ctx, NULL);
+
va_end(va);
- /* Allocate command context */
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return 0;
- cmd->conn = conn;
- cmd->cmd = command->cmd;
- cmd->argc = argc;
- cmd->argv = argv;
- cmd->argv_lens = argv_lens;
- cmd->argv_types = argv_types;
- cmd->cmd_ident = silc_client_cmd_ident(conn);
- cmd->called = TRUE;
- cmd->verbose = TRUE;
- silc_list_init(cmd->reply_callbacks,
- struct SilcClientCommandReplyCallbackStruct, next);
-
- /*** Call command */
- SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
- silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
- silc_client_command_destructor, NULL, FALSE);
- silc_fsm_start_sync(&cmd->thread, command->command);
-
- return cmd->cmd_ident;
+ return TRUE;
}
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. */
-
-SilcUInt16 silc_client_command_send(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, ...)
+/* Add new pending command to be executed when reply to a command has been
+ received. The `reply_cmd' is the command that will call the `callback'
+ with `context' when reply has been received. It can be SILC_COMMAND_NONE
+ to match any command with the `ident'. If `ident' is non-zero
+ the `callback' will be executed when received reply with command
+ identifier `ident'. If there already exists pending command for the
+ specified command, ident, callback and context this function has no
+ effect. */
+
+void silc_client_command_pending(SilcClientConnection conn,
+ SilcCommand reply_cmd,
+ SilcUInt16 ident,
+ SilcCommandCb callback,
+ void *context)
{
- SilcClientCommandContext cmd;
- va_list ap;
+ SilcClientCommandPending *reply;
+
+ assert(conn);
+ reply = silc_calloc(1, sizeof(*reply));
+ reply->reply_cmd = reply_cmd;
+ reply->ident = ident;
+ reply->context = context;
+ reply->callback = callback;
+ silc_dlist_add(conn->internal->pending_commands, reply);
+}
- if (!conn || !reply)
- return 0;
+/* Deletes pending command by reply command type. */
- /* Allocate command context */
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return 0;
- cmd->conn = conn;
- cmd->cmd = command;
- silc_list_init(cmd->reply_callbacks,
- struct SilcClientCommandReplyCallbackStruct, next);
+void silc_client_command_pending_del(SilcClientConnection conn,
+ SilcCommand reply_cmd,
+ SilcUInt16 ident)
+{
+ SilcClientCommandPending *r;
- /* Send the command */
- va_start(ap, argc);
- cmd->cmd_ident =
- silc_client_command_send_vap(client, conn, cmd, command, reply,
- reply_context, argc, ap);
- va_end(ap);
+ if (!conn->internal->pending_commands)
+ return;
- if (!cmd->cmd_ident) {
- silc_client_command_free(cmd);
- return 0;
+ silc_dlist_start(conn->internal->pending_commands);
+ while ((r = silc_dlist_get(conn->internal->pending_commands))
+ != SILC_LIST_END) {
+ if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
+ r->reply_check))
+ && r->ident == ident) {
+ silc_dlist_del(conn->internal->pending_commands, r);
+ silc_free(r);
+ }
}
-
- /*** Wait for command reply */
- silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
- silc_client_command_destructor, NULL, FALSE);
- silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
-
- return cmd->cmd_ident;
}
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct format and in correct order. Arguments come from
- arrays. */
-
-SilcUInt16 silc_client_command_send_argv(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc,
- unsigned char **argv,
- SilcUInt32 *argv_lens,
- SilcUInt32 *argv_types)
-{
- SilcClientCommandContext cmd;
-
- if (!conn || !reply)
- return 0;
-
- /* Allocate command context */
- cmd = silc_calloc(1, sizeof(*cmd));
- if (!cmd)
- return 0;
- cmd->conn = conn;
- cmd->cmd = command;
+/* Checks for pending commands and marks callbacks to be called from
+ the command reply function. */
- /* Send the command */
- cmd->cmd_ident =
- silc_client_command_send_arg_array(client, conn, cmd, command, reply,
- reply_context, argc, argv, argv_lens,
- argv_types);
- if (!cmd->cmd_ident) {
- silc_client_command_free(cmd);
- return 0;
+SilcClientCommandPendingCallbacks
+silc_client_command_pending_check(SilcClientConnection conn,
+ SilcClientCommandReplyContext ctx,
+ SilcCommand command,
+ SilcUInt16 ident,
+ SilcUInt32 *callbacks_count)
+{
+ SilcClientCommandPending *r;
+ SilcClientCommandPendingCallbacks callbacks = NULL;
+ int i = 0;
+
+ silc_dlist_start(conn->internal->pending_commands);
+ while ((r = silc_dlist_get(conn->internal->pending_commands))
+ != SILC_LIST_END) {
+ if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
+ && r->ident == ident) {
+ callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
+ callbacks[i].context = r->context;
+ callbacks[i].callback = r->callback;
+ r->reply_check = TRUE;
+ ctx->ident = ident;
+ i++;
+ }
}
- /*** Wait for command reply */
- silc_fsm_thread_init(&cmd->thread, &conn->internal->fsm, cmd,
- silc_client_command_destructor, NULL, FALSE);
- silc_fsm_start_sync(&cmd->thread, silc_client_command_reply_wait);
-
- return cmd->cmd_ident;
+ *callbacks_count = i;
+ return callbacks;
}
-/* Attach to a command and command identifier to receive command reply. */
+/* Allocate Command Context */
-SilcBool silc_client_command_pending(SilcClientConnection conn,
- SilcCommand command,
- SilcUInt16 ident,
- SilcClientCommandReply reply,
- void *context)
+SilcClientCommandContext silc_client_command_alloc(void)
{
- SilcClientCommandContext cmd;
- SilcClientCommandReplyCallback cb;
-
- if (!conn || !reply)
- return FALSE;
-
- SILC_LOG_DEBUG(("Add pending command reply for ident %d", ident));
-
- silc_mutex_lock(conn->internal->lock);
+ SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->users++;
+ return ctx;
+}
- /* Find the pending command */
- silc_list_start(conn->internal->pending_commands);
- while ((cmd = silc_list_get(conn->internal->pending_commands)))
- if ((cmd->cmd == command || command == SILC_COMMAND_NONE)
- && cmd->cmd_ident == ident) {
+/* Free command context and its internals */
- /* Add the callback */
- cb = silc_calloc(1, sizeof(*cb));
- if (!cb)
- continue;
- cb->reply = reply;
- cb->context = context;
- silc_list_add(cmd->reply_callbacks, cb);
- }
+void silc_client_command_free(SilcClientCommandContext ctx)
+{
+ ctx->users--;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
+ ctx->users));
+ if (ctx->users < 1) {
+ int i;
+
+ for (i = 0; i < ctx->argc; i++)
+ silc_free(ctx->argv[i]);
+ silc_free(ctx->argv);
+ silc_free(ctx->argv_lens);
+ silc_free(ctx->argv_types);
+ silc_free(ctx);
+ }
+}
- silc_mutex_unlock(conn->internal->lock);
+/* Duplicate Command Context by adding reference counter. The context won't
+ be free'd untill it hits zero. */
- return TRUE;
+SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
+{
+ ctx->users++;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
+ ctx->users));
+ return ctx;
}
-/******************************** WHOIS *************************************/
-
/* Command WHOIS. This command is used to query information about
specific user. */
-SILC_FSM_STATE(silc_client_command_whois)
+SILC_CLIENT_CMD_FUNC(whois)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcBuffer attrs = NULL;
+ SilcBuffer buffer, attrs = NULL;
unsigned char count[4], *tmp = NULL;
- SilcBool details = FALSE, nick = FALSE;
- unsigned char *pubkey = NULL;
int i;
+ bool details = FALSE, nick = FALSE;
+ unsigned char *pubkey = NULL;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
/* Given without arguments fetches client's own information */
if (cmd->argc < 2) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
- silc_buffer_data(conn->internal->local_idp),
- silc_buffer_len(conn->internal->local_idp));
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
+ silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
+ ++conn->cmd_ident,
+ 1, 4, buffer->data, buffer->len);
+ silc_buffer_free(buffer);
+ goto out;
}
for (i = 1; i < cmd->argc; i++) {
if (!strcasecmp(cmd->argv[i], "-details")) {
- details = TRUE;
+ details = TRUE;
} else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
- pubkey = cmd->argv[i + 1];
- i++;
+ pubkey = cmd->argv[i + 1];
+ i++;
} else {
/* We assume that the first parameter is the nickname, if it isn't
-details or -pubkey. The last parameter should always be the count */
}
if (details) {
- /* If pubkey is set, add all attributes to the attrs buffer, except
- public key */
+ /* if pubkey is set, add all attributes to the
+ attrs buffer, except public key */
if (pubkey) {
attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
SILC_ATTRIBUTE_SERVICE,
SILC_ATTRIBUTE_PREFERRED_CONTACT,
SILC_ATTRIBUTE_TIMEZONE,
SILC_ATTRIBUTE_GEOLOCATION,
- SILC_ATTRIBUTE_DEVICE_INFO,
- SILC_ATTRIBUTE_USER_ICON, 0);
+ SILC_ATTRIBUTE_DEVICE_INFO, 0);
} else {
attrs = silc_client_attributes_request(0);
}
SilcAttributeObjPk obj;
SilcPublicKey pk;
- if (!silc_pkcs_load_public_key(pubkey, &pk)) {
- SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load public key %s, check the filename",
- pubkey);
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) {
+ if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not load public key %s, check the filename",
+ pubkey);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
}
- switch (silc_pkcs_get_type(pk)) {
- case SILC_PKCS_SILC:
- obj.type = "silc-rsa";
- break;
- case SILC_PKCS_SSH2:
- obj.type = "ssh-rsa";
- break;
- case SILC_PKCS_X509V3:
- obj.type = "x509v3-sign-rsa";
- break;
- case SILC_PKCS_OPENPGP:
- obj.type = "pgp-sign-rsa";
- break;
- default:
- goto out;
- break;
- }
+ obj.type = "silc-rsa";
obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
attrs = silc_attribute_payload_encode(attrs,
&obj, sizeof(obj));
}
- /* Send command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 3, 1, nick ? cmd->argv[1] : NULL,
- nick ? cmd->argv_lens[1] : 0,
- 2, tmp ? tmp : NULL, tmp ? 4 : 0,
- 3, silc_buffer_datalen(attrs));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
+ ++conn->cmd_ident, 3,
+ 1, nick ? cmd->argv[1] : NULL,
+ nick ? cmd->argv_lens[1] : 0,
+ 2, tmp ? tmp : NULL, tmp ? 4 : 0,
+ 3, attrs ? attrs->data : NULL,
+ attrs ? attrs->len : 0);
+
+ silc_client_packet_send(cmd->client, cmd->conn->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/******************************** WHOWAS ************************************/
-
/* Command WHOWAS. This command is used to query history information about
specific user that used to exist in the network. */
-SILC_FSM_STATE(silc_client_command_whowas)
+SILC_CLIENT_CMD_FUNC(whowas)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
unsigned char count[4];
- int c;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 2 || cmd->argc > 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /WHOWAS <nickname>[@<server>] [<count>]");
COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
SILC_STATUS_ERR_TOO_MANY_PARAMS));
- return SILC_FSM_FINISH;
+ goto out;
}
if (cmd->argc == 2) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, cmd->argv[1], cmd->argv_lens[1]);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
+ ++conn->cmd_ident, 1,
+ 1, cmd->argv[1],
+ cmd->argv_lens[1]);
} else {
- c = atoi(cmd->argv[2]);
+ int c = atoi(cmd->argv[2]);
+ memset(count, 0, sizeof(count));
SILC_PUT32_MSB(c, count);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 2, 1, cmd->argv[1], cmd->argv_lens[1],
- 2, count, sizeof(count));
- }
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1], cmd->argv_lens[1],
+ 2, count, sizeof(count));
+ }
+ silc_client_packet_send(cmd->client, cmd->conn->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/******************************** IDENTIFY **********************************/
-
/* Command IDENTIFY. This command is used to query information about
- specific user, especially ID's. */
+ specific user, especially ID's.
+
+ NOTE: This command is used only internally by the client library
+ and application MUST NOT call this command directly. */
-SILC_FSM_STATE(silc_client_command_identify)
+SILC_CLIENT_CMD_FUNC(identify)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
unsigned char count[4];
- int c;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 2 || cmd->argc > 3)
- return SILC_FSM_FINISH;
+ goto out;
if (cmd->argc == 2) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, cmd->argv[1], cmd->argv_lens[1]);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ ++conn->cmd_ident, 1,
+ 1, cmd->argv[1],
+ cmd->argv_lens[1]);
} else {
- c = atoi(cmd->argv[2]);
+ int c = atoi(cmd->argv[2]);
+ memset(count, 0, sizeof(count));
SILC_PUT32_MSB(c, count);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 2, 1, cmd->argv[1], cmd->argv_lens[1],
- 4, count, sizeof(count));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1],
+ cmd->argv_lens[1],
+ 4, count, sizeof(count));
}
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
+ silc_client_packet_send(cmd->client, cmd->conn->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
-/********************************** NICK ************************************/
+ out:
+ silc_client_command_free(cmd);
+}
/* Command NICK. Shows current nickname/sets new nickname on current
window. */
-SILC_FSM_STATE(silc_client_command_nick)
+SILC_CLIENT_CMD_FUNC(nick)
{
- SilcClientCommandContext cmd2, cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /NICK <nickname>");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- if (silc_utf8_strcasecmp(conn->local_entry->nickname, cmd->argv[1]))
+ if (silc_utf8_strcasecmp(conn->nickname, cmd->argv[1]))
goto out;
/* Show current nickname */
if (cmd->argc < 2) {
if (cmd->conn) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Your nickname is %s on server %s",
- conn->local_entry->nickname, conn->remote_host);
+ conn->nickname, conn->remote_host);
} else {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Your nickname is %s", conn->local_entry->nickname);
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Your nickname is %s", conn->nickname);
}
COMMAND(SILC_STATUS_OK);
goto out;
}
- /* If JOIN command is active, wait for it to finish before sending NICK.
- To avoid problems locally with changing IDs while joining, we do this. */
- silc_mutex_lock(conn->internal->lock);
- silc_list_start(conn->internal->pending_commands);
- while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
- if (cmd2->cmd == SILC_COMMAND_JOIN) {
- silc_mutex_unlock(conn->internal->lock);
- silc_fsm_next_later(fsm, silc_client_command_nick, 0, 300000);
- return SILC_FSM_WAIT;
- }
- }
- silc_mutex_unlock(conn->internal->lock);
-
if (cmd->argv_lens[1] > 128)
cmd->argv_lens[1] = 128;
/* Send the NICK command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, cmd->argv[1], cmd->argv_lens[1]);
-
- /* Notify application */
- COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
+ &cmd->argv[1],
+ &cmd->argv_lens[1],
+ &cmd->argv_types[1],
+ ++cmd->conn->cmd_ident);
+ silc_client_packet_send(cmd->client, cmd->conn->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
out:
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************** LIST ************************************/
-
/* Command LIST. Lists channels on the current server. */
-SILC_FSM_STATE(silc_client_command_list)
+SILC_CLIENT_CMD_FUNC(list)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcBuffer idp = NULL;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, idp = NULL;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc == 2) {
/* Get the Channel ID of the channel */
- channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
+ channel = silc_client_get_channel(cmd->client, cmd->conn, cmd->argv[1]);
if (channel)
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
}
if (!idp)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
+ ++conn->cmd_ident, 0);
else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL,
- 1, 1, silc_buffer_datalen(idp));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
+ ++conn->cmd_ident, 1,
+ 1, idp->data, idp->len);
- silc_buffer_free(idp);
- silc_client_unref_channel(client, conn, channel);
+ silc_client_packet_send(cmd->client, cmd->conn->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ if (idp)
+ silc_buffer_free(idp);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** TOPIC ***********************************/
-
/* Command TOPIC. Sets/shows topic on a channel. */
-SILC_FSM_STATE(silc_client_command_topic)
+SILC_CLIENT_CMD_FUNC(topic)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
SilcChannelEntry channel;
- SilcBuffer idp;
+ SilcBuffer buffer, idp;
char *name;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2 || cmd->argc > 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /TOPIC <channel> [<topic>]");
COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
SILC_STATUS_ERR_TOO_MANY_PARAMS));
}
/* Get the Channel ID of the channel */
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
-
/* Send TOPIC command to the server */
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
if (cmd->argc > 2)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(idp),
- 2, cmd->argv[2], strlen(cmd->argv[2]));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
+ ++conn->cmd_ident, 2,
+ 1, idp->data, idp->len,
+ 2, cmd->argv[2],
+ strlen(cmd->argv[2]));
else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(idp));
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
+ ++conn->cmd_ident, 1,
+ 1, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(idp);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************* INVITE ***********************************/
-
/* Command INVITE. Invites specific client to join a channel. This is
also used to mange the invite list of the channel. */
-SILC_FSM_STATE(silc_client_command_invite)
+SILC_CLIENT_CMD_FUNC(invite)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClient client = cmd->client;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
SilcClientEntry client_entry = NULL;
- SilcChannelEntry channel = NULL;
- SilcBuffer clidp, chidp, args = NULL;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, clidp, chidp, args = NULL;
SilcPublicKey pubkey = NULL;
- SilcDList clients = NULL;
char *nickname = NULL, *name;
char *invite = NULL;
unsigned char action[1];
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /INVITE <channel> [<nickname>[@server>]"
"[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
}
channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
} else {
name = cmd->argv[1];
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
/* Parse the typed nickname. */
if (cmd->argc == 3) {
if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
- silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[2], &nickname);
+ else
+ nickname = strdup(cmd->argv[2]);
/* Find client entry */
- clients = silc_client_get_clients_local(client, conn, nickname,
- cmd->argv[2]);
- if (!clients)
- /* Resolve client information */
- SILC_FSM_CALL(silc_client_get_clients(
- client, conn, nickname,
- cmd->argv[2],
- silc_client_command_resolve_continue,
- cmd));
-
- client_entry = silc_dlist_get(clients);
+ client_entry = silc_idlist_get_client(client, conn, nickname,
+ cmd->argv[2], TRUE);
+ if (!client_entry) {
+ if (cmd->pending) {
+ COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
+ goto out;
+ }
+
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_invite,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ goto out;
+ }
} else {
if (cmd->argv[2][0] == '+')
action[0] = 0x00;
action[0] = 0x01;
/* Check if it is public key file to be added to invite list */
- silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
+ if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+ SILC_PKCS_FILE_PEM))
+ silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+ SILC_PKCS_FILE_BIN);
invite = cmd->argv[2];
if (!pubkey)
invite++;
SILC_STR_UI_SHORT(1),
SILC_STR_END);
if (pubkey) {
- chidp = silc_public_key_payload_encode(pubkey);
- args = silc_argument_payload_encode_one(args, silc_buffer_data(chidp),
- silc_buffer_len(chidp), 2);
+ chidp = silc_pkcs_public_key_payload_encode(pubkey);
+ args = silc_argument_payload_encode_one(args, chidp->data,
+ chidp->len, 2);
silc_buffer_free(chidp);
silc_pkcs_public_key_free(pubkey);
} else {
}
/* Send the command */
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
if (client_entry) {
- clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
- 1, silc_buffer_datalen(chidp),
- 2, silc_buffer_datalen(clidp),
- 3, args ? action : NULL, args ? 1 : 0,
- 4, silc_buffer_datalen(args));
+ clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
+ ++conn->cmd_ident, 4,
+ 1, chidp->data, chidp->len,
+ 2, clidp->data, clidp->len,
+ 3, args ? action : NULL,
+ args ? 1 : 0,
+ 4, args ? args->data : NULL,
+ args ? args->len : 0);
silc_buffer_free(clidp);
} else {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(chidp),
- 3, args ? action : NULL, args ? 1 : 0,
- 4, silc_buffer_datalen(args));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
+ ++conn->cmd_ident, 3,
+ 1, chidp->data, chidp->len,
+ 3, args ? action : NULL,
+ args ? 1 : 0,
+ 4, args ? args->data : NULL,
+ args ? args->len : 0);
}
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(chidp);
silc_buffer_free(args);
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
silc_free(nickname);
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************** QUIT ************************************/
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+} *QuitInternal;
-/* Close the connection */
+SILC_TASK_CALLBACK(silc_client_command_quit_cb)
+{
+ QuitInternal q = (QuitInternal)context;
-SILC_FSM_STATE(silc_client_command_quit_final)
+ /* Close connection */
+ q->client->internal->ops->disconnected(q->client, q->conn, 0, NULL);
+ silc_client_close_connection(q->client, q->conn->sock->user_data);
+
+ silc_free(q);
+}
+
+/* Command QUIT. Closes connection with current server. */
+
+SILC_CLIENT_CMD_FUNC(quit)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcBuffer buffer;
+ QuitInternal q;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ if (cmd->argc > 1)
+ buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
+ &cmd->argv[1], &cmd->argv_lens[1],
+ &cmd->argv_types[1],
+ ++cmd->conn->cmd_ident);
+ else
+ buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
+ NULL, NULL, NULL,
+ ++cmd->conn->cmd_ident);
+ silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
- SILC_LOG_DEBUG(("Quitting"));
+ q = silc_calloc(1, sizeof(*q));
+ q->client = cmd->client;
+ q->conn = cmd->conn;
+
+ /* Sleep for a while */
+ sleep(2);
+
+ /* We quit the connection with little timeout */
+ silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
+ silc_client_command_quit_cb, (void *)q,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /* Signal to close connection */
- conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED;
- if (!conn->internal->disconnected) {
- conn->internal->disconnected = TRUE;
- SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
- }
-
- return SILC_FSM_FINISH;
+ out:
+ silc_client_command_free(cmd);
}
-/* Command QUIT. Closes connection with current server. */
+/* Timeout callback to remove the killed client from cache */
-SILC_FSM_STATE(silc_client_command_quit)
+SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClient client = cmd->client;
SilcClientConnection conn = cmd->conn;
+ SilcClientEntry target;
+ char *nickname = NULL;
- if (cmd->argc > 1)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, cmd->argv[1], cmd->argv_lens[1]);
+ /* Parse the typed nickname. */
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[1], &nickname);
else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
+ nickname = strdup(cmd->argv[1]);
- /* Sleep for a while */
- sleep(1);
+ /* Get the target client */
+ target = silc_idlist_get_client(cmd->client, conn, nickname,
+ cmd->argv[1], FALSE);
+ if (target)
+ /* Remove the client from all channels and free it */
+ silc_client_del_client(client, conn, target);
- /* We close the connection with a little timeout */
- silc_fsm_next_later(fsm, silc_client_command_quit_final, 2, 0);
- return SILC_FSM_WAIT;
+ silc_free(nickname);
+ silc_client_command_free(cmd);
}
-/********************************** KILL ************************************/
+/* Kill command's pending command callback to actually remove the killed
+ client from our local cache. */
+
+SILC_CLIENT_CMD_FUNC(kill_remove)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientCommandReplyContext reply =
+ (SilcClientCommandReplyContext)context2;
+ SilcStatus status;
+
+ silc_command_get_status(reply->payload, &status, NULL);
+ if (status == SILC_STATUS_OK) {
+ /* Remove with timeout */
+ silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock,
+ silc_client_command_kill_remove_later, context,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ return;
+ }
+
+ silc_client_command_free(cmd);
+}
/* Command KILL. Router operator can use this command to remove an client
fromthe SILC Network. */
-SILC_FSM_STATE(silc_client_command_kill)
+SILC_CLIENT_CMD_FUNC(kill)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClient client = cmd->client;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcBuffer idp, auth = NULL;
+ SilcBuffer buffer, idp, auth = NULL;
SilcClientEntry target;
- SilcDList clients;
char *nickname = NULL, *comment = NULL;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /KILL <nickname> [<comment>] [-pubkey]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ goto out;
}
/* Parse the typed nickname. */
- if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
- return SILC_FSM_FINISH;
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[1], &nickname);
+ else
+ nickname = strdup(cmd->argv[1]);
/* Get the target client */
- clients = silc_client_get_clients_local(client, conn, nickname,
- cmd->argv[1]);
- if (!clients)
- /* Resolve client information */
- SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname,
- cmd->argv[1],
- silc_client_command_resolve_continue,
- cmd));
+ target = silc_idlist_get_client(cmd->client, conn, nickname,
+ cmd->argv[1], TRUE);
+ if (!target) {
+ if (cmd->pending) {
+ COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
+ goto out;
+ }
- target = silc_dlist_get(clients);
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_kill,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ goto out;
+ }
if (cmd->argc >= 3) {
if (strcasecmp(cmd->argv[2], "-pubkey"))
if (!strcasecmp(cmd->argv[2], "-pubkey") ||
(cmd->argc >= 4 && !strcasecmp(cmd->argv[3], "-pubkey"))) {
/* Encode the public key authentication payload */
- auth = silc_auth_public_key_auth_generate(conn->public_key,
- conn->private_key,
- conn->client->rng,
- conn->internal->sha1hash,
- &target->id, SILC_ID_CLIENT);
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ client->sha1hash,
+ target->id, SILC_ID_CLIENT);
}
}
/* Send the KILL command to the server */
- idp = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(idp),
- 2, comment, comment ? strlen(comment) : 0,
- 3, silc_buffer_datalen(auth));
+ idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_KILL,
+ ++conn->cmd_ident, 3,
+ 1, idp->data, idp->len,
+ 2, comment, comment ? strlen(comment) : 0,
+ 3, auth ? auth->data : NULL,
+ auth ? auth->len : 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(idp);
silc_buffer_free(auth);
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-}
+ /* Register a pending callback that will actually remove the killed
+ client from our cache. */
+ silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident,
+ silc_client_command_kill_remove,
+ silc_client_command_dup(cmd));
-/********************************** INFO ************************************/
+ out:
+ silc_free(nickname);
+ silc_client_command_free(cmd);
+}
/* Command INFO. Request information about specific server. If specific
server is not provided the current server is used. */
-SILC_FSM_STATE(silc_client_command_info)
+SILC_CLIENT_CMD_FUNC(info)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+ char *name = NULL;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
- /* Send the command */
if (cmd->argc == 2)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, cmd->argv[1], cmd->argv_lens[1]);
+ name = strdup(cmd->argv[1]);
+
+ /* Send the command */
+ if (name)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO,
+ ++conn->cmd_ident, 1,
+ 1, name, strlen(name));
else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
+ buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
+ NULL, NULL, NULL, ++conn->cmd_ident);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ if (name)
+ silc_free(name);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** STATS ***********************************/
-
/* Command STATS. Shows server and network statistics. */
-SILC_FSM_STATE(silc_client_command_stats)
+SILC_CLIENT_CMD_FUNC(stats)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer, idp = NULL;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
/* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(conn->internal->
- remote_idp));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
+ ++conn->cmd_ident, 1,
+ SILC_ID_SERVER, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** PING ************************************/
-
-/* Command PING. Sends ping to server. */
+/* Command PING. Sends ping to server. This is used to test the
+ communication channel. */
-SILC_FSM_STATE(silc_client_command_ping)
+SILC_CLIENT_CMD_FUNC(ping)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer, idp;
+ void *id;
+ int i;
- if (cmd->argc < 2) {
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
}
+ idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+
/* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(conn->internal->
- remote_idp));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PING,
+ ++conn->cmd_ident, 1,
+ 1, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
- /* Save ping time */
- cmd->context = SILC_64_TO_PTR(silc_time());
+ id = silc_id_str2id(conn->remote_id_data, conn->remote_id_data_len,
+ SILC_ID_SERVER);
+ if (!id) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ /* Start counting time */
+ for (i = 0; i < conn->internal->ping_count; i++) {
+ if (conn->internal->ping[i].dest_id == NULL) {
+ conn->internal->ping[i].start_time = time(NULL);
+ conn->internal->ping[i].dest_id = id;
+ conn->internal->ping[i].dest_name = strdup(conn->remote_host);
+ break;
+ }
+ }
+ if (i >= conn->internal->ping_count) {
+ i = conn->internal->ping_count;
+ conn->internal->ping =
+ silc_realloc(conn->internal->ping,
+ sizeof(*conn->internal->ping) * (i + 1));
+ conn->internal->ping[i].start_time = time(NULL);
+ conn->internal->ping[i].dest_id = id;
+ conn->internal->ping[i].dest_name = strdup(conn->remote_host);
+ conn->internal->ping_count++;
+ }
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** JOIN ************************************/
-
/* Command JOIN. Joins to a channel. */
-SILC_FSM_STATE(silc_client_command_join)
+SILC_CLIENT_CMD_FUNC(join)
{
- SilcClientCommandContext cmd2, cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcBuffer auth = NULL, cauth = NULL;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
int i, passphrase_len = 0;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* See if we have joined to the requested channel already */
- channel = silc_client_get_channel(conn->client, conn, cmd->argv[1]);
+ channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
if (channel && silc_client_on_channel(channel, conn->local_entry))
goto out;
- /* If NICK command is active, wait for it to finish before sending JOIN.
- To avoid problems locally with changing IDs while joining, we do this. */
- silc_mutex_lock(conn->internal->lock);
- silc_list_start(conn->internal->pending_commands);
- while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
- if (cmd2->cmd == SILC_COMMAND_NICK) {
- silc_mutex_unlock(conn->internal->lock);
- silc_fsm_next_later(fsm, silc_client_command_join, 0, 300000);
- return SILC_FSM_WAIT;
- }
- }
- silc_mutex_unlock(conn->internal->lock);
+ idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
if (cmd->argv_lens[1] > 256)
cmd->argv_lens[1] = 256;
for (i = 2; i < cmd->argc; i++) {
if (!strcasecmp(cmd->argv[i], "-cipher") && cmd->argc > i + 1) {
- cipher = cmd->argv[++i];
+ cipher = cmd->argv[i + 1];
+ i++;
} else if (!strcasecmp(cmd->argv[i], "-hmac") && cmd->argc > i + 1) {
- hmac = cmd->argv[++i];
+ hmac = cmd->argv[i + 1];
+ i++;
} else if (!strcasecmp(cmd->argv[i], "-founder")) {
- auth = silc_auth_public_key_auth_generate(conn->public_key,
- conn->private_key,
- conn->client->rng,
- conn->internal->sha1hash,
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ cmd->client->sha1hash,
conn->local_id,
SILC_ID_CLIENT);
} else if (!strcasecmp(cmd->argv[i], "-auth")) {
- SilcPublicKey pubkey = conn->public_key;
- SilcPrivateKey privkey = conn->private_key;
+ SilcPublicKey pubkey = cmd->client->public_key;
+ SilcPrivateKey privkey = cmd->client->private_key;
unsigned char *pk, pkhash[SILC_HASH_MAXLEN], *pubdata;
SilcUInt32 pk_len;
i++;
}
if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
- &pubkey, &privkey)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+ NULL, &pubkey, &privkey)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Could not load key pair, check your arguments");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
- silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
+ silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
silc_free(pk);
- pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
+ pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
memcpy(pubdata, pkhash, 20);
cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
pubdata, 128,
- conn->internal->sha1hash,
+ cmd->client->sha1hash,
conn->local_id,
SILC_ID_CLIENT);
memset(pubdata, 0, 128);
}
/* Send JOIN command to the server */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
- 1, name, strlen(name),
- 2, silc_buffer_datalen(conn->internal->
- local_idp),
- 3, passphrase, passphrase_len,
- 4, cipher, cipher ? strlen(cipher) : 0,
- 5, hmac, hmac ? strlen(hmac) : 0,
- 6, silc_buffer_datalen(auth),
- 7, silc_buffer_datalen(cauth));
-
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_JOIN, ++conn->cmd_ident, 7,
+ 1, name, strlen(name),
+ 2, idp->data, idp->len,
+ 3, passphrase, passphrase_len,
+ 4, cipher, cipher ? strlen(cipher) : 0,
+ 5, hmac, hmac ? strlen(hmac) : 0,
+ 6, auth ? auth->data : NULL,
+ auth ? auth->len : 0,
+ 7, cauth ? cauth->data : NULL,
+ cauth ? cauth->len : 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
silc_buffer_free(auth);
silc_buffer_free(cauth);
if (passphrase)
memset(passphrase, 0, strlen(passphrase));
silc_free(passphrase);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- silc_client_unref_channel(client, conn, channel);
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************** MOTD ************************************/
-
/* MOTD command. Requests motd from server. */
-SILC_FSM_STATE(silc_client_command_motd)
+SILC_CLIENT_CMD_FUNC(motd)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 1 || cmd->argc > 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /MOTD [<server>]");
COMMAND_ERROR((cmd->argc < 1 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
SILC_STATUS_ERR_TOO_MANY_PARAMS));
- return SILC_FSM_FINISH;
+ goto out;
}
- /* Send the command */
+ /* Send TOPIC command to the server */
if (cmd->argc == 1)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, conn->remote_host,
- strlen(conn->remote_host));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
+ ++conn->cmd_ident, 1,
+ 1, conn->remote_host,
+ strlen(conn->remote_host));
else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, cmd->argv[1], cmd->argv_lens[1]);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD,
+ ++conn->cmd_ident, 1,
+ 1, cmd->argv[1],
+ cmd->argv_lens[1]);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** UMODE ***********************************/
-
/* UMODE. Set/unset user mode in SILC. This is used mainly to unset the
modes as client cannot set itself server/router operator privileges. */
-SILC_FSM_STATE(silc_client_command_umode)
+SILC_CLIENT_CMD_FUNC(umode)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer, idp;
unsigned char *cp, modebuf[4];
SilcUInt32 mode, add, len;
int i;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /UMODE +|-<modes>");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ goto out;
}
mode = conn->local_entry->mode;
break;
default:
COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
- return SILC_FSM_FINISH;
+ goto out;
break;
}
}
+ idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
SILC_PUT32_MSB(mode, modebuf);
- /* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(conn->internal->
- local_idp),
- 2, modebuf, sizeof(modebuf));
+ /* Send the command packet. We support sending only one mode at once
+ that requires an argument. */
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
+ 1, idp->data, idp->len,
+ 2, modebuf, sizeof(modebuf));
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** CMODE ***********************************/
-
/* CMODE command. Sets channel mode. Modes that does not require any arguments
can be set several at once. Those modes that require argument must be set
separately (unless set with modes that does not require arguments). */
-SILC_FSM_STATE(silc_client_command_cmode)
+SILC_CLIENT_CMD_FUNC(cmode)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcBuffer chidp, auth = NULL, pk = NULL;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, chidp, auth = NULL, pk = NULL;
unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
SilcUInt32 mode, add, type, len, arg_len = 0;
int i;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
} else {
name = cmd->argv[1];
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
mode |= SILC_CHANNEL_MODE_ULIMIT;
type = 3;
if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
mode |= SILC_CHANNEL_MODE_PASSPHRASE;
type = 4;
if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
mode |= SILC_CHANNEL_MODE_CIPHER;
type = 5;
if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
mode |= SILC_CHANNEL_MODE_HMAC;
type = 6;
if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
break;
case 'f':
if (add) {
- SilcPublicKey pubkey = conn->public_key;
- SilcPrivateKey privkey = conn->private_key;
+ SilcPublicKey pubkey = cmd->client->public_key;
+ SilcPrivateKey privkey = cmd->client->private_key;
mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
type = 7;
if (cmd->argc >= 6)
pass = cmd->argv[5];
if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
- &pubkey, &privkey)) {
- SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+ NULL, &pubkey, &privkey)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Could not load key pair, check your arguments");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
}
- pk = silc_public_key_payload_encode(pubkey);
+ pk = silc_pkcs_public_key_payload_encode(pubkey);
auth = silc_auth_public_key_auth_generate(pubkey, privkey,
- conn->client->rng,
- conn->internal->sha1hash,
+ cmd->client->rng,
+ cmd->client->sha1hash,
conn->local_id,
SILC_ID_CLIENT);
- arg = silc_buffer_data(auth);
- arg_len = silc_buffer_len(auth);
+ arg = auth->data;
+ arg_len = auth->len;
} else {
mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
}
case 'C':
if (add) {
int k;
- SilcBool chadd = FALSE;
+ bool chadd = FALSE;
SilcPublicKey chpk = NULL;
mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
if (cmd->argc == 3) {
/* Send empty command to receive the public key list. */
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
- NULL, NULL, 1,
- 1, silc_buffer_datalen(chidp));
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
+ 0, 1, 1, chidp->data, chidp->len);
silc_buffer_free(chidp);
/* Notify application */
for (k = 3; k < cmd->argc; k++) {
if (cmd->argv[k][0] == '+')
chadd = TRUE;
- if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load public key %s, check the filename",
- cmd->argv[k]);
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- silc_buffer_free(auth);
- goto out;
- }
+ if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
+ SILC_PKCS_FILE_PEM))
+ if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
+ SILC_PKCS_FILE_BIN)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not load public key %s, check the filename",
+ cmd->argv[k]);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_buffer_free(auth);
+ goto out;
+ }
if (chpk) {
- pk = silc_public_key_payload_encode(chpk);
- auth = silc_argument_payload_encode_one(auth,
- silc_buffer_datalen(pk),
+ pk = silc_pkcs_public_key_payload_encode(chpk);
+ auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
chadd ? 0x00 : 0x01);
silc_pkcs_public_key_free(chpk);
silc_buffer_free(pk);
}
}
- arg = silc_buffer_data(auth);
- arg_len = silc_buffer_len(auth);
+ arg = auth->data;
+ arg_len = auth->len;
} else {
mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
}
}
}
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
SILC_PUT32_MSB(mode, modebuf);
- /* Send the command. We support sending only one mode at once that
- requires an argument. */
+ /* Send the command packet. We support sending only one mode at once
+ that requires an argument. */
if (type && arg) {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
- 1, silc_buffer_datalen(chidp),
- 2, modebuf, sizeof(modebuf),
- type, arg, arg_len,
- 8, silc_buffer_datalen(pk));
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 4,
+ 1, chidp->data, chidp->len,
+ 2, modebuf, sizeof(modebuf),
+ type, arg, arg_len,
+ 8, pk ? pk->data : NULL,
+ pk ? pk->len : 0);
} else {
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(chidp),
- 2, modebuf, sizeof(modebuf));
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_CMODE, ++conn->cmd_ident, 2,
+ 1, chidp->data, chidp->len,
+ 2, modebuf, sizeof(modebuf));
}
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(chidp);
silc_buffer_free(auth);
silc_buffer_free(pk);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- silc_client_unref_channel(client, conn, channel);
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************* CUMODE ***********************************/
-
/* CUMODE command. Changes client's mode on a channel. */
-SILC_FSM_STATE(silc_client_command_cumode)
+SILC_CLIENT_CMD_FUNC(cumode)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClient client = cmd->client;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
+ SilcChannelEntry channel;
SilcChannelUser chu;
SilcClientEntry client_entry;
- SilcBuffer clidp, chidp, auth = NULL;
- SilcDList clients = NULL;
+ SilcBuffer buffer, clidp, chidp, auth = NULL;
unsigned char *name, *cp, modebuf[4];
SilcUInt32 mode = 0, add, len;
char *nickname = NULL;
int i;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 4) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
} else {
name = cmd->argv[1];
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
/* Parse the typed nickname. */
- silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[3], &nickname);
+ else
+ nickname = strdup(cmd->argv[3]);
/* Find client entry */
- clients = silc_client_get_clients_local(client, conn, nickname,
- cmd->argv[3]);
- if (!clients)
- /* Resolve client information */
- SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3],
- silc_client_command_resolve_continue,
- cmd));
+ client_entry = silc_idlist_get_client(cmd->client, conn, nickname,
+ cmd->argv[3], TRUE);
+ if (!client_entry) {
+ if (cmd->pending) {
+ COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
+ goto out;
+ }
- client_entry = silc_dlist_get(clients);
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_cumode,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ goto out;
+ }
/* Get the current mode */
chu = silc_client_on_channel(channel, client_entry);
break;
case 'f':
if (add) {
- SilcPublicKey pubkey = conn->public_key;
- SilcPrivateKey privkey = conn->private_key;
+ SilcPublicKey pubkey = cmd->client->public_key;
+ SilcPrivateKey privkey = cmd->client->private_key;
if (cmd->argc >= 6) {
char *pass = "";
if (cmd->argc >= 7)
pass = cmd->argv[6];
if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
- &pubkey, &privkey)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+ NULL, &pubkey, &privkey)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Could not load key pair, check your arguments");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
auth = silc_auth_public_key_auth_generate(pubkey, privkey,
- conn->client->rng,
- conn->internal->sha1hash,
+ cmd->client->rng,
+ cmd->client->sha1hash,
conn->local_id,
SILC_ID_CLIENT);
mode |= SILC_CHANNEL_UMODE_CHANFO;
}
}
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
SILC_PUT32_MSB(mode, modebuf);
- clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
+ clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
/* Send the command packet. We support sending only one mode at once
that requires an argument. */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, auth ? 4 : 3,
- 1, silc_buffer_datalen(chidp),
- 2, modebuf, 4,
- 3, silc_buffer_datalen(clidp),
- 4, silc_buffer_datalen(auth));
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE,
+ ++conn->cmd_ident,
+ auth ? 4 : 3,
+ 1, chidp->data, chidp->len,
+ 2, modebuf, 4,
+ 3, clidp->data, clidp->len,
+ 4, auth ? auth->data : NULL,
+ auth ? auth->len : 0);
+
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(chidp);
silc_buffer_free(clidp);
if (auth)
silc_buffer_free(auth);
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- silc_client_unref_channel(client, conn, channel);
- silc_client_list_free(client, conn, clients);
silc_free(nickname);
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************** KICK ************************************/
-
/* KICK command. Kicks a client out of channel. */
-SILC_FSM_STATE(silc_client_command_kick)
+SILC_CLIENT_CMD_FUNC(kick)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClient client = cmd->client;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcChannelEntry channel = NULL;
- SilcBuffer idp, idp2;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, idp, idp2;
SilcClientEntry target;
- SilcDList clients = NULL;
char *name;
char *nickname = NULL;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 3) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /KICK <channel> <nickname> [<comment>]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Get the Channel ID of the channel */
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
/* Parse the typed nickname. */
- silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[2], &nickname);
+ else
+ nickname = strdup(cmd->argv[2]);
/* Get the target client */
- clients = silc_client_get_clients_local(client, conn, nickname,
- cmd->argv[2]);
- if (!clients) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ target = silc_idlist_get_client(cmd->client, conn, nickname,
+ cmd->argv[2], FALSE);
+ if (!target) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"No such client: %s", cmd->argv[2]);
COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
goto out;
}
- target = silc_dlist_get(clients);
/* Send KICK command to the server */
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
- idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
if (cmd->argc == 3)
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(idp),
- 2, silc_buffer_datalen(idp2));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
+ ++conn->cmd_ident, 2,
+ 1, idp->data, idp->len,
+ 2, idp2->data, idp2->len);
else
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(idp),
- 2, silc_buffer_datalen(idp2),
- 3, cmd->argv[3], strlen(cmd->argv[3]));
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
+ ++conn->cmd_ident, 3,
+ 1, idp->data, idp->len,
+ 2, idp2->data, idp2->len,
+ 3, cmd->argv[3],
+ strlen(cmd->argv[3]));
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(idp);
silc_buffer_free(idp2);
- silc_free(nickname);
- silc_client_list_free(client, conn, clients);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- silc_client_unref_channel(client, conn, channel);
silc_free(nickname);
- return SILC_FSM_FINISH;
-}
-
-/***************************** OPER & SILCOPER ******************************/
-
-typedef struct {
- unsigned char *passphrase;
- SilcUInt32 passphrase_len;
-} *SilcClientCommandOper;
-
-/* Ask passphrase callback */
-
-static void silc_client_command_oper_cb(unsigned char *data,
- SilcUInt32 data_len, void *context)
-{
- SilcClientCommandContext cmd = context;
- SilcClientCommandOper oper = cmd->context;
-
- if (data && data_len)
- oper->passphrase = silc_memdup(data, data_len);
- oper->passphrase_len = data_len;
-
- /* Continue */
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
+ silc_client_command_free(cmd);
}
-/* Send OPER/SILCOPER command */
-
-SILC_FSM_STATE(silc_client_command_oper_send)
+static void silc_client_command_oper_send(unsigned char *data,
+ SilcUInt32 data_len, void *context)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper = cmd->context;
- SilcBuffer auth;
+ SilcBuffer buffer, auth;
- if (!oper || !oper->passphrase) {
+ if (cmd->argc >= 3) {
/* Encode the public key authentication payload */
- auth = silc_auth_public_key_auth_generate(conn->public_key,
- conn->private_key,
- conn->client->rng,
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
conn->internal->hash,
conn->local_id,
SILC_ID_CLIENT);
} else {
/* Encode the password authentication payload */
auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
- oper->passphrase, oper->passphrase_len);
+ data, data_len);
}
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, cmd->argv[1], strlen(cmd->argv[1]),
- 2, silc_buffer_datalen(auth));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]),
+ 2, auth ? auth->data : NULL,
+ auth ? auth->len : 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_clear(auth);
silc_buffer_free(auth);
- if (oper) {
- silc_free(oper->passphrase);
- silc_free(oper);
- }
/* Notify application */
COMMAND(SILC_STATUS_OK);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
}
/* OPER command. Used to obtain server operator privileges. */
-SILC_FSM_STATE(silc_client_command_oper)
+SILC_CLIENT_CMD_FUNC(oper)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /OPER <username> [-pubkey]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ goto out;
}
- /* Get passphrase */
if (cmd->argc < 3) {
- oper = silc_calloc(1, sizeof(*oper));
- if (!oper)
- return SILC_FSM_FINISH;
- cmd->context = oper;
- SILC_FSM_CALL(conn->client->internal->
- ops->ask_passphrase(conn->client, conn,
- silc_client_command_oper_cb, cmd));
+ /* Get passphrase */
+ cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
+ silc_client_command_oper_send,
+ context);
+ return;
}
- silc_fsm_next(fsm, silc_client_command_oper_send);
- return SILC_FSM_CONTINUE;
+ silc_client_command_oper_send(NULL, 0, context);
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+static void silc_client_command_silcoper_send(unsigned char *data,
+ SilcUInt32 data_len,
+ void *context)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer, auth;
+
+ if (cmd->argc >= 3) {
+ /* Encode the public key authentication payload */
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ conn->internal->hash,
+ conn->local_id,
+ SILC_ID_CLIENT);
+ } else {
+ /* Encode the password authentication payload */
+ auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+ data, data_len);
+ }
+
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]),
+ 2, auth ? auth->data : NULL,
+ auth ? auth->len : 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+
+ silc_buffer_free(buffer);
+ silc_buffer_clear(auth);
+ silc_buffer_free(auth);
+
+ /* Notify application */
+ COMMAND(SILC_STATUS_OK);
}
/* SILCOPER command. Used to obtain router operator privileges. */
-SILC_FSM_STATE(silc_client_command_silcoper)
+SILC_CLIENT_CMD_FUNC(silcoper)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClientCommandOper oper;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /SILCOPER <username> [-pubkey]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ goto out;
}
- /* Get passphrase */
if (cmd->argc < 3) {
- oper = silc_calloc(1, sizeof(*oper));
- if (!oper)
- return SILC_FSM_FINISH;
- cmd->context = oper;
- SILC_FSM_CALL(conn->client->internal->
- ops->ask_passphrase(conn->client, conn,
- silc_client_command_oper_cb, cmd));
+ /* Get passphrase */
+ cmd->client->internal->ops->ask_passphrase(cmd->client, conn,
+ silc_client_command_silcoper_send,
+ context);
+ return;
}
- silc_fsm_next(fsm, silc_client_command_oper_send);
- return SILC_FSM_CONTINUE;
+ silc_client_command_silcoper_send(NULL, 0, context);
+
+ out:
+ silc_client_command_free(cmd);
}
-/*********************************** BAN ************************************/
-
/* Command BAN. This is used to manage the ban list of the channel. */
-SILC_FSM_STATE(silc_client_command_ban)
+SILC_CLIENT_CMD_FUNC(ban)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
SilcChannelEntry channel;
- SilcBuffer chidp, args = NULL;
+ SilcBuffer buffer, chidp, args = NULL;
char *name, *ban = NULL;
unsigned char action[1];
SilcPublicKey pubkey = NULL;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /BAN <channel> "
"[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
}
channel = conn->current_channel;
- silc_client_ref_channel(client, conn, channel);
} else {
name = cmd->argv[1];
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
action[0] = 0x01;
/* Check if it is public key file to be added to invite list */
- silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey);
+ if (!silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+ SILC_PKCS_FILE_PEM))
+ silc_pkcs_load_public_key(cmd->argv[2] + 1, &pubkey,
+ SILC_PKCS_FILE_BIN);
ban = cmd->argv[2];
if (!pubkey)
ban++;
SILC_STR_UI_SHORT(1),
SILC_STR_END);
if (pubkey) {
- chidp = silc_public_key_payload_encode(pubkey);
- args = silc_argument_payload_encode_one(args,
- silc_buffer_datalen(chidp), 2);
+ chidp = silc_pkcs_public_key_payload_encode(pubkey);
+ args = silc_argument_payload_encode_one(args, chidp->data,
+ chidp->len, 2);
silc_buffer_free(chidp);
silc_pkcs_public_key_free(pubkey);
} else {
}
}
- chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
/* Send the command */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
- 1, silc_buffer_datalen(chidp),
- 2, args ? action : NULL, args ? 1 : 0,
- 3, silc_buffer_datalen(args));
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
+ ++conn->cmd_ident, 3,
+ 1, chidp->data, chidp->len,
+ 2, args ? action : NULL,
+ args ? 1 : 0,
+ 3, args ? args->data : NULL,
+ args ? args->len : 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(chidp);
silc_buffer_free(args);
- silc_client_unref_channel(client, conn, channel);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************* DETACH ***********************************/
-
/* Command DETACH. This is used to detach from the server */
-SILC_FSM_STATE(silc_client_command_detach)
+SILC_CLIENT_CMD_FUNC(detach)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 0);
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
+ ++conn->cmd_ident, 0);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
}
-/********************************** WATCH ***********************************/
-
/* Command WATCH. */
-SILC_FSM_STATE(silc_client_command_watch)
+SILC_CLIENT_CMD_FUNC(watch)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcBuffer args = NULL;
+ SilcBuffer buffer, idp = NULL, args = NULL;
int type = 0;
const char *pubkey = NULL;
- SilcBool pubkey_add = TRUE;
+ bool pubkey_add = TRUE;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 3) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
+
if (!strcasecmp(cmd->argv[1], "-add")) {
type = 2;
} else if (!strcasecmp(cmd->argv[1], "-del")) {
if (pubkey) {
SilcPublicKey pk;
- SilcBuffer buffer;
- if (!silc_pkcs_load_public_key(pubkey, &pk)) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Could not load public key %s, check the filename", pubkey);
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_PEM)) {
+ if (!silc_pkcs_load_public_key(pubkey, &pk, SILC_PKCS_FILE_BIN)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not load public key %s, check the filename",
+ pubkey);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
}
args = silc_buffer_alloc_size(2);
silc_buffer_format(args,
SILC_STR_UI_SHORT(1),
SILC_STR_END);
- buffer = silc_public_key_payload_encode(pk);
- args = silc_argument_payload_encode_one(args, silc_buffer_datalen(buffer),
+ buffer = silc_pkcs_public_key_payload_encode(pk);
+ args = silc_argument_payload_encode_one(args, buffer->data, buffer->len,
pubkey_add ? 0x00 : 0x01);
silc_buffer_free(buffer);
silc_pkcs_public_key_free(pk);
}
- /* If watching by nickname, resolve all users with that nickname so that
- we get their information immediately. */
- if (type == 2)
- silc_client_get_clients(conn->client, conn, cmd->argv[2], NULL,
- silc_client_command_resolve_dummy, NULL);
-
- /* Send the commmand */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
- 1, silc_buffer_datalen(conn->internal->
- local_idp),
- type, pubkey ? args->data : cmd->argv[2],
- pubkey ? silc_buffer_len(args) :
- cmd->argv_lens[2]);
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
+ ++conn->cmd_ident, 2,
+ 1, idp->data, idp->len,
+ type,
+ pubkey ? args->data : cmd->argv[2],
+ pubkey ? args->len :
+ cmd->argv_lens[2]);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(args);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- return SILC_FSM_FINISH;
+ if (idp)
+ silc_buffer_free(idp);
+ silc_client_command_free(cmd);
}
-/********************************** LEAVE ***********************************/
-
/* LEAVE command. Leaves a channel. Client removes itself from a channel. */
-SILC_FSM_STATE(silc_client_command_leave)
+SILC_CLIENT_CMD_FUNC(leave)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
SilcChannelEntry channel;
- SilcBuffer idp;
+ SilcBuffer buffer, idp;
char *name;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc != 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /LEAVE <channel>");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Get the channel entry */
- channel = silc_client_get_channel(conn->client, conn, name);
+ channel = silc_client_get_channel(cmd->client, conn, name);
if (!channel) {
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
goto out;
}
- idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
-
/* Send LEAVE command to the server */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(idp));
-
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE,
+ ++conn->cmd_ident, 1,
+ 1, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(idp);
/* Notify application */
if (conn->current_channel == channel)
conn->current_channel = NULL;
- silc_client_unref_channel(client, conn, channel);
-
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************** USERS ***********************************/
-
/* Command USERS. Requests the USERS of the clients joined on requested
channel. */
-SILC_FSM_STATE(silc_client_command_users)
+SILC_CLIENT_CMD_FUNC(users)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
char *name;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc != 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /USERS <channel>");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Send USERS command to the server */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 2, name, strlen(name));
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
+ ++conn->cmd_ident, 1,
+ 2, name, strlen(name));
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, buffer->data,
+ buffer->len, TRUE);
+ silc_buffer_free(buffer);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
-
out:
- return SILC_FSM_FINISH;
+ silc_client_command_free(cmd);
}
-/********************************* GETKEY ***********************************/
-
/* Command GETKEY. Used to fetch remote client's public key. */
-SILC_FSM_STATE(silc_client_command_getkey)
+SILC_CLIENT_CMD_FUNC(getkey)
{
- SilcClientCommandContext cmd = fsm_context;
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcClientEntry client_entry;
- SilcServerEntry server_entry;
- SilcDList clients;
+ SilcClient client = cmd->client;
+ SilcClientEntry client_entry = NULL;
+ SilcServerEntry server_entry = NULL;
char *nickname = NULL;
- SilcBuffer idp;
+ SilcBuffer idp, buffer;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
if (cmd->argc < 2) {
client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /GETKEY <nickname or server name>");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ goto out;
}
/* Parse the typed nickname. */
- if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
- COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
- return SILC_FSM_FINISH;
- }
+ if (client->internal->params->nickname_parse)
+ client->internal->params->nickname_parse(cmd->argv[1], &nickname);
+ else
+ nickname = strdup(cmd->argv[1]);
/* Find client entry */
- clients = silc_client_get_clients_local(client, conn, nickname,
- cmd->argv[1]);
- if (!clients) {
- /* Check whether user requested server */
+ client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[1],
+ FALSE);
+ if (!client_entry) {
+ /* Check whether user requested server actually */
server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
+
if (!server_entry) {
- if (cmd->resolved) {
- /* Resolving didn't find anything. We should never get here as
- errors are handled in the resolving callback. */
- COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
- COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
- return SILC_FSM_FINISH;
- }
+ /* No. what ever user wants we don't have it, so resolve it. We
+ will first try to resolve the client, and if that fails then
+ we'll try to resolve the server. */
+
+ if (!cmd->pending) {
+ /* This will send the IDENTIFY command for nickname */
+ silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_getkey,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ goto out;
+ } else {
+ SilcClientCommandReplyContext reply =
+ (SilcClientCommandReplyContext)context2;
+ SilcStatus error;
+
+ /* If nickname was not found, then resolve the server. */
+ silc_command_get_status(reply->payload, NULL, &error);
+ if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ /* This sends the IDENTIFY command to resolve the server. */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
+ NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1,
+ 2, cmd->argv[1], cmd->argv_lens[1]);
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_getkey,
+ silc_client_command_dup(cmd));
+ goto out;
+ }
+
+ /* If server was not found, then we've resolved both nickname and
+ server and did not find anybody. */
+ if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
+ silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
+ silc_get_status_message(error));
+ COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
+ goto out;
+ }
- /* No client or server exist with this name, query for both. */
- cmd->resolved = TRUE;
- SILC_FSM_CALL(silc_client_command_send(client, conn,
- SILC_COMMAND_IDENTIFY,
- silc_client_command_continue,
- cmd, 2,
- 1, cmd->argv[1],
- strlen(cmd->argv[1]),
- 2, cmd->argv[1],
- strlen(cmd->argv[1])));
- /* NOT REACHED */
+ COMMAND_ERROR(error);
+ goto out;
+ }
}
- idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
- silc_client_unref_server(client, conn, server_entry);
+
+ idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
} else {
- client_entry = silc_dlist_get(clients);
- idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
- silc_client_list_free(client, conn, clients);
+ idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
}
- /* Send the commmand */
- silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
- 1, silc_buffer_datalen(idp));
-
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY,
+ ++conn->cmd_ident, 1,
+ 1, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
silc_buffer_free(idp);
- silc_free(nickname);
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_free(nickname);
+ silc_client_command_free(cmd);
}
-/********************************* SERVICE **********************************/
-
/* Command SERVICE. Negotiates service agreement with server. */
/* XXX incomplete */
-SILC_FSM_STATE(silc_client_command_service)
+SILC_CLIENT_CMD_FUNC(service)
{
- SilcClientCommandContext cmd = fsm_context;
-#if 0
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
SilcBuffer buffer;
char *name;
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
if (cmd->argc < 2) {
- SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
"Usage: /SERVICE [<service name>] [-pubkey]");
COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- return SILC_FSM_FINISH;
+ goto out;
}
name = cmd->argv[1];
buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
++conn->cmd_ident, 1,
1, name, strlen(name));
- silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
NULL, 0, NULL, NULL, buffer->data,
buffer->len, TRUE);
silc_buffer_free(buffer);
-#endif /* 0 */
/* Notify application */
COMMAND(SILC_STATUS_OK);
- /** Wait for command reply */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
+ out:
+ silc_client_command_free(cmd);
+}
+
+/* Register a new command indicated by the `command' to the SILC client.
+ The `name' is optional command name. If provided the command may be
+ searched using the silc_client_command_find by that name. The
+ `command_function' is the function to be called when the command is
+ executed, and the `command_reply_function' is the function to be
+ called after the server has sent reply back to the command.
+
+ The `ident' is optional identifier for the command. If non-zero
+ the `command_reply_function' for the command type `command' will be
+ called only if the command reply sent by server includes the
+ command identifier `ident'. Application usually does not need it
+ and set it to zero value. */
+
+bool silc_client_command_register(SilcClient client,
+ SilcCommand command,
+ const char *name,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ SilcUInt8 max_args,
+ SilcUInt16 ident)
+{
+ SilcClientCommand cmd;
+
+ cmd = silc_calloc(1, sizeof(*cmd));
+ cmd->cmd = command;
+ cmd->command = command_function;
+ cmd->reply = command_reply_function;
+ cmd->name = name ? strdup(name) : NULL;
+ cmd->max_args = max_args;
+ cmd->ident = ident;
+
+ silc_list_add(client->internal->commands, cmd);
+
+ return TRUE;
+}
+
+/* Unregister a command indicated by the `command' with command function
+ `command_function' and command reply function `command_reply_function'.
+ Returns TRUE if the command was found and unregistered. */
+
+bool silc_client_command_unregister(SilcClient client,
+ SilcCommand command,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ SilcUInt16 ident)
+{
+ SilcClientCommand cmd;
+
+ silc_list_start(client->internal->commands);
+ while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
+ if (cmd->cmd == command && cmd->command == command_function &&
+ cmd->reply == command_reply_function && cmd->ident == ident) {
+ silc_list_del(client->internal->commands, cmd);
+ silc_free(cmd->name);
+ silc_free(cmd);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Private range commands, specific to this implementation (and compatible
+ with SILC Server). */
+
+/* CONNECT command. Connects the server to another server. */
+
+SILC_CLIENT_CMD_FUNC(connect)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+ unsigned char port[4];
+ SilcUInt32 tmp;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ if (cmd->argc < 2) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Usage: /CONNECT <server> [<port>]");
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ if (cmd->argc == 3) {
+ tmp = atoi(cmd->argv[2]);
+ SILC_PUT32_MSB(tmp, port);
+ }
+
+ if (cmd->argc == 3)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]),
+ 2, port, 4);
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT,
+ ++conn->cmd_ident, 1,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]));
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+
+ /* Notify application */
+ COMMAND(SILC_STATUS_OK);
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+
+/* CLOSE command. Close server connection to the remote server */
+
+SILC_CLIENT_CMD_FUNC(close)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+ unsigned char port[4];
+ SilcUInt32 tmp;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ if (cmd->argc < 2) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Usage: /CLOSE <server> [<port>]");
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ if (cmd->argc == 3) {
+ tmp = atoi(cmd->argv[2]);
+ SILC_PUT32_MSB(tmp, port);
+ }
+
+ if (cmd->argc == 3)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
+ ++conn->cmd_ident, 2,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]),
+ 2, port, 4);
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE,
+ ++conn->cmd_ident, 1,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]));
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+
+ /* Notify application */
+ COMMAND(SILC_STATUS_OK);
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+/* SHUTDOWN command. Shutdowns the server. */
+
+SILC_CLIENT_CMD_FUNC(shutdown)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
+ goto out;
+ }
+
+ /* Send the command */
+ silc_client_command_send(cmd->client, cmd->conn,
+ SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
+
+ /* Notify application */
+ COMMAND(SILC_STATUS_OK);
+
+ out:
+ silc_client_command_free(cmd);
}
/* Register all default commands provided by the client library for the
SILC_CLIENT_CMD(users, USERS, "USERS", 2);
SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
+
+ SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
+ SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
+ SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
}
/* Unregister all commands. */
SILC_CLIENT_CMDU(users, USERS, "USERS");
SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
-}
-
-/****************** Client Side Incoming Command Handling *******************/
-
-/* Reply to WHOIS command from server */
-
-static void silc_client_command_process_whois(SilcClient client,
- SilcClientConnection conn,
- SilcCommandPayload payload,
- SilcArgumentPayload args)
-{
- SilcDList attrs;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
- SilcBuffer buffer, packet;
-
- SILC_LOG_DEBUG(("Received WHOIS command"));
-
- /* Try to take the Requested Attributes */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (!tmp)
- return;
-
- attrs = silc_attribute_payload_parse(tmp, tmp_len);
- if (!attrs)
- return;
-
- /* Process requested attributes */
- buffer = silc_client_attributes_process(client, conn, attrs);
- if (!buffer) {
- silc_attribute_payload_list_free(attrs);
- return;
- }
-
- /* Send the attributes back in COMMAND_REPLY packet */
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- SILC_STATUS_OK, 0,
- silc_command_get_ident(payload),
- 1, 11, buffer->data,
- silc_buffer_len(buffer));
- if (!packet) {
- silc_buffer_free(buffer);
- return;
- }
- SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
+ SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
+ SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
+ SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
+}
- silc_packet_send(conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
- silc_buffer_datalen(packet));
+/**** Client side incoming command handling **********************************/
- silc_buffer_free(packet);
- silc_buffer_free(buffer);
-}
+void silc_client_command_process_whois(SilcClient client,
+ SilcSocketConnection sock,
+ SilcCommandPayload payload,
+ SilcArgumentPayload args);
/* Client is able to receive some command packets even though they are
special case. Server may send WHOIS command to the client to retrieve
Requested Attributes information for WHOIS query the server is
processing. This function currently handles only the WHOIS command,
- but if in the future more commands may arrive then this can be made
+ but if in the future for commands may arrive then this can be made
to support other commands too. */
-SILC_FSM_STATE(silc_client_command)
+void silc_client_command_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
- SilcPacket packet = state_context;
SilcCommandPayload payload;
SilcCommand command;
SilcArgumentPayload args;
/* Get command payload from packet */
- payload = silc_command_payload_parse(packet->buffer.data,
- silc_buffer_len(&packet->buffer));
+ payload = silc_command_payload_parse(packet->buffer->data,
+ packet->buffer->len);
if (!payload) {
+ /* Silently ignore bad reply packet */
SILC_LOG_DEBUG(("Bad command packet"));
- return SILC_FSM_FINISH;
+ return;
}
/* Get arguments */
case SILC_COMMAND_WHOIS:
/* Ignore everything if requested by application */
- if (conn->internal->params.ignore_requested_attributes)
+ if (client->internal->params->ignore_requested_attributes)
break;
- silc_client_command_process_whois(client, conn, payload, args);
+ silc_client_command_process_whois(client, sock, payload, args);
break;
default:
}
silc_command_payload_free(payload);
- return SILC_FSM_FINISH;
+}
+
+void silc_client_command_process_whois(SilcClient client,
+ SilcSocketConnection sock,
+ SilcCommandPayload payload,
+ SilcArgumentPayload args)
+{
+ SilcDList attrs;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+ SilcBuffer buffer, packet;
+
+ SILC_LOG_DEBUG(("Received WHOIS command"));
+
+ /* Try to take the Requested Attributes */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ return;
+
+ attrs = silc_attribute_payload_parse(tmp, tmp_len);
+ if (!attrs)
+ return;
+
+ /* Process requested attributes */
+ buffer = silc_client_attributes_process(client, sock, attrs);
+ if (!buffer) {
+ silc_attribute_payload_list_free(attrs);
+ return;
+ }
+
+ /* Send the attributes back */
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+ SILC_STATUS_OK, 0,
+ silc_command_get_ident(payload),
+ 1, 11, buffer->data, buffer->len);
+ silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
+ NULL, 0, NULL, NULL, packet->data,
+ packet->len, TRUE);
+ silc_buffer_free(packet);
+ silc_buffer_free(buffer);
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2006 - 2007 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
#ifndef COMMAND_H
#define COMMAND_H
-SILC_FSM_STATE(silc_client_command);
-SILC_FSM_STATE(silc_client_command_whois);
-SILC_FSM_STATE(silc_client_command_whowas);
-SILC_FSM_STATE(silc_client_command_identify);
-SILC_FSM_STATE(silc_client_command_nick);
-SILC_FSM_STATE(silc_client_command_list);
-SILC_FSM_STATE(silc_client_command_topic);
-SILC_FSM_STATE(silc_client_command_invite);
-SILC_FSM_STATE(silc_client_command_quit);
-SILC_FSM_STATE(silc_client_command_kill);
-SILC_FSM_STATE(silc_client_command_info);
-SILC_FSM_STATE(silc_client_command_ping);
-SILC_FSM_STATE(silc_client_command_oper);
-SILC_FSM_STATE(silc_client_command_join);
-SILC_FSM_STATE(silc_client_command_motd);
-SILC_FSM_STATE(silc_client_command_umode);
-SILC_FSM_STATE(silc_client_command_cmode);
-SILC_FSM_STATE(silc_client_command_cumode);
-SILC_FSM_STATE(silc_client_command_kick);
-SILC_FSM_STATE(silc_client_command_ban);
-SILC_FSM_STATE(silc_client_command_detach);
-SILC_FSM_STATE(silc_client_command_watch);
-SILC_FSM_STATE(silc_client_command_silcoper);
-SILC_FSM_STATE(silc_client_command_leave);
-SILC_FSM_STATE(silc_client_command_users);
-SILC_FSM_STATE(silc_client_command_getkey);
-SILC_FSM_STATE(silc_client_command_service);
-
-SilcUInt16 silc_client_command_send_argv(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc,
- unsigned char **argv,
- SilcUInt32 *argv_lens,
- SilcUInt32 *argv_types);
+#include "command_reply.h"
+
+/* Structure holding one command and pointer to its function. This
+ structure is allocate into the commands list, and is returned
+ for example by silc_client_command_find function.
+
+ To call a command: command->command(cmd, NULL);
+ To call a command reply: command->reply(cmd, NULL);
+
+*/
+struct SilcClientCommandStruct {
+ SilcCommand cmd; /* Command type */
+ SilcCommandCb command; /* Command function */
+ SilcCommandCb reply; /* Command reply callback */
+ char *name; /* Name of the command (optional) */
+ SilcUInt8 max_args; /* Maximum arguments (optional) */
+ SilcUInt16 ident; /* Identifier for command (optional) */
+ struct SilcClientCommandStruct *next;
+};
+
+/* Context sent as argument to all commands. This is used by the library
+ and application should use this as well. However, application may
+ choose to use some own context for its own local command. All library
+ commands, however, must use this context. */
+struct SilcClientCommandContextStruct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcClientCommand command;
+ SilcUInt32 argc;
+ unsigned char **argv;
+ SilcUInt32 *argv_lens;
+ SilcUInt32 *argv_types;
+ int pending; /* Command is being re-processed when TRUE */
+ int users; /* Reference counter */
+};
+
+/* Structure holding pending commands. If command is pending it will be
+ executed after command reply has been executed. */
+typedef struct SilcClientCommandPendingStruct {
+ SilcCommand reply_cmd;
+ SilcUInt16 ident;
+ unsigned int reply_check : 8;
+ SilcCommandCb callback;
+ void *context;
+ struct SilcClientCommandPendingStruct *next;
+} SilcClientCommandPending;
+
+/* List of pending commands */
+extern SilcClientCommandPending *silc_command_pending;
+
+
+/* Macros */
+
+/* Macro used for command registering and unregistering */
+#define SILC_CLIENT_CMD(func, cmd, name, args) \
+silc_client_command_register(client, SILC_COMMAND_##cmd, name, \
+ silc_client_command_##func, \
+ silc_client_command_reply_##func, args, 0)
+#define SILC_CLIENT_CMDU(func, cmd, name) \
+silc_client_command_unregister(client, SILC_COMMAND_##cmd, \
+ silc_client_command_##func, \
+ silc_client_command_reply_##func, 0)
+
+/* Macro used to declare command functions */
+#define SILC_CLIENT_CMD_FUNC(func) \
+void silc_client_command_##func(void *context, void *context2)
+
+/* Executed pending command callback */
+#define SILC_CLIENT_PENDING_EXEC(ctx, cmd) \
+do { \
+ int _i; \
+ for (_i = 0; _i < ctx->callbacks_count; _i++) \
+ if (ctx->callbacks[_i].callback) \
+ (*ctx->callbacks[_i].callback)(ctx->callbacks[_i].context, ctx); \
+ silc_client_command_pending_del(ctx->sock->user_data, cmd, ctx->ident); \
+} while(0)
+
+SilcClientCommandContext silc_client_command_alloc(void);
+void silc_client_command_free(SilcClientCommandContext ctx);
+SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx);
+SilcClientCommand silc_client_command_find(SilcClient client,
+ const char *name);
+bool silc_client_command_register(SilcClient client,
+ SilcCommand command,
+ const char *name,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ SilcUInt8 max_args,
+ SilcUInt16 ident);
+bool silc_client_command_unregister(SilcClient client,
+ SilcCommand command,
+ SilcCommandCb command_function,
+ SilcCommandCb command_reply_function,
+ SilcUInt16 ident);
void silc_client_commands_register(SilcClient client);
void silc_client_commands_unregister(SilcClient client);
-SilcBool silc_client_command_called_dummy(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap);
-void silc_client_command_resolve_dummy(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context);
-
-#endif /* COMMAND_H */
+void silc_client_command_pending_del(SilcClientConnection conn,
+ SilcCommand reply_cmd,
+ SilcUInt16 ident);
+SilcClientCommandPendingCallbacks
+silc_client_command_pending_check(SilcClientConnection conn,
+ SilcClientCommandReplyContext ctx,
+ SilcCommand command,
+ SilcUInt16 ident,
+ SilcUInt32 *callbacks_count);
+void silc_client_command_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+SILC_CLIENT_CMD_FUNC(whois);
+SILC_CLIENT_CMD_FUNC(whowas);
+SILC_CLIENT_CMD_FUNC(identify);
+SILC_CLIENT_CMD_FUNC(nick);
+SILC_CLIENT_CMD_FUNC(list);
+SILC_CLIENT_CMD_FUNC(topic);
+SILC_CLIENT_CMD_FUNC(invite);
+SILC_CLIENT_CMD_FUNC(quit);
+SILC_CLIENT_CMD_FUNC(kill);
+SILC_CLIENT_CMD_FUNC(info);
+SILC_CLIENT_CMD_FUNC(ping);
+SILC_CLIENT_CMD_FUNC(oper);
+SILC_CLIENT_CMD_FUNC(join);
+SILC_CLIENT_CMD_FUNC(motd);
+SILC_CLIENT_CMD_FUNC(umode);
+SILC_CLIENT_CMD_FUNC(cmode);
+SILC_CLIENT_CMD_FUNC(cumode);
+SILC_CLIENT_CMD_FUNC(kick);
+SILC_CLIENT_CMD_FUNC(ban);
+SILC_CLIENT_CMD_FUNC(detach);
+SILC_CLIENT_CMD_FUNC(watch);
+SILC_CLIENT_CMD_FUNC(silcoper);
+SILC_CLIENT_CMD_FUNC(leave);
+SILC_CLIENT_CMD_FUNC(users);
+SILC_CLIENT_CMD_FUNC(getkey);
+SILC_CLIENT_CMD_FUNC(service);
+
+SILC_CLIENT_CMD_FUNC(shutdown);
+SILC_CLIENT_CMD_FUNC(close);
+SILC_CLIENT_CMD_FUNC(connect);
+
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-
-#include "silc.h"
+/*
+ * Command reply functions are "the otherside" of the command functions.
+ * Reply to a command sent by server is handled by these functions.
+ *
+ * The arguments received from server are also passed to the calling
+ * application through command_reply client operation. The arguments are
+ * exactly same and in same order as the server sent it. However, ID's are
+ * not sent to the application. Instead, corresponding ID entry is sent
+ * to the application. For example, instead of sending Client ID the
+ * corresponding SilcClientEntry is sent to the application. The case is
+ * same with for example Channel ID's. This way application has all the
+ * necessary data already in hand without redundant searching. If ID is
+ * received but ID entry does not exist, NULL is sent.
+ */
+
+#include "silcincludes.h"
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
+#define SAY cmd->client->internal->ops->say
-/* Calls error command reply callback back to command sender. */
-#define ERROR_CALLBACK(err) \
+/* All functions that call the COMMAND_CHECK_STATUS macro must have
+ out: and err: goto labels. out label should call the pending
+ command replies, and the err label just handle error condition. */
+
+#define COMMAND_CHECK_STATUS \
do { \
- void *arg1 = NULL, *arg2 = NULL; \
- if (cmd->status != SILC_STATUS_OK) \
- silc_status_get_args(cmd->status, args, &arg1, &arg2); \
- else \
- cmd->status = cmd->error = err; \
- SILC_LOG_DEBUG(("Error in command reply: %s", \
- silc_get_status_message(cmd->status))); \
- silc_client_command_callback(cmd, arg1, arg2); \
+ SILC_LOG_DEBUG(("Start")); \
+ if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
+ if (SILC_STATUS_IS_ERROR(cmd->status)) { \
+ /* Single error */ \
+ COMMAND_REPLY_ERROR(cmd->status); \
+ goto out; \
+ } \
+ /* List of errors */ \
+ COMMAND_REPLY_ERROR(cmd->error); \
+ if (cmd->status == SILC_STATUS_LIST_END) \
+ goto out; \
+ goto err; \
+ } \
} while(0)
-/* Check for error */
-#define CHECK_STATUS(msg) \
- SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
- if (cmd->error != SILC_STATUS_OK) { \
- if (cmd->verbose) \
- SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, \
- msg "%s", silc_get_status_message(cmd->error)); \
- ERROR_CALLBACK(cmd->error); \
- silc_client_command_process_error(cmd, state_context, cmd->error); \
- silc_fsm_next(fsm, silc_client_command_reply_processed); \
- return SILC_FSM_CONTINUE; \
- }
-
-/* Check for correct arguments */
-#define CHECK_ARGS(min, max) \
- if (silc_argument_get_arg_num(args) < min || \
- silc_argument_get_arg_num(args) > max) { \
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
- silc_fsm_next(fsm, silc_client_command_reply_processed); \
- return SILC_FSM_CONTINUE; \
- }
-
-#define SAY cmd->conn->client->internal->ops->say
-
-/************************ Static utility functions **************************/
-
-/* Delivers the command reply back to application */
-
-static inline void
-silc_client_command_callback(SilcClientCommandContext cmd, ...)
-{
- SilcClientCommandReplyCallback cb;
- SilcList list;
- va_list ap, cp;
-
- va_start(ap, cmd);
-
- /* Default reply callback */
- if (cmd->called) {
- silc_va_copy(cp, ap);
- cmd->conn->client->internal->ops->command_reply(
- cmd->conn->client, cmd->conn, cmd->cmd, cmd->status,
- cmd->error, cp);
- va_end(cp);
- }
-
- /* Reply callback */
- list = cmd->reply_callbacks;
- silc_list_start(list);
- while ((cb = silc_list_get(list)))
- if (!cb->do_not_call) {
- silc_va_copy(cp, ap);
- cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
- cmd->status, cmd->error, cb->context, cp);
- va_end(cp);
- }
-
- va_end(ap);
-}
-
-/* Handles common error status types. */
-
-static void silc_client_command_process_error(SilcClientCommandContext cmd,
- SilcCommandPayload payload,
- SilcStatus error)
-{
- SilcClient client = cmd->conn->client;
- SilcClientConnection conn = cmd->conn;
- SilcArgumentPayload args = silc_command_get_args(payload);
- SilcID id;
-
- if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
- SilcClientEntry client_entry;
-
- /* Remove unknown client entry from cache */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
- return;
-
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry) {
- silc_client_remove_from_channels(client, conn, client_entry);
- silc_client_del_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry);
- }
- return;
- }
-
- if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
- SilcChannelEntry channel;
-
- /* Remove unknown client entry from cache */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
- return;
-
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (channel) {
- silc_client_empty_channel(client, conn, channel);
- silc_client_del_channel(client, conn, channel);
- silc_client_unref_channel(client, conn, channel);
- }
- return;
- }
-
- if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
- SilcServerEntry server_entry;
-
- /* Remove unknown client entry from cache */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
- return;
-
- server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
- if (server_entry) {
- silc_client_del_server(client, conn, server_entry);
- silc_client_unref_server(client, conn, server_entry);
- }
- return;
- }
-}
-
-/***************************** Command Reply ********************************/
+/* Same as COMMAND_CHECK_STATUS but doesn't call client operation */
+#define COMMAND_CHECK_STATUS_I \
+do { \
+ SILC_LOG_DEBUG(("Start")); \
+ if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
+ if (SILC_STATUS_IS_ERROR(cmd->status)) \
+ goto out; \
+ if (cmd->status == SILC_STATUS_LIST_END) \
+ goto out; \
+ goto err; \
+ } \
+} while(0)
-/* Process received command reply packet */
+/* Process received command reply. */
-SILC_FSM_STATE(silc_client_command_reply)
+void silc_client_command_reply_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- SilcClientConnection conn = fsm_context;
- SilcPacket packet = state_context;
- SilcClientCommandContext cmd;
+ SilcBuffer buffer = packet->buffer;
+ SilcClientCommand cmd;
+ SilcClientCommandReplyContext ctx;
SilcCommandPayload payload;
SilcCommand command;
- SilcUInt16 cmd_ident;
+ SilcCommandCb reply = NULL;
/* Get command reply payload from packet */
- payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
- silc_packet_free(packet);
+ payload = silc_command_payload_parse(buffer->data, buffer->len);
if (!payload) {
+ /* Silently ignore bad reply packet */
SILC_LOG_DEBUG(("Bad command reply packet"));
- return SILC_FSM_FINISH;
+ return;
}
- cmd_ident = silc_command_get_ident(payload);
- command = silc_command_get(payload);
-
- /* Find the command pending reply */
- silc_mutex_lock(conn->internal->lock);
- silc_list_start(conn->internal->pending_commands);
- while ((cmd = silc_list_get(conn->internal->pending_commands))) {
- if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
- && cmd->cmd_ident == cmd_ident) {
- silc_list_del(conn->internal->pending_commands, cmd);
+ /* Allocate command reply context. This must be free'd by the
+ command reply routine receiving it. */
+ ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->users++;
+ ctx->client = client;
+ ctx->sock = sock;
+ ctx->payload = payload;
+ ctx->args = silc_command_get_args(ctx->payload);
+ ctx->packet = packet;
+ ctx->ident = silc_command_get_ident(ctx->payload);
+ silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
+
+ /* Check for pending commands and mark to be exeucted */
+ ctx->callbacks =
+ silc_client_command_pending_check(sock->user_data, ctx,
+ silc_command_get(ctx->payload),
+ ctx->ident, &ctx->callbacks_count);
+
+ /* Execute command reply */
+
+ command = silc_command_get(ctx->payload);
+
+ /* Try to find matching the command identifier */
+ silc_list_start(client->internal->commands);
+ while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
+ if (cmd->cmd == command && !cmd->ident)
+ reply = cmd->reply;
+ if (cmd->cmd == command && cmd->ident == ctx->ident) {
+ (*cmd->reply)((void *)ctx, NULL);
break;
}
}
- silc_mutex_unlock(conn->internal->lock);
- if (!cmd) {
- SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
- silc_get_command_name(command), cmd_ident));
- silc_command_payload_free(payload);
- return SILC_FSM_FINISH;
+ if (cmd == SILC_LIST_END) {
+ if (reply)
+ /* No specific identifier for command reply, call first one found */
+ (*reply)(ctx, NULL);
+ else
+ silc_free(ctx);
}
-
- /* Signal command thread that command reply has arrived. We continue
- command reply processing synchronously because we save the command
- payload into state context. No other reply may arrive to this command
- while we're processing this reply. */
- silc_fsm_set_state_context(&cmd->thread, payload);
- silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
- silc_fsm_continue_sync(&cmd->thread);
-
- return SILC_FSM_FINISH;
}
-/* Wait here for command reply to arrive from remote host */
+/* Duplicate Command Reply Context by adding reference counter. The context
+ won't be free'd untill it hits zero. */
-SILC_FSM_STATE(silc_client_command_reply_wait)
+SilcClientCommandReplyContext
+silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
{
- SilcClientCommandContext cmd = fsm_context;
-
- SILC_LOG_DEBUG(("Wait for command reply"));
-
- /** Wait for command reply */
- silc_fsm_set_state_context(fsm, NULL);
- silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
- cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
- return SILC_FSM_WAIT;
-}
-
-/* Timeout occurred while waiting command reply */
-
-SILC_FSM_STATE(silc_client_command_reply_timeout)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcArgumentPayload args = NULL;
-
- if (conn->internal->disconnected) {
- SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
- silc_list_del(conn->internal->pending_commands, cmd);
- if (!cmd->called)
- ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
- return SILC_FSM_FINISH;
- }
-
- SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
-
- /* Timeout, reply not received in timely fashion */
- silc_list_del(conn->internal->pending_commands, cmd);
- ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
- return SILC_FSM_FINISH;
+ cmd->users++;
+ SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
+ cmd->users - 1, cmd->users));
+ return cmd;
}
-/* Process received command reply payload */
+/* Free command reply context and its internals. */
-SILC_FSM_STATE(silc_client_command_reply_process)
+void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
-
- silc_command_get_status(payload, &cmd->status, &cmd->error);
-
- switch (cmd->cmd) {
- case SILC_COMMAND_WHOIS:
- /** WHOIS */
- silc_fsm_next(fsm, silc_client_command_reply_whois);
- break;
- case SILC_COMMAND_WHOWAS:
- /** WHOWAS */
- silc_fsm_next(fsm, silc_client_command_reply_whowas);
- break;
- case SILC_COMMAND_IDENTIFY:
- /** IDENTIFY */
- silc_fsm_next(fsm, silc_client_command_reply_identify);
- break;
- case SILC_COMMAND_NICK:
- /** NICK */
- silc_fsm_next(fsm, silc_client_command_reply_nick);
- break;
- case SILC_COMMAND_LIST:
- /** LIST */
- silc_fsm_next(fsm, silc_client_command_reply_list);
- break;
- case SILC_COMMAND_TOPIC:
- /** TOPIC */
- silc_fsm_next(fsm, silc_client_command_reply_topic);
- break;
- case SILC_COMMAND_INVITE:
- /** INVITE */
- silc_fsm_next(fsm, silc_client_command_reply_invite);
- break;
- case SILC_COMMAND_QUIT:
- /** QUIT */
- silc_fsm_next(fsm, silc_client_command_reply_quit);
- break;
- case SILC_COMMAND_KILL:
- /** KILL */
- silc_fsm_next(fsm, silc_client_command_reply_kill);
- break;
- case SILC_COMMAND_INFO:
- /** INFO */
- silc_fsm_next(fsm, silc_client_command_reply_info);
- break;
- case SILC_COMMAND_STATS:
- /** STATS */
- silc_fsm_next(fsm, silc_client_command_reply_stats);
- break;
- case SILC_COMMAND_PING:
- /** PING */
- silc_fsm_next(fsm, silc_client_command_reply_ping);
- break;
- case SILC_COMMAND_OPER:
- /** OPER */
- silc_fsm_next(fsm, silc_client_command_reply_oper);
- break;
- case SILC_COMMAND_JOIN:
- /** JOIN */
- silc_fsm_next(fsm, silc_client_command_reply_join);
- break;
- case SILC_COMMAND_MOTD:
- /** MOTD */
- silc_fsm_next(fsm, silc_client_command_reply_motd);
- break;
- case SILC_COMMAND_UMODE:
- /** UMODE */
- silc_fsm_next(fsm, silc_client_command_reply_umode);
- break;
- case SILC_COMMAND_CMODE:
- /** CMODE */
- silc_fsm_next(fsm, silc_client_command_reply_cmode);
- break;
- case SILC_COMMAND_CUMODE:
- /** CUMODE */
- silc_fsm_next(fsm, silc_client_command_reply_cumode);
- break;
- case SILC_COMMAND_KICK:
- /** KICK */
- silc_fsm_next(fsm, silc_client_command_reply_kick);
- break;
- case SILC_COMMAND_BAN:
- /** BAN */
- silc_fsm_next(fsm, silc_client_command_reply_ban);
- break;
- case SILC_COMMAND_DETACH:
- /** DETACH */
- silc_fsm_next(fsm, silc_client_command_reply_detach);
- break;
- case SILC_COMMAND_WATCH:
- /** WATCH */
- silc_fsm_next(fsm, silc_client_command_reply_watch);
- break;
- case SILC_COMMAND_SILCOPER:
- /** SILCOPER */
- silc_fsm_next(fsm, silc_client_command_reply_silcoper);
- break;
- case SILC_COMMAND_LEAVE:
- /** LEAVE */
- silc_fsm_next(fsm, silc_client_command_reply_leave);
- break;
- case SILC_COMMAND_USERS:
- /** USERS */
- silc_fsm_next(fsm, silc_client_command_reply_users);
- break;
- case SILC_COMMAND_GETKEY:
- /** GETKEY */
- silc_fsm_next(fsm, silc_client_command_reply_getkey);
- break;
- case SILC_COMMAND_SERVICE:
- /** SERVICE */
- silc_fsm_next(fsm, silc_client_command_reply_service);
- break;
- default:
- return SILC_FSM_FINISH;
+ cmd->users--;
+ SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
+ cmd->users + 1, cmd->users));
+ if (cmd->users < 1) {
+ silc_command_payload_free(cmd->payload);
+ silc_free(cmd);
}
-
- return SILC_FSM_CONTINUE;
-}
-
-/* Completes command reply processing */
-
-SILC_FSM_STATE(silc_client_command_reply_processed)
-{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcCommandPayload payload = state_context;
-
- silc_command_payload_free(payload);
-
- if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
- SILC_STATUS_IS_ERROR(cmd->status))
- return SILC_FSM_FINISH;
-
- /* Add back to pending command reply list */
- silc_mutex_lock(conn->internal->lock);
- cmd->resolved = FALSE;
- silc_list_add(conn->internal->pending_commands, cmd);
- silc_mutex_unlock(conn->internal->lock);
-
- /** Wait more command payloads */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
}
-/******************************** WHOIS *************************************/
-
-/* Received reply for WHOIS command. */
-
-SILC_FSM_STATE(silc_client_command_reply_whois)
+void
+silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
+ SilcStatus status,
+ bool notify)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClientID *client_id;
SilcClientEntry client_entry = NULL;
- SilcUInt32 idle = 0, mode = 0, fingerprint_len, len, *umodes = NULL;
+ SilcUInt32 len;
+ unsigned char *id_data, *tmp;
+ char *nickname = NULL, *username = NULL;
+ char *realname = NULL;
+ SilcUInt32 idle = 0, mode = 0;
SilcBufferStruct channels, ch_user_modes;
- SilcBool has_channels = FALSE;
- SilcDList channel_list = NULL;
- SilcID id;
- char *nickname = NULL, *username = NULL, *realname = NULL;
- unsigned char *fingerprint, *tmp;
-
- CHECK_STATUS("WHOIS: ");
- CHECK_ARGS(5, 11);
+ bool has_channels = FALSE, has_user_modes = FALSE;
+ unsigned char *fingerprint;
+ SilcUInt32 fingerprint_len;
+
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!id_data) {
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
+ }
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ client_id = silc_id_payload_parse_id(id_data, len, NULL);
+ if (!client_id) {
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- /* Get names */
- nickname = silc_argument_get_arg_type(args, 3, NULL);
- username = silc_argument_get_arg_type(args, 4, NULL);
- realname = silc_argument_get_arg_type(args, 5, NULL);
+ nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
+ username = silc_argument_get_arg_type(cmd->args, 4, &len);
+ realname = silc_argument_get_arg_type(cmd->args, 5, &len);
if (!nickname || !username || !realname) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- /* Get joined channel list */
- memset(&channels, 0, sizeof(channels));
- tmp = silc_argument_get_arg_type(args, 6, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
if (tmp) {
- has_channels = TRUE;
silc_buffer_set(&channels, tmp, len);
-
- /* Get channel user mode list */
- tmp = silc_argument_get_arg_type(args, 10, &len);
- if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- silc_buffer_set(&ch_user_modes, tmp, len);
+ has_channels = TRUE;
}
- /* Get user mode */
- tmp = silc_argument_get_arg_type(args, 7, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
if (tmp)
SILC_GET32_MSB(mode, tmp);
- /* Get idle time */
- tmp = silc_argument_get_arg_type(args, 8, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
if (tmp)
SILC_GET32_MSB(idle, tmp);
- /* Get fingerprint */
- fingerprint = silc_argument_get_arg_type(args, 9, &fingerprint_len);
+ fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
+
+ tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
+ if (tmp) {
+ silc_buffer_set(&ch_user_modes, tmp, len);
+ has_user_modes = TRUE;
+ }
/* Check if we have this client cached already. */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
if (!client_entry) {
- SILC_LOG_DEBUG(("Adding new client entry (WHOIS)"));
+ SILC_LOG_DEBUG(("Adding new client entry"));
client_entry =
- silc_client_add_client(client, conn, nickname, username, realname,
- &id.u.client_id, mode);
+ silc_client_add_client(cmd->client, conn, nickname, username, realname,
+ client_id, mode);
if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
- goto out;
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- silc_client_ref_client(client, conn, client_entry);
} else {
- silc_client_update_client(client, conn, client_entry,
+ silc_client_update_client(cmd->client, conn, client_entry,
nickname, username, realname, mode);
+ silc_free(client_id);
}
- silc_rwlock_wrlock(client_entry->internal.lock);
-
- if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
- memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
+ if (fingerprint && !client_entry->fingerprint) {
+ client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
+ client_entry->fingerprint_len = fingerprint_len;
+ }
- /* Get user attributes */
- tmp = silc_argument_get_arg_type(args, 11, &len);
+ /* Take Requested Attributes if set. */
+ tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
if (tmp) {
if (client_entry->attrs)
silc_attribute_payload_list_free(client_entry->attrs);
client_entry->attrs = silc_attribute_payload_parse(tmp, len);
}
- silc_rwlock_unlock(client_entry->internal.lock);
-
- /* Parse channel and channel user mode list */
- if (has_channels) {
- channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
- silc_buffer_len(&channels));
- if (channel_list)
- silc_get_mode_list(&ch_user_modes, silc_dlist_count(channel_list),
- &umodes);
- }
+ client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
/* Notify application */
- silc_client_command_callback(cmd, client_entry, nickname, username,
- realname, channel_list, mode, idle, fingerprint,
- umodes, client_entry->attrs);
+ if (!cmd->callbacks_count && notify)
+ COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname,
+ has_channels ? &channels : NULL, mode, idle,
+ fingerprint, has_user_modes ? &ch_user_modes : NULL,
+ client_entry->attrs));
+}
+
+/* Received reply for WHOIS command. This maybe called several times
+ for one WHOIS command as server may reply with list of results. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(whois)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ COMMAND_CHECK_STATUS;
- silc_client_unref_client(client, conn, client_entry);
- if (has_channels) {
- silc_channel_payload_list_free(channel_list);
- silc_free(umodes);
+ /* Save WHOIS info */
+ silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
}
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
-}
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
+
+ err:
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
-/******************************** WHOWAS ************************************/
+ silc_client_command_reply_free(cmd);
+}
/* Received reply for WHOWAS command. */
-SILC_FSM_STATE(silc_client_command_reply_whowas)
+SILC_CLIENT_CMD_REPLY_FUNC(whowas)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClientID *client_id;
SilcClientEntry client_entry = NULL;
- SilcID id;
+ SilcUInt32 len;
+ unsigned char *id_data;
char *nickname, *username;
char *realname = NULL;
- CHECK_STATUS("WHOWAS: ");
- CHECK_ARGS(4, 5);
+ COMMAND_CHECK_STATUS;
- /* Get Client ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!id_data) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ client_id = silc_id_payload_parse_id(id_data, len, NULL);
+ if (!client_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- /* Get the client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
+ /* Get the client entry, if exists */
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+ silc_free(client_id);
- /* Get names */
- nickname = silc_argument_get_arg_type(args, 3, NULL);
- username = silc_argument_get_arg_type(args, 4, NULL);
- realname = silc_argument_get_arg_type(args, 5, NULL);
+ nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
+ username = silc_argument_get_arg_type(cmd->args, 4, &len);
+ realname = silc_argument_get_arg_type(cmd->args, 5, &len);
if (!nickname || !username) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Notify application. We don't save any history information to any
- cache. Just pass the data to the application. */
- silc_client_command_callback(cmd, client_entry, nickname, username,
- realname);
+ cache. Just pass the data to the application for displaying on
+ the screen. */
+ COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname));
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
out:
- silc_client_unref_client(client, conn, client_entry);
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+ err:
+ silc_client_command_reply_free(cmd);
}
-/******************************** IDENTIFY **********************************/
-
-/* Received reply for IDENTIFY command. */
-
-SILC_FSM_STATE(silc_client_command_reply_identify)
+static void
+silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
+ SilcStatus status,
+ bool notify)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClient client = cmd->client;
+ SilcClientID *client_id = NULL;
+ SilcServerID *server_id = NULL;
+ SilcChannelID *channel_id = NULL;
SilcClientEntry client_entry;
SilcServerEntry server_entry;
SilcChannelEntry channel_entry;
SilcUInt32 len;
- SilcID id;
+ unsigned char *id_data;
char *name = NULL, *info = NULL;
+ SilcIDPayload idp = NULL;
+ SilcIdType id_type;
- CHECK_STATUS("IDENTIFY: ");
- CHECK_ARGS(2, 4);
-
- /* Get the ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!id_data) {
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
+ }
+ idp = silc_id_payload_parse(id_data, len);
+ if (!idp) {
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- /* Get names */
- name = silc_argument_get_arg_type(args, 3, &len);
- info = silc_argument_get_arg_type(args, 4, &len);
+ name = silc_argument_get_arg_type(cmd->args, 3, &len);
+ info = silc_argument_get_arg_type(cmd->args, 4, &len);
- switch (id.type) {
+ id_type = silc_id_payload_get_type(idp);
+
+ switch (id_type) {
case SILC_ID_CLIENT:
+ client_id = silc_id_payload_get_id(idp);
+
SILC_LOG_DEBUG(("Received client information"));
/* Check if we have this client cached already. */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
if (!client_entry) {
- SILC_LOG_DEBUG(("Adding new client entry (IDENTIFY)"));
+ SILC_LOG_DEBUG(("Adding new client entry"));
client_entry =
- silc_client_add_client(client, conn, name, info, NULL,
- &id.u.client_id, 0);
+ silc_client_add_client(cmd->client, conn, name, info, NULL,
+ silc_id_dup(client_id, id_type), 0);
if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
- goto out;
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- silc_client_ref_client(client, conn, client_entry);
} else {
- silc_client_update_client(client, conn, client_entry,
+ silc_client_update_client(cmd->client, conn, client_entry,
name, info, NULL, 0);
}
+ client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+
/* Notify application */
- silc_client_command_callback(cmd, client_entry, name, info);
- silc_client_unref_client(client, conn, client_entry);
+ if (notify)
+ COMMAND_REPLY((SILC_ARGS, client_entry, name, info));
break;
case SILC_ID_SERVER:
+ server_id = silc_id_payload_get_id(idp);
+
SILC_LOG_DEBUG(("Received server information"));
/* Check if we have this server cached already. */
- server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
+ server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
if (!server_entry) {
- SILC_LOG_DEBUG(("Adding new server entry (IDENTIFY)"));
- server_entry = silc_client_add_server(client, conn, name, info,
- &id.u.server_id);
+ SILC_LOG_DEBUG(("Adding new server entry"));
+ server_entry = silc_client_add_server(cmd->client, conn, name, info,
+ silc_id_dup(server_id, id_type));
if (!server_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- silc_client_ref_server(client, conn, server_entry);
} else {
silc_client_update_server(client, conn, server_entry, name, info);
}
- server_entry->internal.resolve_cmd_ident = 0;
+
+ server_entry->resolve_cmd_ident = 0;
/* Notify application */
- silc_client_command_callback(cmd, server_entry, name, info);
- silc_client_unref_server(client, conn, server_entry);
+ if (notify)
+ COMMAND_REPLY((SILC_ARGS, server_entry, name, info));
break;
case SILC_ID_CHANNEL:
+ channel_id = silc_id_payload_get_id(idp);
+
SILC_LOG_DEBUG(("Received channel information"));
/* Check if we have this channel cached already. */
- channel_entry = silc_client_get_channel_by_id(client, conn,
- &id.u.channel_id);
+ channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
if (!channel_entry) {
- SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
-
- if (!name) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
+ if (!name)
+ break;
/* Add new channel entry */
channel_entry = silc_client_add_channel(client, conn, name, 0,
- &id.u.channel_id);
+ channel_id);
if (!channel_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ if (notify)
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return;
}
- silc_client_ref_channel(client, conn, channel_entry);
+ channel_id = NULL;
}
/* Notify application */
- silc_client_command_callback(cmd, channel_entry, name, info);
- silc_client_unref_channel(client, conn, channel_entry);
+ if (notify)
+ COMMAND_REPLY((SILC_ARGS, channel_entry, name, info));
break;
}
- out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ silc_id_payload_free(idp);
+ silc_free(client_id);
+ silc_free(server_id);
+ silc_free(channel_id);
}
-/********************************** NICK ************************************/
+/* Received reply for IDENTIFY command. This maybe called several times
+ for one IDENTIFY command as server may reply with list of results.
+ This is totally silent and does not print anything on screen. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(identify)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ COMMAND_CHECK_STATUS;
+
+ /* Save IDENTIFY info */
+ silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
+
+ err:
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ silc_client_command_reply_free(cmd);
+}
-/* Received reply for command NICK. */
+/* Received reply for command NICK. If everything went without errors
+ we just received our new Client ID. */
-SILC_FSM_STATE(silc_client_command_reply_nick)
+SILC_CLIENT_CMD_REPLY_FUNC(nick)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
- unsigned char *nick, *idp;
- SilcUInt32 len, idp_len;
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcIDPayload idp;
+ unsigned char *tmp;
+ SilcUInt32 argc, len;
SilcClientID old_client_id;
- SilcID id;
- /* Sanity checks */
- CHECK_STATUS("Cannot set nickname: ");
- CHECK_ARGS(2, 3);
+ SILC_LOG_DEBUG(("Start"));
- /* Take received Client ID */
- idp = silc_argument_get_arg_type(args, 2, &idp_len);
- if (!idp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (!silc_id_payload_parse_id(idp, idp_len, &id)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot set nickname: %s",
+ silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
- /* Take the new nickname */
- nick = silc_argument_get_arg_type(args, 3, &len);
- if (!nick) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc < 2 || argc > 3) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot set nickname: bad reply to command");
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_rwlock_wrlock(conn->local_entry->internal.lock);
-
- /* Change the nickname */
+ /* Save old Client ID */
old_client_id = *conn->local_id;
- if (!silc_client_change_nickname(client, conn, conn->local_entry,
- nick, &id.u.client_id, idp, idp_len)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
+
+ /* Take received Client ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ idp = silc_id_payload_parse(tmp, len);
+ if (!idp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ silc_client_receive_new_id(cmd->client, cmd->sock, idp);
+
+ /* Take the new nickname too */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (tmp) {
+ silc_idcache_del_by_context(conn->internal->client_cache,
+ conn->local_entry);
+ if (conn->nickname)
+ silc_free(conn->nickname);
+ conn->nickname = strdup(tmp);
+ conn->local_entry->nickname = conn->nickname;
+
+ /* Normalize nickname */
+ tmp = silc_identifier_check(conn->nickname, strlen(conn->nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_NICKNAME);
+ goto out;
+ }
- silc_rwlock_unlock(conn->local_entry->internal.lock);
+ silc_client_nickname_format(cmd->client, conn, conn->local_entry);
+
+ silc_idcache_add(conn->internal->client_cache, tmp,
+ conn->local_entry->id, conn->local_entry, 0, NULL);
+ }
/* Notify application */
- silc_client_command_callback(cmd, conn->local_entry,
- conn->local_entry->nickname, &old_client_id);
+ COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
+ (const SilcClientID *)&old_client_id));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
+ silc_client_command_reply_free(cmd);
}
-/********************************** LIST ************************************/
-
/* Received reply to the LIST command. */
-SILC_FSM_STATE(silc_client_command_reply_list)
+SILC_CLIENT_CMD_REPLY_FUNC(list)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
unsigned char *tmp, *name, *topic;
- SilcUInt32 usercount = 0;
- SilcChannelEntry channel_entry = NULL;
- SilcID id;
+ SilcUInt32 usercount = 0, len;
+ SilcChannelID *channel_id = NULL;
+ SilcChannelEntry channel_entry;
- /* Sanity checks */
- CHECK_STATUS("Cannot list channels: ");
+ COMMAND_CHECK_STATUS;
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp) {
/* There were no channels in the network. */
- silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ COMMAND_REPLY((SILC_ARGS, NULL, NULL, 0));
+ goto out;
}
- CHECK_ARGS(3, 5);
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
- name = silc_argument_get_arg_type(args, 3, NULL);
+ name = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!name) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- topic = silc_argument_get_arg_type(args, 4, NULL);
- tmp = silc_argument_get_arg_type(args, 5, NULL);
+ topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
if (tmp)
SILC_GET32_MSB(usercount, tmp);
/* Check whether the channel exists, and add it to cache if it doesn't. */
- channel_entry = silc_client_get_channel_by_id(client, conn,
- &id.u.channel_id);
+ channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
+ channel_id);
if (!channel_entry) {
/* Add new channel entry */
- channel_entry = silc_client_add_channel(client, conn, name, 0,
- &id.u.channel_id);
+ channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
+ channel_id);
if (!channel_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_client_ref_channel(client, conn, channel_entry);
+ channel_id = NULL;
}
/* Notify application */
- silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
+ COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
out:
- silc_client_unref_channel(client, conn, channel_entry);
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ silc_free(channel_id);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
+ err:
+ silc_client_command_reply_free(cmd);
}
-/********************************* TOPIC ************************************/
-
/* Received reply to topic command. */
-SILC_FSM_STATE(silc_client_command_reply_topic)
+SILC_CLIENT_CMD_REPLY_FUNC(topic)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcChannelEntry channel;
+ SilcChannelID *channel_id = NULL;
+ unsigned char *tmp;
char *topic;
- SilcUInt32 len;
- SilcID id;
+ SilcUInt32 argc, len;
- /* Sanity checks */
- CHECK_STATUS("Cannot set topic: ");
- CHECK_ARGS(2, 3);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot set topic: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
- /* Take Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc < 1 || argc > 3) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ /* Take Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ /* Take topic */
+ topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!topic)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
+ goto out;
+
/* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_rwlock_wrlock(channel->internal.lock);
-
- /* Take topic */
- topic = silc_argument_get_arg_type(args, 3, &len);
if (topic) {
silc_free(channel->topic);
- channel->topic = silc_memdup(topic, len);
+ channel->topic = silc_memdup(topic, strlen(topic));
}
- silc_rwlock_unlock(channel->internal.lock);
-
/* Notify application */
- silc_client_command_callback(cmd, channel, channel->topic);
+ COMMAND_REPLY((SILC_ARGS, channel, topic));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
+ silc_client_command_reply_free(cmd);
}
-/********************************* INVITE ***********************************/
-
/* Received reply to invite command. */
-SILC_FSM_STATE(silc_client_command_reply_invite)
+SILC_CLIENT_CMD_REPLY_FUNC(invite)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcChannelEntry channel;
+ SilcChannelID *channel_id;
unsigned char *tmp;
SilcUInt32 len;
- SilcArgumentPayload invite_args = NULL;
- SilcID id;
+ SilcBufferStruct buf;
- /* Sanity checks */
- CHECK_STATUS("Cannot invite: ");
- CHECK_ARGS(2, 3);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot invite: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Take Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
goto out;
- }
/* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Get the invite list */
- tmp = silc_argument_get_arg_type(args, 3, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
if (tmp)
- invite_args = silc_argument_list_parse(tmp, len);
+ silc_buffer_set(&buf, tmp, len);
/* Notify application */
- silc_client_command_callback(cmd, channel, invite_args);
-
- if (invite_args)
- silc_argument_payload_free(invite_args);
+ COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
+ silc_client_command_reply_free(cmd);
}
-/********************************** KILL ************************************/
-
/* Received reply to the KILL command. */
-SILC_FSM_STATE(silc_client_command_reply_kill)
+SILC_CLIENT_CMD_REPLY_FUNC(kill)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
- SilcClientEntry client_entry;
- SilcID id;
-
- /* Sanity checks */
- CHECK_STATUS("Cannot kill: ");
- CHECK_ARGS(2, 2);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClientID *client_id;
+ SilcClientEntry client_entry = NULL;
+ SilcUInt32 len;
+ unsigned char *id_data;
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot kill: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
- /* Get the client entry, if exists */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
-
- /* Notify application */
- silc_client_command_callback(cmd, client_entry);
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (id_data) {
+ client_id = silc_id_payload_parse_id(id_data, len, NULL);
+ if (!client_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
- /* Remove the client */
- if (client_entry) {
- silc_client_remove_from_channels(client, conn, client_entry);
- silc_client_del_client(client, conn, client_entry);
- silc_client_unref_client(client, conn, client_entry);
+ /* Get the client entry, if exists */
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+ silc_free(client_id);
}
+ /* Notify application */
+ COMMAND_REPLY((SILC_ARGS, client_entry));
+
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
+ silc_client_command_reply_free(cmd);
}
-/********************************** INFO ************************************/
-
/* Received reply to INFO command. We receive the server ID and some
information about the server user requested. */
-SILC_FSM_STATE(silc_client_command_reply_info)
+SILC_CLIENT_CMD_REPLY_FUNC(info)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ unsigned char *tmp;
SilcServerEntry server;
+ SilcServerID *server_id = NULL;
char *server_name, *server_info;
- SilcID id;
+ SilcUInt32 len;
- /* Sanity checks */
- CHECK_STATUS("Cannot get info: ");
- CHECK_ARGS(4, 4);
+ SILC_LOG_DEBUG(("Start"));
- /* Get server ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
+ silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
- /* Get server name */
- server_name = silc_argument_get_arg_type(args, 3, NULL);
- if (!server_name) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ /* Get server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ server_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!server_id)
+ goto out;
+
+ /* Get server name */
+ server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!server_name)
goto out;
- }
/* Get server info */
- server_info = silc_argument_get_arg_type(args, 4, NULL);
- if (!server_info) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (!server_info)
goto out;
- }
/* See whether we have this server cached. If not create it. */
- server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
+ server = silc_client_get_server_by_id(cmd->client, conn, server_id);
if (!server) {
- SILC_LOG_DEBUG(("Add new server entry (INFO)"));
- server = silc_client_add_server(client, conn, server_name,
- server_info, &id.u.server_id);
+ SILC_LOG_DEBUG(("New server entry"));
+ server = silc_client_add_server(cmd->client, conn, server_name,
+ server_info,
+ silc_id_dup(server_id, SILC_ID_SERVER));
if (!server)
goto out;
- silc_client_ref_server(client, conn, server);
}
/* Notify application */
- silc_client_command_callback(cmd, server, server->server_name,
- server->server_info);
- silc_client_unref_server(client, conn, server);
+ COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
+ silc_free(server_id);
+ silc_client_command_reply_free(cmd);
}
-/********************************** STATS ***********************************/
-
/* Received reply to STATS command. */
-SILC_FSM_STATE(silc_client_command_reply_stats)
+SILC_CLIENT_CMD_REPLY_FUNC(stats)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
- SilcClientStats stats;
- unsigned char *buf = NULL;
- SilcUInt32 buf_len = 0;
- SilcBufferStruct b;
- SilcID id;
-
- /* Sanity checks */
- CHECK_STATUS("Cannot get stats: ");
- CHECK_ARGS(2, 3);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ unsigned char *tmp, *buf = NULL;
+ SilcUInt32 len, buf_len = 0;
+
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Get server ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
goto out;
- }
/* Get statistics structure */
- memset(&stats, 0, sizeof(stats));
- buf = silc_argument_get_arg_type(args, 3, &buf_len);
- if (buf) {
- silc_buffer_set(&b, buf, buf_len);
- silc_buffer_unformat(&b,
- SILC_STR_UI_INT(&stats.starttime),
- SILC_STR_UI_INT(&stats.uptime),
- SILC_STR_UI_INT(&stats.my_clients),
- SILC_STR_UI_INT(&stats.my_channels),
- SILC_STR_UI_INT(&stats.my_server_ops),
- SILC_STR_UI_INT(&stats.my_router_ops),
- SILC_STR_UI_INT(&stats.cell_clients),
- SILC_STR_UI_INT(&stats.cell_channels),
- SILC_STR_UI_INT(&stats.cell_servers),
- SILC_STR_UI_INT(&stats.clients),
- SILC_STR_UI_INT(&stats.channels),
- SILC_STR_UI_INT(&stats.servers),
- SILC_STR_UI_INT(&stats.routers),
- SILC_STR_UI_INT(&stats.server_ops),
- SILC_STR_UI_INT(&stats.router_ops),
- SILC_STR_END);
- }
+ buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
/* Notify application */
- silc_client_command_callback(cmd, &stats);
+ COMMAND_REPLY((SILC_ARGS, buf, buf_len));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
+ silc_client_command_reply_free(cmd);
}
-/********************************** PING ************************************/
-
-/* Received reply to PING command. */
+/* Received reply to PING command. The reply time is shown to user. */
-SILC_FSM_STATE(silc_client_command_reply_ping)
+SILC_CLIENT_CMD_REPLY_FUNC(ping)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcInt64 diff;
-
- diff = silc_time() - SILC_PTR_TO_64(cmd->context);
- if (cmd->verbose)
- SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Ping reply from %s: %d second%s", conn->remote_host,
- (int)diff, diff == 1 ? "" : "s");
-
- /* Notify application */
- silc_client_command_callback(cmd);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ void *id;
+ int i;
+ time_t diff, curtime;
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
-}
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
-/********************************** JOIN ************************************/
+ curtime = time(NULL);
+ id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
+ cmd->packet->src_id_type);
+ if (!id || !conn->internal->ping) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
-/* Continue JOIN command reply processing after resolving unknown users */
+ for (i = 0; i < conn->internal->ping_count; i++) {
+ if (!conn->internal->ping[i].dest_id)
+ continue;
+ if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
+ diff = curtime - conn->internal->ping[i].start_time;
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Ping reply from %s: %d second%s",
+ conn->internal->ping[i].dest_name, diff,
+ diff == 1 ? "" : "s");
+
+ conn->internal->ping[i].start_time = 0;
+ silc_free(conn->internal->ping[i].dest_id);
+ conn->internal->ping[i].dest_id = NULL;
+ silc_free(conn->internal->ping[i].dest_name);
+ conn->internal->ping[i].dest_name = NULL;
+ break;
+ }
+ }
-static void
-silc_client_command_reply_join_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
-{
- SilcClientCommandContext cmd = context;
- SilcChannelEntry channel = cmd->context;
+ silc_free(id);
- channel->internal.resolve_cmd_ident = 0;
- silc_client_unref_channel(client, conn, channel);
+ /* Notify application */
+ COMMAND_REPLY((SILC_ARGS));
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
+ silc_client_command_reply_free(cmd);
}
-
/* Received reply for JOIN command. */
-SILC_FSM_STATE(silc_client_command_reply_join)
+SILC_CLIENT_CMD_REPLY_FUNC(join)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcChannelEntry channel;
- SilcUInt32 mode = 0, len, list_count;
+ SilcChannelUser chu;
+ SilcChannelID *channel_id;
+ SilcUInt32 argc, mode = 0, len, list_count;
char *topic, *tmp, *channel_name = NULL, *hmac;
- const char *cipher;
- SilcBufferStruct client_id_list, client_mode_list, keyp;
- SilcHashTableList htl;
- SilcID id;
+ SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
+ SilcBufferStruct chpklist;
int i;
- /* Sanity checks */
- CHECK_STATUS("Cannot join channel: ");
- CHECK_ARGS(9, 17);
+ SILC_LOG_DEBUG(("Start"));
+
+ if (cmd->error != SILC_STATUS_OK) {
+ if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot join channel: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
+
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc < 7) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot join channel: Bad reply packet");
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
/* Get channel name */
- channel_name = silc_argument_get_arg_type(args, 2, NULL);
- if (!channel_name) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot join channel: Bad reply packet");
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ channel_name = tmp;
/* Get Channel ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!tmp) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot join channel: Bad reply packet");
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ /* Get channel mode */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ if (tmp)
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get channel key */
+ tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
+ if (tmp) {
+ keyp = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
+ silc_buffer_put(keyp, tmp, len);
+ }
+
+ /* Get topic */
+ topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
+
/* Check whether we have this channel entry already. */
- channel = silc_client_get_channel(client, conn, channel_name);
+ channel = silc_client_get_channel(cmd->client, conn, channel_name);
if (channel) {
- if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
- silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
+ if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
+ silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
} else {
/* Create new channel entry */
- channel = silc_client_add_channel(client, conn, channel_name,
- mode, &id.u.channel_id);
- if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
+ channel = silc_client_add_channel(cmd->client, conn, channel_name,
+ mode, channel_id);
+ }
+ if (!channel) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_CHANNEL);
+ goto out;
+ }
+
+ conn->current_channel = channel;
+ channel->mode = mode;
+
+ /* Get hmac */
+ hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
+ if (hmac) {
+ if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot join channel: Unsupported HMAC `%s'", hmac);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_client_ref_channel(client, conn, channel);
}
/* Get the list count */
- tmp = silc_argument_get_arg_type(args, 12, &len);
- if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
+ if (!tmp)
goto out;
- }
SILC_GET32_MSB(list_count, tmp);
/* Get Client ID list */
- tmp = silc_argument_get_arg_type(args, 13, &len);
- if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
+ if (!tmp)
goto out;
- }
- silc_buffer_set(&client_id_list, tmp, len);
- /* Resolve users we do not know about */
- if (!cmd->resolved) {
- cmd->resolved = TRUE;
- cmd->context = channel;
- SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
- silc_client_get_clients_by_list(
- client, conn, list_count, &client_id_list,
- silc_client_command_reply_join_resolved, cmd));
- /* NOT REACHED */
- }
+ client_id_list = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(client_id_list, len);
+ silc_buffer_put(client_id_list, tmp, len);
/* Get client mode list */
- tmp = silc_argument_get_arg_type(args, 14, &len);
- if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
+ if (!tmp)
goto out;
- }
- silc_buffer_set(&client_mode_list, tmp, len);
- silc_rwlock_wrlock(channel->internal.lock);
+ client_mode_list = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(client_mode_list, len);
+ silc_buffer_put(client_mode_list, tmp, len);
/* Add clients we received in the reply to the channel */
for (i = 0; i < list_count; i++) {
SilcUInt16 idp_len;
SilcUInt32 mode;
- SilcID id;
+ SilcClientID *client_id;
SilcClientEntry client_entry;
/* Client ID */
- SILC_GET16_MSB(idp_len, client_id_list.data + 2);
+ SILC_GET16_MSB(idp_len, client_id_list->data + 2);
idp_len += 4;
- if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
+ client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
+ if (!client_id)
continue;
/* Mode */
- SILC_GET32_MSB(mode, client_mode_list.data);
+ SILC_GET32_MSB(mode, client_mode_list->data);
- /* Get client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry && client_entry->internal.valid) {
- /* Join client to the channel */
- silc_rwlock_wrlock(client_entry->internal.lock);
- silc_client_add_to_channel(client, conn, channel, client_entry, mode);
- silc_rwlock_unlock(client_entry->internal.lock);
- }
- silc_client_unref_client(client, conn, client_entry);
-
- if (!silc_buffer_pull(&client_id_list, idp_len)) {
- silc_rwlock_unlock(channel->internal.lock);
- goto out;
- }
- if (!silc_buffer_pull(&client_mode_list, 4)) {
- silc_rwlock_unlock(channel->internal.lock);
- goto out;
+ /* Check if we have this client cached already. */
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+ if (!client_entry) {
+ /* No, we don't have it, add entry for it. */
+ client_entry =
+ silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
+ silc_id_dup(client_id, SILC_ID_CLIENT), 0);
+ if (!client_entry)
+ goto out;
}
- }
- /* Get hmac */
- hmac = silc_argument_get_arg_type(args, 11, NULL);
- if (hmac) {
- if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
- if (cmd->verbose)
- SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
- "Cannot join channel: Unsupported HMAC `%s'", hmac);
- ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
- silc_rwlock_unlock(channel->internal.lock);
- goto out;
+ /* Join client to the channel */
+ if (!silc_client_on_channel(channel, client_entry)) {
+ chu = silc_calloc(1, sizeof(*chu));
+ chu->client = client_entry;
+ chu->channel = channel;
+ chu->mode = mode;
+ silc_hash_table_add(channel->user_list, client_entry, chu);
+ silc_hash_table_add(client_entry->channels, channel, chu);
}
- }
-
- /* Get channel mode */
- tmp = silc_argument_get_arg_type(args, 5, &len);
- if (tmp && len == 4)
- SILC_GET32_MSB(mode, tmp);
- channel->mode = mode;
- /* Get channel key and save it */
- tmp = silc_argument_get_arg_type(args, 7, &len);
- if (tmp) {
- silc_buffer_set(&keyp, tmp, len);
- silc_client_save_channel_key(client, conn, &keyp, channel);
+ silc_free(client_id);
+ silc_buffer_pull(client_id_list, idp_len);
+ silc_buffer_pull(client_mode_list, 4);
}
+ silc_buffer_push(client_id_list, client_id_list->data -
+ client_id_list->head);
+ silc_buffer_push(client_mode_list, client_mode_list->data -
+ client_mode_list->head);
- /* Get topic */
- topic = silc_argument_get_arg_type(args, 10, NULL);
- if (topic) {
- silc_free(channel->topic);
- channel->topic = silc_memdup(topic, strlen(topic));
- }
+ /* Save channel key */
+ if (keyp)
+ silc_client_save_channel_key(cmd->client, conn, keyp, channel);
/* Get founder key */
- tmp = silc_argument_get_arg_type(args, 15, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
if (tmp) {
if (channel->founder_key)
silc_pkcs_public_key_free(channel->founder_key);
channel->founder_key = NULL;
- silc_public_key_payload_decode(tmp, len, &channel->founder_key);
+ silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
}
/* Get user limit */
- tmp = silc_argument_get_arg_type(args, 17, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
if (tmp && len == 4)
SILC_GET32_MSB(channel->user_limit, tmp);
if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
channel->user_limit = 0;
/* Get channel public key list */
- tmp = silc_argument_get_arg_type(args, 16, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
if (tmp)
- silc_client_channel_save_public_keys(channel, tmp, len);
+ silc_buffer_set(&chpklist, tmp, len);
- /* Set current channel */
- conn->current_channel = channel;
-
- silc_rwlock_unlock(channel->internal.lock);
-
- cipher = (channel->internal.send_key ?
- silc_cipher_get_name(channel->internal.send_key) : NULL);
- silc_hash_table_list(channel->user_list, &htl);
+ if (topic) {
+ silc_free(channel->topic);
+ channel->topic = silc_memdup(topic, strlen(topic));
+ }
/* Notify application */
- silc_client_command_callback(cmd, channel_name, channel, mode, &htl,
- topic, cipher, hmac, channel->founder_key,
- channel->channel_pubkeys, channel->user_limit);
-
- silc_hash_table_list_reset(&htl);
- silc_client_unref_channel(client, conn, channel);
+ COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
+ keyp ? keyp->head : NULL, NULL,
+ NULL, topic, hmac, list_count, client_id_list,
+ client_mode_list, channel->founder_key,
+ tmp ? &chpklist : NULL, channel->user_limit));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
+ silc_client_command_reply_free(cmd);
+ silc_buffer_free(keyp);
+ silc_buffer_free(client_id_list);
+ silc_buffer_free(client_mode_list);
}
-/********************************** MOTD ************************************/
-
/* Received reply for MOTD command */
-SILC_FSM_STATE(silc_client_command_reply_motd)
+SILC_CLIENT_CMD_REPLY_FUNC(motd)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
- SilcUInt32 i;
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcUInt32 argc, i;
char *motd = NULL, *cp, line[256];
- /* Sanity checks */
- CHECK_STATUS("Cannot get motd: ");
- CHECK_ARGS(2, 3);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ return;
+ }
- if (silc_argument_get_arg_num(args) == 3) {
- motd = silc_argument_get_arg_type(args, 3, NULL);
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc > 3) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ if (argc == 3) {
+ motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!motd) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
if (i == 2)
line[0] = ' ';
- if (cmd->verbose)
- SAY(client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
if (!strlen(cp))
break;
}
/* Notify application */
- silc_client_command_callback(cmd, motd);
+ COMMAND_REPLY((SILC_ARGS, motd));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
+ silc_client_command_reply_free(cmd);
}
-/********************************** UMODE ***********************************/
-
-/* Received reply to the UMODE command. Save the current user mode */
+/* Received reply tot he UMODE command. Save the current user mode */
-SILC_FSM_STATE(silc_client_command_reply_umode)
+SILC_CLIENT_CMD_REPLY_FUNC(umode)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
unsigned char *tmp;
- SilcUInt32 mode, len;
+ SilcUInt32 mode;
- /* Sanity checks */
- CHECK_STATUS("Cannot change mode: ");
- CHECK_ARGS(2, 2);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot change mode: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
- tmp = silc_argument_get_arg_type(args, 2, &len);
- if (!tmp || len != 4) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
SILC_GET32_MSB(mode, tmp);
- silc_rwlock_wrlock(conn->local_entry->internal.lock);
conn->local_entry->mode = mode;
- silc_rwlock_unlock(conn->local_entry->internal.lock);
/* Notify application */
- silc_client_command_callback(cmd, mode);
+ COMMAND_REPLY((SILC_ARGS, mode));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
+ silc_client_command_reply_free(cmd);
}
-/********************************** CMODE ***********************************/
-
/* Received reply for CMODE command. */
-SILC_FSM_STATE(silc_client_command_reply_cmode)
+SILC_CLIENT_CMD_REPLY_FUNC(cmode)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
unsigned char *tmp;
SilcUInt32 mode;
+ SilcChannelID *channel_id;
SilcChannelEntry channel;
SilcUInt32 len;
SilcPublicKey public_key = NULL;
- SilcDList channel_pubkeys = NULL;
- SilcID id;
+ SilcBufferStruct channel_pubkeys;
- /* Sanity checks */
- CHECK_STATUS("Cannot change mode: ");
- CHECK_ARGS(3, 6);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot change mode: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Take Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
goto out;
- }
/* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- /* Get founder public key */
- tmp = silc_argument_get_arg_type(args, 4, &len);
- if (tmp)
- silc_public_key_payload_decode(tmp, len, &public_key);
-
/* Get channel mode */
- tmp = silc_argument_get_arg_type(args, 3, &len);
- if (!tmp || len != 4) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!tmp) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_rwlock_wrlock(channel->internal.lock);
-
/* Save the mode */
SILC_GET32_MSB(mode, tmp);
channel->mode = mode;
+ /* Get founder public key */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
+ if (tmp) {
+ if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+ public_key = NULL;
+ }
+
/* Get user limit */
- tmp = silc_argument_get_arg_type(args, 6, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
if (tmp && len == 4)
SILC_GET32_MSB(channel->user_limit, tmp);
if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
channel->user_limit = 0;
/* Get channel public key(s) */
- tmp = silc_argument_get_arg_type(args, 5, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
if (tmp)
- silc_client_channel_save_public_keys(channel, tmp, len);
-
- silc_rwlock_unlock(channel->internal.lock);
+ silc_buffer_set(&channel_pubkeys, tmp, len);
/* Notify application */
- silc_client_command_callback(cmd, channel, mode, public_key,
- channel_pubkeys, channel->user_limit);
+ COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
+ tmp ? &channel_pubkeys : NULL, channel->user_limit));
- silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
+ silc_free(channel_id);
out:
if (public_key)
silc_pkcs_public_key_free(public_key);
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
+ silc_client_command_reply_free(cmd);
}
-/********************************** CUMODE **********************************/
-
/* Received reply for CUMODE command */
-SILC_FSM_STATE(silc_client_command_reply_cumode)
+SILC_CLIENT_CMD_REPLY_FUNC(cumode)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClientID *client_id;
+ SilcChannelID *channel_id;
SilcClientEntry client_entry;
SilcChannelEntry channel;
SilcChannelUser chu;
- unsigned char *modev;
+ unsigned char *modev, *tmp, *id;
SilcUInt32 len, mode;
- SilcID id;
- /* Sanity checks */
- CHECK_STATUS("Cannot change mode: ");
- CHECK_ARGS(4, 4);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot change mode: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Get channel mode */
- modev = silc_argument_get_arg_type(args, 2, &len);
- if (!modev || len != 4) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!modev) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- SILC_GET32_MSB(mode, modev);
/* Take Channel ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
goto out;
- }
/* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Get Client ID */
- if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ id = silc_argument_get_arg_type(cmd->args, 4, &len);
+ if (!id) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(id, len, NULL);
+ if (!client_id) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Get client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_free(channel_id);
+ silc_free(client_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Save the mode */
- silc_rwlock_wrlock(channel->internal.lock);
+ SILC_GET32_MSB(mode, modev);
chu = silc_client_on_channel(channel, client_entry);
if (chu)
chu->mode = mode;
- silc_rwlock_unlock(channel->internal.lock);
/* Notify application */
- silc_client_command_callback(cmd, mode, channel, client_entry);
-
- silc_client_unref_client(client, conn, client_entry);
+ COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
+ silc_free(client_id);
+ silc_free(channel_id);
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
+ silc_client_command_reply_free(cmd);
}
-/********************************** KICK ************************************/
-
-SILC_FSM_STATE(silc_client_command_reply_kick)
+SILC_CLIENT_CMD_REPLY_FUNC(kick)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
- SilcClientEntry client_entry;
- SilcChannelEntry channel;
- SilcID id;
-
- /* Sanity checks */
- CHECK_STATUS("Cannot kick: ");
- CHECK_ARGS(3, 3);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClientID *client_id = NULL;
+ SilcChannelID *channel_id = NULL;
+ SilcClientEntry client_entry = NULL;
+ SilcChannelEntry channel = NULL;
+ unsigned char *tmp;
+ SilcUInt32 len;
- /* Take Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot kick: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
- /* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ /* Take Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (tmp) {
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get the channel entry */
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+ if (!channel) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
}
/* Get Client ID */
- if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (tmp) {
+ client_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!client_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
- /* Get client entry */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ /* Get client entry */
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+ if (!client_entry) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
}
/* Notify application */
- silc_client_command_callback(cmd, channel, client_entry);
-
- silc_client_unref_client(client, conn, client_entry);
+ COMMAND_REPLY((SILC_ARGS, channel, client_entry));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ silc_free(channel_id);
+ silc_free(client_id);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
+ silc_client_command_reply_free(cmd);
}
-/******************************** SILCOPER **********************************/
-
-SILC_FSM_STATE(silc_client_command_reply_silcoper)
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
- /* Sanity checks */
- CHECK_STATUS("Cannot change mode: ");
- CHECK_ARGS(1, 1);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Notify application */
- silc_client_command_callback(cmd);
+ COMMAND_REPLY((SILC_ARGS));
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
+ silc_client_command_reply_free(cmd);
}
-/********************************** OPER ************************************/
-
-SILC_FSM_STATE(silc_client_command_reply_oper)
+SILC_CLIENT_CMD_REPLY_FUNC(oper)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
- /* Sanity checks */
- CHECK_STATUS("Cannot change mode: ");
- CHECK_ARGS(1, 1);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Notify application */
- silc_client_command_callback(cmd);
+ COMMAND_REPLY((SILC_ARGS));
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
+ silc_client_command_reply_free(cmd);
}
-/********************************* DETACH ***********************************/
-
-SILC_FSM_STATE(silc_client_command_reply_detach)
+SILC_CLIENT_CMD_REPLY_FUNC(detach)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcBuffer detach;
- /* Sanity checks */
- CHECK_STATUS("Cannot detach: ");
- CHECK_ARGS(1, 1);
-
- /* Get detachment data */
- detach = silc_client_get_detach_data(client, conn);
- if (!detach) {
- ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
/* Notify application */
- silc_client_command_callback(cmd, detach);
- silc_buffer_free(detach);
+ COMMAND_REPLY((SILC_ARGS));
+
+ /* Generate the detachment data and deliver it to the client in the
+ detach client operation */
+ detach = silc_client_get_detach_data(cmd->client, conn);
+ if (detach) {
+ cmd->client->internal->ops->detach(cmd->client, conn,
+ detach->data, detach->len);
+ silc_buffer_free(detach);
+ }
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
+ silc_client_command_reply_free(cmd);
}
-/********************************** WATCH ***********************************/
-
-SILC_FSM_STATE(silc_client_command_reply_watch)
+SILC_CLIENT_CMD_REPLY_FUNC(watch)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
- /* Sanity checks */
- CHECK_STATUS("Cannot set watch: ");
- CHECK_ARGS(1, 1);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Notify application */
- silc_client_command_callback(cmd);
+ COMMAND_REPLY((SILC_ARGS));
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
+ silc_client_command_reply_free(cmd);
}
-/*********************************** BAN ************************************/
-
-SILC_FSM_STATE(silc_client_command_reply_ban)
+SILC_CLIENT_CMD_REPLY_FUNC(ban)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcChannelEntry channel;
+ SilcChannelID *channel_id;
unsigned char *tmp;
SilcUInt32 len;
- SilcArgumentPayload invite_args = NULL;
- SilcID id;
+ SilcBufferStruct buf;
- /* Sanity checks */
- CHECK_STATUS("Cannot set ban: ");
- CHECK_ARGS(2, 3);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Take Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
goto out;
- }
/* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- /* Get the invite list */
- tmp = silc_argument_get_arg_type(args, 3, &len);
+ /* Get the ban list */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
if (tmp)
- invite_args = silc_argument_list_parse(tmp, len);
+ silc_buffer_set(&buf, tmp, len);
/* Notify application */
- silc_client_command_callback(cmd, channel, invite_args);
-
- if (invite_args)
- silc_argument_payload_free(invite_args);
+ COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
+ silc_client_command_reply_free(cmd);
}
-/********************************** LEAVE ***********************************/
-
/* Reply to LEAVE command. */
-SILC_FSM_STATE(silc_client_command_reply_leave)
+SILC_CLIENT_CMD_REPLY_FUNC(leave)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
- SilcChannelEntry channel;
- SilcID id;
-
- /* Sanity checks */
- CHECK_STATUS("Cannot set leave: ");
- CHECK_ARGS(2, 2);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel = NULL;
+ SilcChannelUser chu;
+ unsigned char *tmp;
+ SilcUInt32 len;
- /* Get Channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
- /* Get the channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
+ /* From protocol version 1.1 we get the channel ID of the left channel */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (tmp) {
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
+ goto out;
- /* Remove us from this channel. */
- silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
+ /* Get the channel entry */
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+ if (!channel) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Remove us from this channel. */
+ chu = silc_client_on_channel(channel, conn->local_entry);
+ if (chu) {
+ silc_hash_table_del(chu->client->channels, chu->channel);
+ silc_hash_table_del(chu->channel->user_list, chu->client);
+ silc_free(chu);
+ }
+
+ silc_free(channel_id);
+ }
/* Notify application */
- silc_client_command_callback(cmd, channel);
+ COMMAND_REPLY((SILC_ARGS, channel));
/* Now delete the channel. */
- silc_client_empty_channel(client, conn, channel);
- silc_client_del_channel(client, conn, channel);
+ if (channel)
+ silc_client_del_channel(cmd->client, conn, channel);
out:
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
+ silc_client_command_reply_free(cmd);
}
-/********************************* USERS ************************************/
+/* Channel resolving callback for USERS command reply. */
-/* Continue USERS command reply processing after resolving unknown users */
-
-static void
-silc_client_command_reply_users_resolved(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context)
+static void silc_client_command_reply_users_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry *channels,
+ SilcUInt32 channels_count,
+ void *context)
{
- SilcClientCommandContext cmd = context;
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
-}
-
-
-/* Continue USERS command after resolving unknown channel */
-
-static void
-silc_client_command_reply_users_continue(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList channels,
- void *context)
-{
- SilcClientCommandContext cmd = context;
-
- if (!channels) {
- SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
- SilcArgumentPayload args = silc_command_get_args(payload);
-
- cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
- ERROR_CALLBACK(cmd->status);
- silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
+ if (!channels_count) {
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+ silc_client_command_reply_free(cmd);
+ return;
}
- SILC_FSM_CALL_CONTINUE(&cmd->thread);
+ silc_client_command_reply_users(context, NULL);
}
-/* Reply to USERS command. Received list of client ID's and theirs modes
- on the channel we requested. */
-
-SILC_FSM_STATE(silc_client_command_reply_users)
+static int
+silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
+ SilcStatus status,
+ bool notify,
+ bool resolve,
+ SilcGetChannelCallback get_channel,
+ SilcCommandCb get_clients)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcChannelEntry channel;
+ SilcClientEntry client_entry;
+ SilcChannelUser chu;
+ SilcChannelID *channel_id = NULL;
+ SilcBufferStruct client_id_list, client_mode_list;
unsigned char *tmp;
SilcUInt32 tmp_len, list_count;
- SilcUInt16 idp_len, mode;
- SilcHashTableList htl;
- SilcBufferStruct client_id_list, client_mode_list;
- SilcChannelEntry channel = NULL;
- SilcClientEntry client_entry;
- SilcID id;
int i;
+ unsigned char **res_argv = NULL;
+ SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+ bool wait_res = FALSE;
- /* Sanity checks */
- CHECK_STATUS("Cannot get users: ");
- CHECK_ARGS(5, 5);
+ SILC_LOG_DEBUG(("Start"));
/* Get channel ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
-
- /* Get channel entry */
- channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
- if (!channel) {
- /* Resolve the channel from server */
- SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
- client, conn, &id.u.channel_id,
- silc_client_command_reply_users_continue, cmd));
- /* NOT REACHED */
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!channel_id) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
}
/* Get the list count */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (!tmp || tmp_len != 4) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
SILC_GET32_MSB(list_count, tmp);
/* Get Client ID list */
- tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
silc_buffer_set(&client_id_list, tmp, tmp_len);
- /* Resolve users we do not know about */
- if (!cmd->resolved) {
- cmd->resolved = TRUE;
- silc_client_unref_channel(client, conn, channel);
- SILC_FSM_CALL(silc_client_get_clients_by_list(
- client, conn, list_count, &client_id_list,
- silc_client_command_reply_users_resolved, cmd));
- /* NOT REACHED */
- }
-
/* Get client mode list */
- tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
silc_buffer_set(&client_mode_list, tmp, tmp_len);
- SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
+ /* Get channel entry */
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+ if (!channel) {
+ /* Resolve the channel from server */
+ silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
+ get_channel, cmd);
+ silc_free(channel_id);
+ return 1;
+ }
- silc_rwlock_wrlock(channel->internal.lock);
+ SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
/* Cache the received Client ID's and modes. */
for (i = 0; i < list_count; i++) {
+ SilcUInt16 idp_len;
+ SilcUInt32 mode;
+ SilcClientID *client_id;
+
+ /* Client ID */
SILC_GET16_MSB(idp_len, client_id_list.data + 2);
idp_len += 4;
- if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
- goto out;
+ client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
+ if (!client_id)
+ continue;
/* Mode */
SILC_GET32_MSB(mode, client_mode_list.data);
- /* Save the client on this channel. Unknown clients are ignored as they
- clearly do not exist since the resolving didn't find them. */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry && client_entry->internal.valid) {
- silc_rwlock_wrlock(client_entry->internal.lock);
- silc_client_add_to_channel(client, conn, channel, client_entry, mode);
- silc_rwlock_unlock(client_entry->internal.lock);
+ /* Check if we have this client cached already. */
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+ if (!client_entry || !client_entry->username || !client_entry->realname) {
+ if (resolve) {
+ /* No we don't have it (or it is incomplete in information), query
+ it from the server. Assemble argument table that will be sent
+ for the WHOIS command later. */
+ res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
+ (res_argc + 1));
+ res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+ (res_argc + 1));
+ res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+ (res_argc + 1));
+ res_argv[res_argc] = client_id_list.data;
+ res_argv_lens[res_argc] = idp_len;
+ res_argv_types[res_argc] = res_argc + 4;
+ res_argc++;
+ }
+ } else {
+ if (!silc_client_on_channel(channel, client_entry)) {
+ chu = silc_calloc(1, sizeof(*chu));
+ chu->client = client_entry;
+ chu->mode = mode;
+ chu->channel = channel;
+ silc_hash_table_add(channel->user_list, client_entry, chu);
+ silc_hash_table_add(client_entry->channels, channel, chu);
+ }
}
- silc_client_unref_client(client, conn, client_entry);
- if (!silc_buffer_pull(&client_id_list, idp_len)) {
- silc_rwlock_unlock(channel->internal.lock);
+ silc_free(client_id);
+ silc_buffer_pull(&client_id_list, idp_len);
+ silc_buffer_pull(&client_mode_list, 4);
+ }
+
+ /* Query the client information from server if the list included clients
+ that we don't know about. */
+ if (res_argc) {
+ SilcBuffer res_cmd;
+
+ /* Send the WHOIS command to server */
+ silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ ++conn->cmd_ident);
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ res_argc, res_argv, res_argv_lens,
+ res_argv_types, conn->cmd_ident);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
+ TRUE);
+
+ /* Register pending command callback. After we've received the WHOIS
+ command reply we will reprocess this command reply by re-calling this
+ USERS command reply callback. */
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ get_clients, cmd);
+
+ silc_buffer_free(res_cmd);
+ silc_free(channel_id);
+ silc_free(res_argv);
+ silc_free(res_argv_lens);
+ silc_free(res_argv_types);
+ return 1;
+ }
+
+ if (wait_res)
+ return 1;
+
+ silc_buffer_push(&client_id_list, (client_id_list.data -
+ client_id_list.head));
+ silc_buffer_push(&client_mode_list, (client_mode_list.data -
+ client_mode_list.head));
+
+ /* Notify application */
+ if (notify)
+ COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
+ &client_mode_list));
+
+ out:
+ silc_free(channel_id);
+ return 0;
+}
+
+/* Reply to USERS command. Received list of client ID's and theirs modes
+ on the channel we requested. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(users)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Query failed: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
+
+ if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ /* Do not resolve anymore. Server may be sending us some non-existent
+ Client ID (a bug in server), and we want to show the users list
+ anyway. */
+ silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
+ silc_client_command_reply_users_cb,
+ silc_client_command_reply_users);
goto out;
- }
- if (!silc_buffer_pull(&client_mode_list, 4)) {
- silc_rwlock_unlock(channel->internal.lock);
+ } else {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Query failed: %s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
}
- /* Notify application */
- silc_hash_table_list(channel->user_list, &htl);
- silc_client_command_callback(cmd, channel, &htl);
- silc_hash_table_list_reset(&htl);
+ if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
+ silc_client_command_reply_users_cb,
+ silc_client_command_reply_users))
+ return;
out:
- silc_client_unref_channel(client, conn, channel);
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+ silc_client_command_reply_free(cmd);
}
-/********************************** GETKEY **********************************/
-
/* Received command reply to GETKEY command. WE've received the remote
client's public key. */
-SILC_FSM_STATE(silc_client_command_reply_getkey)
+SILC_CLIENT_CMD_REPLY_FUNC(getkey)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcClientConnection conn = cmd->conn;
- SilcClient client = conn->client;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcIDPayload idp = NULL;
+ SilcClientID *client_id = NULL;
SilcClientEntry client_entry;
+ SilcServerID *server_id = NULL;
SilcServerEntry server_entry;
unsigned char *tmp;
SilcUInt32 len;
- SilcPublicKey public_key;
- SilcID id;
+ SilcIdType id_type;
+ SilcPublicKey public_key = NULL;
- /* Sanity checks */
- CHECK_STATUS("Cannot get key: ");
- CHECK_ARGS(2, 3);
+ SILC_LOG_DEBUG(("Start"));
- /* Get the ID */
- if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
goto out;
}
- /* Get the public key */
- tmp = silc_argument_get_arg_type(args, 3, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ idp = silc_id_payload_parse(tmp, len);
+ if (!idp) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- if (id.type == SILC_ID_CLIENT) {
+ /* Get the public key payload */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (tmp) {
+ if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+ public_key = NULL;
+ }
+
+ if (!public_key) {
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ id_type = silc_id_payload_get_type(idp);
+ if (id_type == SILC_ID_CLIENT) {
/* Received client's public key */
- client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
+ client_id = silc_id_payload_get_id(idp);
+ client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_rwlock_wrlock(client_entry->internal.lock);
-
/* Save fingerprint */
- if (!client_entry->fingerprint)
- silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
+ if (!client_entry->fingerprint) {
+ client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
+ client_entry->fingerprint_len = 20;
+ silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
client_entry->fingerprint);
+ }
if (!client_entry->public_key) {
client_entry->public_key = public_key;
public_key = NULL;
}
- silc_rwlock_unlock(client_entry->internal.lock);
-
/* Notify application */
- silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
- client_entry->public_key);
- silc_client_unref_client(client, conn, client_entry);
- } else if (id.type == SILC_ID_SERVER) {
+ COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
+ client_entry->public_key));
+ } else if (id_type == SILC_ID_SERVER) {
/* Received server's public key */
- server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
+ server_id = silc_id_payload_get_id(idp);
+ server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
if (!server_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- silc_rwlock_wrlock(server_entry->internal.lock);
-
- if (!server_entry->public_key) {
- server_entry->public_key = public_key;
- public_key = NULL;
- }
-
- silc_rwlock_unlock(server_entry->internal.lock);
-
/* Notify application */
- silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
- server_entry->public_key);
- silc_client_unref_server(client, conn, server_entry);
+ COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
}
out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
+ if (idp)
+ silc_id_payload_free(idp);
if (public_key)
silc_pkcs_public_key_free(public_key);
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ silc_free(client_id);
+ silc_free(server_id);
+ silc_client_command_reply_free(cmd);
}
-/********************************** SERVICE *********************************/
-
/* Reply to SERVICE command. */
/* XXX incomplete */
-SILC_FSM_STATE(silc_client_command_reply_service)
+SILC_CLIENT_CMD_REPLY_FUNC(service)
{
- SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
- SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcUInt32 tmp_len;
unsigned char *service_list, *name;
- /* Sanity checks */
- CHECK_STATUS("Cannot get service: ");
+ COMMAND_CHECK_STATUS;
/* Get service list */
- service_list = silc_argument_get_arg_type(args, 2, &tmp_len);
+ service_list = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
/* Get requested service name */
- name = silc_argument_get_arg_type(args, 3, &tmp_len);
+ name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+
+ /* Notify application */
+ COMMAND_REPLY((SILC_ARGS, service_list, name));
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SERVICE);
+ err:
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(quit)
+{
+ silc_client_command_reply_free(context);
+}
+
+
+/******************************************************************************
+
+ Internal command reply functions
+
+******************************************************************************/
+
+SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ COMMAND_CHECK_STATUS_I;
+
+ /* Save WHOIS info */
+ silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
+
+ err:
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
+ NULL, silc_client_command_reply_whois_i,
+ cmd->ident);
+
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ COMMAND_CHECK_STATUS_I;
+
+ /* Save IDENTIFY info */
+ silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
+
+ err:
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
+ NULL, silc_client_command_reply_identify_i,
+ cmd->ident);
+
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(info_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ unsigned char *tmp;
+ SilcServerEntry server;
+ SilcServerID *server_id = NULL;
+ char *server_name, *server_info;
+ SilcUInt32 len;
+
+ COMMAND_CHECK_STATUS_I;
+
+ /* Get server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ server_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!server_id)
+ goto out;
+
+ /* Get server name */
+ server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!server_name)
+ goto out;
+
+ /* Get server info */
+ server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (!server_info)
+ goto out;
+
+ /* See whether we have this server cached. If not create it. */
+ server = silc_client_get_server_by_id(cmd->client, conn, server_id);
+ if (!server) {
+ SILC_LOG_DEBUG(("New server entry"));
+ silc_client_add_server(cmd->client, conn, server_name, server_info,
+ silc_id_dup(server_id, SILC_ID_SERVER));
+ }
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
+ silc_free(server_id);
+ err:
+ silc_client_command_reply_free(cmd);
+}
+
+static void silc_client_command_reply_users_i_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry *channels,
+ SilcUInt32 channels_count,
+ void *context)
+{
+ if (!channels_count) {
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ silc_client_command_reply_users_i(context, NULL);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(users_i)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+
+ COMMAND_CHECK_STATUS_I;
+
+ /* Save USERS info */
+ if (silc_client_command_reply_users_save(
+ cmd, cmd->status, FALSE, TRUE,
+ silc_client_command_reply_users_i_cb,
+ silc_client_command_reply_users_i))
+ return;
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+
+ err:
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
+ NULL, silc_client_command_reply_users_i,
+ cmd->ident);
+
+ silc_client_command_reply_free(cmd);
+}
+
+/* Private range commands, specific to this implementation (and compatible
+ with SILC Server >= 0.9). */
+
+SILC_CLIENT_CMD_REPLY_FUNC(connect)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
/* Notify application */
- silc_client_command_callback(cmd, service_list, name);
+ COMMAND_REPLY((SILC_ARGS));
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
+ silc_client_command_reply_free(cmd);
}
-/*********************************** QUIT ***********************************/
+SILC_CLIENT_CMD_REPLY_FUNC(close)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
-/* QUIT command reply stub */
+ /* Notify application */
+ COMMAND_REPLY((SILC_ARGS));
-SILC_FSM_STATE(silc_client_command_reply_quit)
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
{
- silc_fsm_next(fsm, silc_client_command_reply_processed);
- return SILC_FSM_CONTINUE;
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ if (cmd->error != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(cmd->error));
+ COMMAND_REPLY_ERROR(cmd->error);
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((SILC_ARGS));
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
+ silc_client_command_reply_free(cmd);
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2006 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
#ifndef COMMAND_REPLY_H
#define COMMAND_REPLY_H
-SILC_FSM_STATE(silc_client_command_reply);
-SILC_FSM_STATE(silc_client_command_reply_wait);
-SILC_FSM_STATE(silc_client_command_reply_timeout);
-SILC_FSM_STATE(silc_client_command_reply_process);
-SILC_FSM_STATE(silc_client_command_reply_processed);
-SILC_FSM_STATE(silc_client_command_reply_whois);
-SILC_FSM_STATE(silc_client_command_reply_whowas);
-SILC_FSM_STATE(silc_client_command_reply_identify);
-SILC_FSM_STATE(silc_client_command_reply_nick);
-SILC_FSM_STATE(silc_client_command_reply_list);
-SILC_FSM_STATE(silc_client_command_reply_topic);
-SILC_FSM_STATE(silc_client_command_reply_invite);
-SILC_FSM_STATE(silc_client_command_reply_kill);
-SILC_FSM_STATE(silc_client_command_reply_info);
-SILC_FSM_STATE(silc_client_command_reply_stats);
-SILC_FSM_STATE(silc_client_command_reply_ping);
-SILC_FSM_STATE(silc_client_command_reply_oper);
-SILC_FSM_STATE(silc_client_command_reply_join);
-SILC_FSM_STATE(silc_client_command_reply_motd);
-SILC_FSM_STATE(silc_client_command_reply_umode);
-SILC_FSM_STATE(silc_client_command_reply_cmode);
-SILC_FSM_STATE(silc_client_command_reply_cumode);
-SILC_FSM_STATE(silc_client_command_reply_kick);
-SILC_FSM_STATE(silc_client_command_reply_ban);
-SILC_FSM_STATE(silc_client_command_reply_detach);
-SILC_FSM_STATE(silc_client_command_reply_watch);
-SILC_FSM_STATE(silc_client_command_reply_silcoper);
-SILC_FSM_STATE(silc_client_command_reply_leave);
-SILC_FSM_STATE(silc_client_command_reply_users);
-SILC_FSM_STATE(silc_client_command_reply_getkey);
-SILC_FSM_STATE(silc_client_command_reply_service);
-SILC_FSM_STATE(silc_client_command_reply_quit);
-
-#endif /* COMMAND_REPLY_H */
+/* Structure holding one command reply and pointer to its function. */
+typedef struct {
+ SilcCommandCb cb;
+ SilcCommand cmd;
+} SilcClientCommandReply;
+
+/* Context holding pending command callbacks. */
+typedef struct {
+ SilcCommandCb callback;
+ void *context;
+} *SilcClientCommandPendingCallbacks;
+
+/* Context sent as argument to all command reply functions */
+struct SilcClientCommandReplyContextStruct {
+ SilcClient client;
+ SilcSocketConnection sock;
+ SilcCommandPayload payload;
+ SilcStatus status;
+ SilcStatus error;
+ SilcArgumentPayload args;
+ SilcPacketContext *packet;
+
+ /* If defined this executes the pending command. */
+ SilcClientCommandPendingCallbacks callbacks;
+ SilcUInt32 callbacks_count;
+ SilcUInt16 ident;
+ SilcUInt8 users;
+};
+
+/* Macros */
+
+/* Command reply operation that is called at the end of all command replys.
+ Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
+#define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
+#define SILC_ARGS cmd->client, cmd->sock->user_data, \
+ cmd->payload, TRUE, silc_command_get(cmd->payload), cmd->status
+
+/* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
+#define COMMAND_REPLY_ERROR(error) \
+do { \
+ if (cmd->status == SILC_STATUS_OK) { \
+ cmd->client->internal->ops-> \
+ command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
+ FALSE, silc_command_get(cmd->payload), error); \
+ } else { \
+ void *arg1 = NULL, *arg2 = NULL; \
+ silc_status_get_args(cmd->status, cmd->args, &arg1, &arg2); \
+ cmd->client->internal->ops-> \
+ command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
+ FALSE, silc_command_get(cmd->payload), cmd->status, \
+ arg1, arg2); \
+ silc_free(arg1); \
+ silc_free(arg2); \
+ } \
+} while(0)
+
+/* Macro used to declare command reply functions */
+#define SILC_CLIENT_CMD_REPLY_FUNC(func) \
+void silc_client_command_reply_##func(void *context, void *context2)
+
+/* Prototypes */
+
+void silc_client_command_reply_process(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_client_command_reply_free(SilcClientCommandReplyContext cmd);
+SILC_CLIENT_CMD_REPLY_FUNC(whois);
+SILC_CLIENT_CMD_REPLY_FUNC(whowas);
+SILC_CLIENT_CMD_REPLY_FUNC(identify);
+SILC_CLIENT_CMD_REPLY_FUNC(nick);
+SILC_CLIENT_CMD_REPLY_FUNC(list);
+SILC_CLIENT_CMD_REPLY_FUNC(topic);
+SILC_CLIENT_CMD_REPLY_FUNC(invite);
+SILC_CLIENT_CMD_REPLY_FUNC(kill);
+SILC_CLIENT_CMD_REPLY_FUNC(info);
+SILC_CLIENT_CMD_REPLY_FUNC(stats);
+SILC_CLIENT_CMD_REPLY_FUNC(ping);
+SILC_CLIENT_CMD_REPLY_FUNC(oper);
+SILC_CLIENT_CMD_REPLY_FUNC(join);
+SILC_CLIENT_CMD_REPLY_FUNC(motd);
+SILC_CLIENT_CMD_REPLY_FUNC(umode);
+SILC_CLIENT_CMD_REPLY_FUNC(cmode);
+SILC_CLIENT_CMD_REPLY_FUNC(cumode);
+SILC_CLIENT_CMD_REPLY_FUNC(kick);
+SILC_CLIENT_CMD_REPLY_FUNC(ban);
+SILC_CLIENT_CMD_REPLY_FUNC(detach);
+SILC_CLIENT_CMD_REPLY_FUNC(watch);
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper);
+SILC_CLIENT_CMD_REPLY_FUNC(leave);
+SILC_CLIENT_CMD_REPLY_FUNC(users);
+SILC_CLIENT_CMD_REPLY_FUNC(getkey);
+SILC_CLIENT_CMD_REPLY_FUNC(service);
+SILC_CLIENT_CMD_REPLY_FUNC(quit);
+
+/* Internal command reply functions */
+SILC_CLIENT_CMD_REPLY_FUNC(whois_i);
+SILC_CLIENT_CMD_REPLY_FUNC(identify_i);
+SILC_CLIENT_CMD_REPLY_FUNC(info_i);
+SILC_CLIENT_CMD_REPLY_FUNC(users_i);
+
+SILC_CLIENT_CMD_REPLY_FUNC(connect);
+SILC_CLIENT_CMD_REPLY_FUNC(close);
+SILC_CLIENT_CMD_REPLY_FUNC(shutdown);
+
+#endif
--- /dev/null
+/*
+
+ idlist.c
+
+ 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
+ GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+#include "silcclient.h"
+#include "client_internal.h"
+
+/******************************************************************************
+
+ Client Searching Locally
+
+******************************************************************************/
+
+/* Same as silc_client_get_clients function but does not resolve anything
+ from the server. This checks local cache and returns all matching
+ clients from the local cache. If none was found this returns NULL.
+ The `nickname' is the real nickname of the client, and the `format'
+ is the formatted nickname to find exact match from multiple found
+ entries. The format must be same as given in the SilcClientParams
+ structure to the client library. If the `format' is NULL all found
+ clients by `nickname' are returned. */
+
+SilcClientEntry *silc_client_get_clients_local(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *format,
+ SilcUInt32 *clients_count)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list = NULL;
+ SilcClientEntry entry, *clients;
+ int i = 0;
+ bool found = FALSE;
+ char *nicknamec;
+
+ assert(client && conn);
+ if (!nickname)
+ return NULL;
+
+ /* Normalize nickname for search */
+ nicknamec = silc_identifier_check(nickname, strlen(nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nicknamec)
+ return NULL;
+
+ /* Find ID from cache */
+ if (!silc_idcache_find_by_name(conn->internal->client_cache, nicknamec,
+ &list)) {
+ silc_free(nicknamec);
+ return NULL;
+ }
+
+ if (!silc_idcache_list_count(list)) {
+ silc_idcache_list_free(list);
+ silc_free(nicknamec);
+ return NULL;
+ }
+
+ clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
+ *clients_count = silc_idcache_list_count(list);
+
+ if (!format) {
+ /* Take all without any further checking */
+ silc_idcache_list_first(list, &id_cache);
+ while (id_cache) {
+ clients[i++] = id_cache->context;
+ found = TRUE;
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ } else {
+ /* Check multiple cache entries for match */
+ silc_idcache_list_first(list, &id_cache);
+ while (id_cache) {
+ entry = (SilcClientEntry)id_cache->context;
+ if (!silc_utf8_strcasecmp(entry->nickname, format)) {
+ if (!silc_idcache_list_next(list, &id_cache)) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ clients[i++] = id_cache->context;
+ found = TRUE;
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_free(nicknamec);
+
+ if (list)
+ silc_idcache_list_free(list);
+
+ if (!found) {
+ *clients_count = 0;
+ if (clients)
+ silc_free(clients);
+ return NULL;
+ }
+
+ return clients;
+}
+
+
+/******************************************************************************
+
+ Client Resolving from Server
+
+******************************************************************************/
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcGetClientCallback completion;
+ void *context;
+ char *nickname;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
+} *GetClientInternal;
+
+/* Completion for IDENTIFY */
+
+SILC_CLIENT_CMD_FUNC(get_client_callback)
+{
+ GetClientInternal i = (GetClientInternal)context;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
+
+ /* Get the clients */
+ clients = silc_client_get_clients_local(i->client, i->conn,
+ i->nickname, NULL,
+ &clients_count);
+ if (clients) {
+ i->completion(i->client, i->conn, clients, clients_count, i->context);
+ silc_free(clients);
+ } else {
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
+
+ silc_free(i->nickname);
+ silc_free(i);
+}
+
+/* Completion for WHOIS */
+
+SILC_CLIENT_CMD_FUNC(get_client_callback_wc)
+{
+ GetClientInternal i = (GetClientInternal)context;
+ SilcClientCommandReplyContext cmd = context2;
+ SilcClientID *client_id = NULL;
+ SilcClientEntry client_entry = NULL;
+ unsigned char *id_data;
+ SilcUInt32 len;
+
+ /* Get the client entry just returned from server */
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (id_data)
+ client_id = silc_id_payload_parse_id(id_data, len, NULL);
+ if (client_id)
+ client_entry = silc_client_get_client_by_id(i->client,
+ i->conn, client_id);
+ if (!client_entry) {
+ if (!SILC_STATUS_IS_ERROR(cmd->status) &&
+ cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_free(client_id);
+ return;
+ }
+
+ i->completion(i->client, i->conn, i->clients, i->clients_count,
+ i->context);
+ silc_free(client_id);
+ silc_free(i->clients);
+ silc_free(i->nickname);
+ silc_free(i);
+ return;
+ }
+
+ /* Save the client */
+ i->clients = silc_realloc(i->clients,
+ (sizeof(*i->clients) * (i->clients_count + 1)));
+ i->clients[i->clients_count] = client_entry;
+ i->clients_count++;
+
+ /* Return if more data is expected */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ silc_free(client_id);
+ return;
+ }
+
+ i->completion(i->client, i->conn, i->clients, i->clients_count,
+ i->context);
+
+ silc_free(client_id);
+ silc_free(i->clients);
+ silc_free(i->nickname);
+ silc_free(i);
+}
+
+/* Our own WHOIS reply processor. */
+
+SILC_CLIENT_CMD_FUNC(get_client_callback_w)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_command_get_status(cmd->payload, NULL, NULL)) {
+ if (SILC_STATUS_IS_ERROR(cmd->status))
+ goto out;
+ if (cmd->status == SILC_STATUS_LIST_END)
+ goto out;
+ goto err;
+ }
+
+ /* Save WHOIS info */
+ silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
+
+ /* Call pending completion for each reply */
+ if (cmd->status != SILC_STATUS_OK &&
+ cmd->status != SILC_STATUS_LIST_END) {
+ if (cmd->callbacks[0].callback)
+ (*cmd->callbacks[0].callback)(cmd->callbacks[0].context, cmd);
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
+
+ err:
+ /* If we received notify for invalid ID we'll remove the ID if we
+ have it cached. */
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+ SilcUInt32 tmp_len;
+ unsigned char *tmp =
+ silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
+ 2, &tmp_len);
+ if (tmp) {
+ SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (client_id) {
+ client_entry = silc_client_get_client_by_id(cmd->client, conn,
+ client_id);
+ if (client_entry)
+ silc_client_del_client(cmd->client, conn, client_entry);
+ silc_free(client_id);
+ }
+ }
+ }
+
+ /* Unregister this command reply */
+ silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
+ NULL, silc_client_command_reply_whois_i,
+ cmd->ident);
+ silc_client_command_reply_free(cmd);
+}
+
+/* Finds client entry or entries by the `nickname' and `server'. The
+ completion callback will be called when the client entries has been found.
+
+ Note: this function is always asynchronous and resolves the client
+ information from the server. Thus, if you already know the client
+ information then use the silc_client_get_client_by_id function to
+ get the client entry since this function may be very slow and should
+ be used only to initially get the client entries. */
+
+void silc_client_get_clients_i(SilcClient client,
+ SilcClientConnection conn,
+ SilcCommand command,
+ const char *nickname,
+ const char *server,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ GetClientInternal i;
+ int len;
+ char *userhost = NULL;
+
+ assert(client && conn);
+
+ if (!nickname && !attributes)
+ return;
+
+ i = silc_calloc(1, sizeof(*i));
+ i->client = client;
+ i->conn = conn;
+ i->nickname = nickname ? strdup(nickname) : NULL;
+ i->completion = completion;
+ i->context = context;
+
+ if (nickname && server) {
+ len = strlen(nickname) + strlen(server) + 3;
+ userhost = silc_calloc(len, sizeof(*userhost));
+ silc_strncat(userhost, len, nickname, strlen(nickname));
+ silc_strncat(userhost, len, "@", 1);
+ silc_strncat(userhost, len, server, strlen(server));
+ } else if (nickname) {
+ userhost = silc_memdup(nickname, strlen(nickname));
+ }
+
+ /* Register our own command reply for this command */
+ if (command == SILC_COMMAND_IDENTIFY) {
+ silc_client_command_register(client, command, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+ /* Send the command */
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 1, userhost,
+ strlen(userhost));
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, command, conn->cmd_ident,
+ silc_client_command_get_client_callback,
+ (void *)i);
+ } else {
+ silc_client_command_register(client, command, NULL, NULL,
+ silc_client_command_get_client_callback_w, 0,
+ ++conn->cmd_ident);
+ /* Send the command */
+ silc_client_command_send(client, conn, command, conn->cmd_ident, 2,
+ 1, userhost, userhost ? strlen(userhost) : 0,
+ 3, attributes ? attributes->data : NULL,
+ attributes ? attributes->len : 0);
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, command, conn->cmd_ident,
+ silc_client_command_get_client_callback_wc,
+ (void *)i);
+ }
+ silc_free(userhost);
+}
+
+void silc_client_get_clients(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *server,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ silc_client_get_clients_i(client, conn, SILC_COMMAND_IDENTIFY,
+ nickname, server, NULL,
+ completion, context);
+}
+
+void silc_client_get_clients_whois(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *server,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ silc_client_get_clients_i(client, conn, SILC_COMMAND_WHOIS,
+ nickname, server, attributes,
+ completion, context);
+}
+
+/* The old style function to find client entry. This is used by the
+ library internally. If `query' is TRUE then the client information is
+ requested by the server. The pending command callback must be set
+ by the caller. */
+/* XXX This function should be removed */
+
+SilcClientEntry silc_idlist_get_client(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *format,
+ bool query)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list = NULL;
+ SilcClientEntry entry = NULL;
+ char *nicknamec;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Normalize nickname for search */
+ nicknamec = silc_identifier_check(nickname, strlen(nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nicknamec)
+ return NULL;
+
+ /* Find ID from cache */
+ if (!silc_idcache_find_by_name(conn->internal->client_cache,
+ nicknamec, &list)) {
+ identify:
+
+ if (query) {
+ SILC_LOG_DEBUG(("Requesting Client ID from server"));
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 1, nickname,
+ strlen(nickname));
+
+ if (list)
+ silc_idcache_list_free(list);
+
+ silc_free(nicknamec);
+ return NULL;
+ }
+
+ silc_free(nicknamec);
+ return NULL;
+ }
+
+ if (!format) {
+ /* Take first found cache entry */
+ if (!silc_idcache_list_first(list, &id_cache))
+ goto identify;
+
+ entry = (SilcClientEntry)id_cache->context;
+ } else {
+ /* Check multiple cache entries for match */
+ silc_idcache_list_first(list, &id_cache);
+ while (id_cache) {
+ entry = (SilcClientEntry)id_cache->context;
+
+ if (!silc_utf8_strcasecmp(entry->nickname, format)) {
+ if (!silc_idcache_list_next(list, &id_cache)) {
+ entry = NULL;
+ break;
+ } else {
+ entry = NULL;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ /* If match weren't found, request it */
+ if (!entry)
+ goto identify;
+ }
+
+ silc_free(nicknamec);
+
+ if (list)
+ silc_idcache_list_free(list);
+
+ return entry;
+}
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcUInt32 list_count;
+ SilcBuffer client_id_list;
+ SilcGetClientCallback completion;
+ void *context;
+ int res_count;
+} *GetClientsByListInternal;
+
+SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
+{
+ GetClientsByListInternal i = (GetClientsByListInternal)context;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcBuffer client_id_list = i->client_id_list;
+ SilcClientEntry *clients = NULL;
+ SilcUInt32 clients_count = 0;
+ bool found = FALSE;
+ int c;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (i->res_count) {
+ i->res_count--;
+ if (i->res_count)
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Resolved all clients"));
+
+ clients = silc_calloc(i->list_count, sizeof(*clients));
+
+ for (c = 0; c < i->list_count; c++) {
+ SilcUInt16 idp_len;
+ SilcClientID *client_id;
+
+ /* Get Client ID */
+ SILC_GET16_MSB(idp_len, client_id_list->data + 2);
+ idp_len += 4;
+ client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
+ if (!client_id) {
+ silc_buffer_pull(client_id_list, idp_len);
+ continue;
+ }
+
+ /* Get the client entry */
+ if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache,
+ (void *)client_id,
+ NULL, NULL,
+ silc_hash_client_id_compare, NULL,
+ &id_cache)) {
+ clients[clients_count] = (SilcClientEntry)id_cache->context;
+ clients_count++;
+ found = TRUE;
+ }
+
+ silc_free(client_id);
+ silc_buffer_pull(client_id_list, idp_len);
+ }
+
+ if (found) {
+ i->completion(i->client, i->conn, clients, clients_count, i->context);
+ silc_free(clients);
+ } else {
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
+
+ if (i->client_id_list)
+ silc_buffer_free(i->client_id_list);
+ silc_free(i);
+}
+
+/* Gets client entries by the list of client ID's `client_id_list'. This
+ always resolves those client ID's it does not know yet from the server
+ so this function might take a while. The `client_id_list' is a list
+ of ID Payloads added one after other. JOIN command reply and USERS
+ command reply for example returns this sort of list. The `completion'
+ will be called after the entries are available. */
+
+void silc_client_get_clients_by_list(SilcClient client,
+ SilcClientConnection conn,
+ SilcUInt32 list_count,
+ SilcBuffer client_id_list,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ SilcIDCacheEntry id_cache = NULL;
+ int i;
+ unsigned char **res_argv = NULL;
+ SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+ GetClientsByListInternal in;
+ bool wait_res = FALSE;
+
+ assert(client && conn && client_id_list);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ in = silc_calloc(1, sizeof(*in));
+ in->client = client;
+ in->conn = conn;
+ in->list_count = list_count;
+ in->client_id_list = silc_buffer_copy(client_id_list);
+ in->completion = completion;
+ in->context = context;
+
+ for (i = 0; i < list_count; i++) {
+ SilcUInt16 idp_len;
+ SilcClientID *client_id;
+ SilcClientEntry entry;
+ bool ret;
+
+ /* Get Client ID */
+ SILC_GET16_MSB(idp_len, client_id_list->data + 2);
+ idp_len += 4;
+ client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
+ if (!client_id) {
+ silc_buffer_pull(client_id_list, idp_len);
+ continue;
+ }
+
+ /* Check if we have this client cached already. */
+ ret =
+ silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
+ (void *)client_id, NULL, NULL,
+ silc_hash_client_id_compare, NULL,
+ &id_cache);
+
+ /* If we don't have the entry or it has incomplete info, then resolve
+ it from the server. */
+ if (!ret || !((SilcClientEntry)id_cache->context)->nickname) {
+ entry = ret ? (SilcClientEntry)id_cache->context : NULL;
+
+ if (entry) {
+ if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to this resolving and wait until it finishes */
+ silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
+ silc_client_command_get_clients_list_callback,
+ (void *)in);
+ wait_res = TRUE;
+ in->res_count++;
+
+ silc_free(client_id);
+ silc_buffer_pull(client_id_list, idp_len);
+ continue;
+ }
+
+ entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ entry->resolve_cmd_ident = conn->cmd_ident + 1;
+ }
+
+ /* No we don't have it, query it from the server. Assemble argument
+ table that will be sent for the IDENTIFY command later. */
+ res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
+ (res_argc + 1));
+ res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+ (res_argc + 1));
+ res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+ (res_argc + 1));
+ res_argv[res_argc] = client_id_list->data;
+ res_argv_lens[res_argc] = idp_len;
+ res_argv_types[res_argc] = res_argc + 5;
+ res_argc++;
+ }
+
+ silc_free(client_id);
+ silc_buffer_pull(client_id_list, idp_len);
+ }
+
+ silc_buffer_push(client_id_list, client_id_list->data -
+ client_id_list->head);
+
+ /* Query the client information from server if the list included clients
+ that we don't know about. */
+ if (res_argc) {
+ SilcBuffer res_cmd;
+
+ /* Send the IDENTIFY command to server */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
+ res_argc, res_argv, res_argv_lens,
+ res_argv_types, ++conn->cmd_ident);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
+ TRUE);
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ conn->cmd_ident);
+
+ /* Process the applications request after reply has been received */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+ silc_client_command_get_clients_list_callback,
+ (void *)in);
+ in->res_count++;
+
+ silc_buffer_free(res_cmd);
+ silc_free(res_argv);
+ silc_free(res_argv_lens);
+ silc_free(res_argv_types);
+ return;
+ }
+
+ if (wait_res)
+ return;
+
+ /* We have the clients in cache, get them and call the completion */
+ silc_client_command_get_clients_list_callback((void *)in, NULL);
+}
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcChannelID channel_id;
+ SilcGetClientCallback completion;
+ void *context;
+ int res_count;
+} *GetClientsByChannelInternal;
+
+SILC_CLIENT_CMD_FUNC(get_clients_by_channel_cb)
+{
+ GetClientsByChannelInternal i = context;
+ SilcClientEntry *clients = NULL;
+ SilcUInt32 clients_count = 0;
+ bool found = FALSE;
+ SilcChannelEntry channel;
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+
+ if (i->res_count) {
+ i->res_count--;
+ if (i->res_count)
+ return;
+ }
+
+ channel = silc_client_get_channel_by_id(i->client, i->conn, &i->channel_id);
+ if (channel && !silc_hash_table_count(channel->user_list)) {
+ clients = silc_calloc(silc_hash_table_count(channel->user_list),
+ sizeof(*clients));
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu))
+ clients[clients_count++] = chu->client;
+ silc_hash_table_list_reset(&htl);
+ found = TRUE;
+ }
+
+ if (found) {
+ i->completion(i->client, i->conn, clients, clients_count, i->context);
+ silc_free(clients);
+ } else {
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
+
+ silc_free(i);
+}
+
+/* Gets client entries by the channel entry indicated by `channel'. Thus,
+ it resolves the clients currently on that channel. */
+
+void silc_client_get_clients_by_channel(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ GetClientsByChannelInternal in;
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+ SilcClientEntry entry;
+ unsigned char **res_argv = NULL;
+ SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+ SilcBuffer idp;
+ bool wait_res = FALSE;
+
+ assert(client && conn && channel);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ in = silc_calloc(1, sizeof(*in));
+ in->client = client;
+ in->conn = conn;
+ in->channel_id = *channel->id;
+ in->completion = completion;
+ in->context = context;
+
+ /* If user list does not exist, send USERS command. */
+ if (!channel->user_list || !silc_hash_table_count(channel->user_list)) {
+ SILC_LOG_DEBUG(("Sending USERS"));
+ silc_client_command_register(client, SILC_COMMAND_USERS, NULL, NULL,
+ silc_client_command_reply_users_i, 0,
+ ++conn->cmd_ident);
+ silc_client_command_send(client, conn, SILC_COMMAND_USERS,
+ conn->cmd_ident, 1, 2, channel->channel_name,
+ strlen(channel->channel_name));
+ silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
+ silc_client_command_get_clients_by_channel_cb,
+ in);
+ return;
+ }
+
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ entry = chu->client;
+
+ /* If the entry has incomplete info, then resolve it from the server. */
+ if (!entry->nickname || !entry->realname) {
+ if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to this resolving and wait until it finishes */
+ silc_client_command_pending(
+ conn, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
+ silc_client_command_get_clients_by_channel_cb,
+ (void *)in);
+ wait_res = TRUE;
+ in->res_count++;
+ continue;
+ }
+ entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ entry->resolve_cmd_ident = conn->cmd_ident + 1;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+
+ /* No we don't have it, query it from the server. Assemble argument
+ table that will be sent for the WHOIS command later. */
+ res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
+ (res_argc + 1));
+ res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+ (res_argc + 1));
+ res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+ (res_argc + 1));
+ res_argv[res_argc] = silc_memdup(idp->data, idp->len);
+ res_argv_lens[res_argc] = idp->len;
+ res_argv_types[res_argc] = res_argc + 4;
+ res_argc++;
+
+ silc_buffer_free(idp);
+ }
+ }
+ silc_hash_table_list_reset(&htl);
+
+ /* Query the client information from server if the list included clients
+ that we don't know about. */
+ if (res_argc) {
+ SilcBuffer res_cmd;
+
+ /* Send the WHOIS command to server */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ res_argc, res_argv, res_argv_lens,
+ res_argv_types, ++conn->cmd_ident);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
+ TRUE);
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ conn->cmd_ident);
+
+ /* Process the applications request after reply has been received */
+ silc_client_command_pending(
+ conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ silc_client_command_get_clients_by_channel_cb,
+ (void *)in);
+ in->res_count++;
+
+ silc_buffer_free(res_cmd);
+ silc_free(res_argv);
+ silc_free(res_argv_lens);
+ silc_free(res_argv_types);
+ return;
+ }
+
+ if (wait_res)
+ return;
+
+ /* We have the clients in cache, get them and call the completion */
+ silc_client_command_get_clients_by_channel_cb((void *)in, NULL);
+}
+
+/* Finds entry for client by the client's ID. Returns the entry or NULL
+ if the entry was not found. */
+
+SilcClientEntry silc_client_get_client_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientID *client_id)
+{
+ SilcIDCacheEntry id_cache;
+
+ assert(client && conn);
+ if (!client_id)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Finding client by ID (%s)",
+ silc_id_render(client_id, SILC_ID_CLIENT)));
+
+ /* Find ID from cache */
+ if (!silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
+ (void *)client_id, NULL, NULL,
+ silc_hash_client_id_compare, NULL,
+ &id_cache))
+ return NULL;
+
+ SILC_LOG_DEBUG(("Found"));
+
+ return (SilcClientEntry)id_cache->context;
+}
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcClientID *client_id;
+ SilcGetClientCallback completion;
+ void *context;
+} *GetClientByIDInternal;
+
+SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
+{
+ GetClientByIDInternal i = (GetClientByIDInternal)context;
+ SilcClientEntry entry;
+
+ /* Get the client */
+ entry = silc_client_get_client_by_id(i->client, i->conn, i->client_id);
+ if (entry) {
+ if (i->completion)
+ i->completion(i->client, i->conn, &entry, 1, i->context);
+ } else {
+ if (i->completion)
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
+
+ silc_free(i->client_id);
+ silc_free(i);
+}
+
+/* Same as above but will always resolve the information from the server.
+ Use this only if you know that you don't have the entry and the only
+ thing you know about the client is its ID. */
+
+void silc_client_get_client_by_id_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientID *client_id,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context)
+{
+ SilcBuffer idp;
+ GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
+
+ assert(client && conn && client_id);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ i->client = client;
+ i->conn = conn;
+ i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
+ i->completion = completion;
+ i->context = context;
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
+ silc_client_command_reply_whois_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+ silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ 2, 3, attributes ? attributes->data : NULL,
+ attributes ? attributes->len : 0,
+ 4, idp->data, idp->len);
+ silc_buffer_free(idp);
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ silc_client_command_get_client_by_id_callback,
+ (void *)i);
+}
+
+
+/******************************************************************************
+
+ Client, Channel and Server entry manipulation
+
+******************************************************************************/
+
+
+/* Creates new client entry and adds it to the ID cache. Returns pointer
+ to the new entry. */
+
+SilcClientEntry
+silc_client_add_client(SilcClient client, SilcClientConnection conn,
+ char *nickname, char *username,
+ char *userinfo, SilcClientID *id, SilcUInt32 mode)
+{
+ SilcClientEntry client_entry;
+ char *nick = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Save the client infos */
+ client_entry = silc_calloc(1, sizeof(*client_entry));
+ client_entry->id = id;
+ client_entry->valid = TRUE;
+ silc_parse_userfqdn(nickname, &nick, &client_entry->server);
+ silc_parse_userfqdn(username, &client_entry->username,
+ &client_entry->hostname);
+ if (userinfo)
+ client_entry->realname = strdup(userinfo);
+ client_entry->mode = mode;
+ if (nick)
+ client_entry->nickname = strdup(nick);
+ client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
+ NULL, NULL, NULL, TRUE);
+
+ /* Normalize nickname */
+ if (client_entry->nickname) {
+ silc_free(nick);
+ nick = silc_identifier_check(client_entry->nickname,
+ strlen(client_entry->nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nick) {
+ silc_free(client_entry->nickname);
+ silc_free(client_entry->username);
+ silc_free(client_entry->hostname);
+ silc_free(client_entry->server);
+ silc_hash_table_free(client_entry->channels);
+ silc_free(client_entry);
+ return NULL;
+ }
+ }
+
+ /* Format the nickname */
+ silc_client_nickname_format(client, conn, client_entry);
+
+ /* Add client to cache, the non-formatted nickname is saved to cache */
+ if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
+ (void *)client_entry, 0, NULL)) {
+ silc_free(nick);
+ silc_free(client_entry->nickname);
+ silc_free(client_entry->username);
+ silc_free(client_entry->hostname);
+ silc_free(client_entry->server);
+ silc_hash_table_free(client_entry->channels);
+ silc_free(client_entry);
+ return NULL;
+ }
+
+ return client_entry;
+}
+
+/* Updates the `client_entry' with the new information sent as argument. */
+
+void silc_client_update_client(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *nickname,
+ const char *username,
+ const char *userinfo,
+ SilcUInt32 mode)
+{
+ char *nick = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if ((!client_entry->username || !client_entry->hostname) && username) {
+ silc_free(client_entry->username);
+ silc_free(client_entry->hostname);
+ client_entry->username = NULL;
+ client_entry->hostname = NULL;
+ silc_parse_userfqdn(username, &client_entry->username,
+ &client_entry->hostname);
+ }
+ if (!client_entry->realname && userinfo)
+ client_entry->realname = strdup(userinfo);
+ if (!client_entry->nickname && nickname) {
+ silc_parse_userfqdn(nickname, &nick, &client_entry->server);
+ client_entry->nickname = strdup(nick);
+
+ /* Normalize nickname */
+ silc_free(nick);
+ nick = silc_identifier_check(client_entry->nickname,
+ strlen(client_entry->nickname),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!nick)
+ return;
+
+ /* Format nickname */
+ silc_client_nickname_format(client, conn, client_entry);
+ }
+ client_entry->mode = mode;
+
+ if (nick) {
+ /* Remove the old cache entry and create a new one */
+ silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
+ silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
+ client_entry, 0, NULL);
+ }
+}
+
+/* Deletes the client entry and frees all memory. */
+
+void silc_client_del_client_entry(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SILC_LOG_DEBUG(("Start"));
+
+ silc_free(client_entry->nickname);
+ silc_free(client_entry->username);
+ silc_free(client_entry->realname);
+ silc_free(client_entry->hostname);
+ silc_free(client_entry->server);
+ silc_free(client_entry->id);
+ silc_free(client_entry->fingerprint);
+ if (client_entry->public_key)
+ silc_pkcs_public_key_free(client_entry->public_key);
+ silc_hash_table_free(client_entry->channels);
+ if (client_entry->send_key)
+ silc_cipher_free(client_entry->send_key);
+ if (client_entry->receive_key)
+ silc_cipher_free(client_entry->receive_key);
+ silc_free(client_entry->key);
+ silc_client_ftp_session_free_client(conn, client_entry);
+ if (client_entry->ke)
+ silc_client_abort_key_agreement(client, conn, client_entry);
+ silc_free(client_entry);
+}
+
+/* Removes client from the cache by the client entry. */
+
+bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ bool ret = silc_idcache_del_by_context(conn->internal->client_cache,
+ client_entry);
+
+ if (ret) {
+ /* Remove from channels */
+ silc_client_remove_from_channels(client, conn, client_entry);
+
+ /* Free the client entry data */
+ silc_client_del_client_entry(client, conn, client_entry);
+ }
+
+ return ret;
+}
+
+/* Add new channel entry to the ID Cache */
+
+SilcChannelEntry silc_client_add_channel(SilcClient client,
+ SilcClientConnection conn,
+ const char *channel_name,
+ SilcUInt32 mode,
+ SilcChannelID *channel_id)
+{
+ SilcChannelEntry channel;
+ char *channel_namec;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ channel = silc_calloc(1, sizeof(*channel));
+ channel->channel_name = strdup(channel_name);
+ channel->id = channel_id;
+ channel->mode = mode;
+ channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
+ NULL, NULL, NULL, TRUE);
+
+ /* Normalize channel name */
+ channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!channel_namec) {
+ silc_free(channel->channel_name);
+ silc_hash_table_free(channel->user_list);
+ silc_free(channel);
+ return NULL;
+ }
+
+ /* Put it to the ID cache */
+ if (!silc_idcache_add(conn->internal->channel_cache, channel_namec,
+ (void *)channel->id, (void *)channel, 0, NULL)) {
+ silc_free(channel_namec);
+ silc_free(channel->channel_name);
+ silc_hash_table_free(channel->user_list);
+ silc_free(channel);
+ return NULL;
+ }
+
+ return channel;
+}
+
+/* Foreach callbcak to free all users from the channel when deleting a
+ channel entry. */
+
+static void silc_client_del_channel_foreach(void *key, void *context,
+ void *user_context)
+{
+ SilcChannelUser chu = (SilcChannelUser)context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* 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(chu->client->channels, chu->channel);
+ silc_free(chu);
+}
+
+/* Removes channel from the cache by the channel entry. */
+
+bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
+ SilcChannelEntry channel)
+{
+ bool ret = silc_idcache_del_by_context(conn->internal->channel_cache,
+ channel);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Free all client entrys from the users list. The silc_hash_table_free
+ will free all the entries so they are not freed at the foreach
+ callback. */
+ silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
+ NULL);
+ silc_hash_table_free(channel->user_list);
+
+ silc_free(channel->channel_name);
+ silc_free(channel->topic);
+ silc_free(channel->id);
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ silc_free(channel->key);
+ if (channel->channel_key)
+ silc_cipher_free(channel->channel_key);
+ if (channel->hmac)
+ silc_hmac_free(channel->hmac);
+ if (channel->old_channel_keys) {
+ SilcCipher key;
+ silc_dlist_start(channel->old_channel_keys);
+ while ((key = silc_dlist_get(channel->old_channel_keys)) != SILC_LIST_END)
+ silc_cipher_free(key);
+ silc_dlist_uninit(channel->old_channel_keys);
+ }
+ if (channel->old_hmacs) {
+ SilcHmac hmac;
+ silc_dlist_start(channel->old_hmacs);
+ while ((hmac = silc_dlist_get(channel->old_hmacs)) != SILC_LIST_END)
+ silc_hmac_free(hmac);
+ silc_dlist_uninit(channel->old_hmacs);
+ }
+ silc_schedule_task_del_by_context(conn->client->schedule, channel);
+ silc_client_del_channel_private_keys(client, conn, channel);
+ silc_free(channel);
+ return ret;
+}
+
+/* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
+ if the ID could not be changed. */
+
+bool silc_client_replace_channel_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcChannelID *new_id)
+{
+ char *channel_namec;
+
+ if (!new_id)
+ return FALSE;
+
+ SILC_LOG_DEBUG(("Old Channel ID id(%s)",
+ silc_id_render(channel->id, SILC_ID_CHANNEL)));
+ SILC_LOG_DEBUG(("New Channel ID id(%s)",
+ silc_id_render(new_id, SILC_ID_CHANNEL)));
+
+ silc_idcache_del_by_id(conn->internal->channel_cache, channel->id);
+ silc_free(channel->id);
+ channel->id = new_id;
+
+ /* Normalize channel name */
+ channel_namec = silc_channel_name_check(channel->channel_name,
+ strlen(channel->channel_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!channel_namec)
+ return FALSE;
+
+ return silc_idcache_add(conn->internal->channel_cache, channel_namec,
+ (void *)channel->id, (void *)channel, 0, NULL);
+
+}
+
+/* Finds entry for channel by the channel name. Returns the entry or NULL
+ if the entry was not found. It is found only if the client is joined
+ to the channel. */
+
+SilcChannelEntry silc_client_get_channel(SilcClient client,
+ SilcClientConnection conn,
+ char *channel)
+{
+ SilcIDCacheEntry id_cache;
+ SilcChannelEntry entry;
+
+ assert(client && conn);
+ if (!channel)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Normalize name for search */
+ channel = silc_channel_name_check(channel, strlen(channel), SILC_STRING_UTF8,
+ 256, NULL);
+ if (!channel)
+ return NULL;
+
+ if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
+ &id_cache)) {
+ silc_free(channel);
+ return NULL;
+ }
+
+ entry = (SilcChannelEntry)id_cache->context;
+
+ SILC_LOG_DEBUG(("Found"));
+
+ silc_free(channel);
+
+ return entry;
+}
+
+/* Finds entry for channel by the channel ID. Returns the entry or NULL
+ if the entry was not found. It is found only if the client is joined
+ to the channel. */
+
+SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelID *channel_id)
+{
+ SilcIDCacheEntry id_cache;
+ SilcChannelEntry entry;
+
+ assert(client && conn);
+ if (!channel_id)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
+ &id_cache))
+ return NULL;
+
+ entry = (SilcChannelEntry)id_cache->context;
+
+ SILC_LOG_DEBUG(("Found"));
+
+ return entry;
+}
+
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ union {
+ SilcChannelID *channel_id;
+ char *channel_name;
+ } u;
+ SilcGetChannelCallback completion;
+ void *context;
+} *GetChannelInternal;
+
+SILC_CLIENT_CMD_FUNC(get_channel_resolve_callback)
+{
+ GetChannelInternal i = (GetChannelInternal)context;
+ SilcChannelEntry entry;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Get the channel */
+ entry = silc_client_get_channel(i->client, i->conn, i->u.channel_name);
+ if (entry) {
+ i->completion(i->client, i->conn, &entry, 1, i->context);
+ } else {
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
+
+ silc_free(i->u.channel_name);
+ silc_free(i);
+}
+
+/* Resolves channel entry from the server by the channel name. */
+
+void silc_client_get_channel_resolve(SilcClient client,
+ SilcClientConnection conn,
+ char *channel_name,
+ SilcGetChannelCallback completion,
+ void *context)
+{
+ GetChannelInternal i = silc_calloc(1, sizeof(*i));
+
+ assert(client && conn && channel_name);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ i->client = client;
+ i->conn = conn;
+ i->u.channel_name = strdup(channel_name);
+ i->completion = completion;
+ i->context = context;
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ 1, 3, channel_name, strlen(channel_name));
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+ silc_client_command_get_channel_resolve_callback,
+ (void *)i);
+}
+
+SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
+{
+ GetChannelInternal i = (GetChannelInternal)context;
+ SilcChannelEntry entry;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Get the channel */
+ entry = silc_client_get_channel_by_id(i->client, i->conn, i->u.channel_id);
+ if (entry) {
+ i->completion(i->client, i->conn, &entry, 1, i->context);
+ } else {
+ i->completion(i->client, i->conn, NULL, 0, i->context);
+ }
+
+ silc_free(i->u.channel_id);
+ silc_free(i);
+}
+
+/* Resolves channel information from the server by the channel ID. */
+
+void silc_client_get_channel_by_id_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelID *channel_id,
+ SilcGetChannelCallback completion,
+ void *context)
+{
+ SilcBuffer idp;
+ GetChannelInternal i = silc_calloc(1, sizeof(*i));
+
+ assert(client && conn && channel_id);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ i->client = client;
+ i->conn = conn;
+ i->u.channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
+ i->completion = completion;
+ i->context = context;
+
+ /* Register our own command reply for this command */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
+ ++conn->cmd_ident);
+
+ /* Send the command */
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ 1, 5, idp->data, idp->len);
+ silc_buffer_free(idp);
+
+ /* Add pending callback */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+ silc_client_command_get_channel_by_id_callback,
+ (void *)i);
+}
+
+/* Finds entry for server by the server name. */
+
+SilcServerEntry silc_client_get_server(SilcClient client,
+ SilcClientConnection conn,
+ char *server_name)
+{
+ SilcIDCacheEntry id_cache;
+ SilcServerEntry entry;
+
+ assert(client && conn);
+ if (!server_name)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Normalize server name for search */
+ server_name = silc_identifier_check(server_name, strlen(server_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!server_name)
+ return NULL;
+
+ if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
+ server_name, &id_cache)) {
+ silc_free(server_name);
+ return NULL;
+ }
+
+ entry = (SilcServerEntry)id_cache->context;
+
+ silc_free(server_name);
+
+ return entry;
+}
+
+/* Finds entry for server by the server ID. */
+
+SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcServerID *server_id)
+{
+ SilcIDCacheEntry id_cache;
+ SilcServerEntry entry;
+
+ assert(client && conn);
+ if (!server_id)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_idcache_find_by_id_one(conn->internal->server_cache,
+ (void *)server_id, &id_cache))
+ return NULL;
+
+ entry = (SilcServerEntry)id_cache->context;
+
+ return entry;
+}
+
+/* Add new server entry */
+
+SilcServerEntry silc_client_add_server(SilcClient client,
+ SilcClientConnection conn,
+ const char *server_name,
+ const char *server_info,
+ SilcServerID *server_id)
+{
+ SilcServerEntry server_entry;
+ char *server_namec = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ server_entry = silc_calloc(1, sizeof(*server_entry));
+ if (!server_entry || !server_id)
+ return NULL;
+
+ server_entry->server_id = server_id;
+ if (server_name)
+ server_entry->server_name = strdup(server_name);
+ if (server_info)
+ server_entry->server_info = strdup(server_info);
+
+ /* Normalize server name */
+ if (server_name) {
+ server_namec = silc_identifier_check(server_name, strlen(server_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!server_namec) {
+ silc_free(server_entry->server_id);
+ silc_free(server_entry->server_name);
+ silc_free(server_entry->server_info);
+ silc_free(server_entry);
+ return NULL;
+ }
+ }
+
+ /* Add server to cache */
+ if (!silc_idcache_add(conn->internal->server_cache, server_namec,
+ server_entry->server_id, server_entry, 0, NULL)) {
+ silc_free(server_namec);
+ silc_free(server_entry->server_id);
+ silc_free(server_entry->server_name);
+ silc_free(server_entry->server_info);
+ silc_free(server_entry);
+ return NULL;
+ }
+
+ return server_entry;
+}
+
+/* Removes server from the cache by the server entry. */
+
+bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
+ SilcServerEntry server)
+{
+ bool ret = silc_idcache_del_by_context(conn->internal->server_cache, server);
+ silc_free(server->server_name);
+ silc_free(server->server_info);
+ silc_free(server->server_id);
+ silc_free(server);
+ return ret;
+}
+
+/* Updates the `server_entry' with the new information sent as argument. */
+
+void silc_client_update_server(SilcClient client,
+ SilcClientConnection conn,
+ SilcServerEntry server_entry,
+ const char *server_name,
+ const char *server_info)
+{
+ char *server_namec = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (server_name &&
+ (!server_entry->server_name ||
+ !silc_utf8_strcasecmp(server_entry->server_name, server_name))) {
+
+ silc_idcache_del_by_context(conn->internal->server_cache, server_entry);
+ silc_free(server_entry->server_name);
+ server_entry->server_name = strdup(server_name);
+
+ /* Normalize server name */
+ if (server_name) {
+ server_namec = silc_identifier_check(server_name, strlen(server_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!server_namec)
+ return;
+
+ silc_idcache_add(conn->internal->server_cache, server_namec,
+ server_entry->server_id,
+ server_entry, 0, NULL);
+ }
+ }
+
+ if (server_info &&
+ (!server_entry->server_info ||
+ !silc_utf8_strcasecmp(server_entry->server_info, server_info))) {
+ silc_free(server_entry->server_info);
+ server_entry->server_info = strdup(server_info);
+ }
+}
+
+/* Formats the nickname of the client specified by the `client_entry'.
+ If the format is specified by the application this will format the
+ nickname and replace the old nickname in the client entry. If the
+ format string is not specified then this function has no effect. */
+
+void silc_client_nickname_format(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ char *cp;
+ char *newnick = NULL;
+ int i, off = 0, len;
+ bool freebase;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count = 0;
+ SilcClientEntry unformatted = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!client->internal->params->nickname_format[0])
+ return;
+
+ if (!client_entry->nickname)
+ return;
+
+ /* Get all clients with same nickname. Do not perform the formatting
+ if there aren't any clients with same nickname unless the application
+ is forcing us to do so. */
+ clients = silc_client_get_clients_local(client, conn,
+ client_entry->nickname, NULL,
+ &clients_count);
+ if (!clients && !client->internal->params->nickname_force_format)
+ return;
+
+ len = 0;
+ freebase = TRUE;
+ for (i = 0; i < clients_count; i++) {
+ if (clients[i]->valid && clients[i] != client_entry)
+ len++;
+ if (clients[i]->valid && clients[i] != client_entry &&
+ silc_utf8_strcasecmp(clients[i]->nickname, client_entry->nickname))
+ freebase = FALSE;
+ }
+ if (!len || freebase)
+ return;
+
+ if (clients_count == 1)
+ unformatted = clients[0];
+ else
+ for (i = 0; i < clients_count; i++)
+ if (silc_utf8_strncasecmp(clients[i]->nickname, client_entry->nickname,
+ strlen(clients[i]->nickname)))
+ unformatted = clients[i];
+
+ /* If we are changing nickname of our local entry we'll enforce
+ that we will always get the unformatted nickname. Give our
+ format number to the one that is not formatted now. */
+ if (unformatted && client_entry == conn->local_entry)
+ client_entry = unformatted;
+
+ cp = client->internal->params->nickname_format;
+ while (*cp) {
+ if (*cp == '%') {
+ cp++;
+ continue;
+ }
+
+ switch(*cp) {
+ case 'n':
+ /* Nickname */
+ if (!client_entry->nickname)
+ break;
+ len = strlen(client_entry->nickname);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->nickname, len);
+ off += len;
+ break;
+ case 'h':
+ /* Stripped hostname */
+ if (!client_entry->hostname)
+ break;
+ len = strcspn(client_entry->hostname, ".");
+ i = strcspn(client_entry->hostname, "-");
+ if (i < len)
+ len = i;
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->hostname, len);
+ off += len;
+ break;
+ case 'H':
+ /* Full hostname */
+ if (!client_entry->hostname)
+ break;
+ len = strlen(client_entry->hostname);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->hostname, len);
+ off += len;
+ break;
+ case 's':
+ /* Stripped server name */
+ if (!client_entry->server)
+ break;
+ len = strcspn(client_entry->server, ".");
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->server, len);
+ off += len;
+ break;
+ case 'S':
+ /* Full server name */
+ if (!client_entry->server)
+ break;
+ len = strlen(client_entry->server);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], client_entry->server, len);
+ off += len;
+ break;
+ case 'a':
+ /* Ascending number */
+ {
+ char tmp[6];
+ int num, max = 1;
+
+ if (clients_count == 1)
+ break;
+
+ for (i = 0; i < clients_count; i++) {
+ if (!silc_utf8_strncasecmp(clients[i]->nickname, newnick, off))
+ continue;
+ if (strlen(clients[i]->nickname) <= off)
+ continue;
+ num = atoi(&clients[i]->nickname[off]);
+ if (num > max)
+ max = num;
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "%d", ++max);
+ len = strlen(tmp);
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + len));
+ memcpy(&newnick[off], tmp, len);
+ off += len;
+ }
+ break;
+ default:
+ /* Some other character in the string */
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
+ memcpy(&newnick[off], cp, 1);
+ off++;
+ break;
+ }
+
+ cp++;
+ }
+
+ newnick = silc_realloc(newnick, sizeof(*newnick) * (off + 1));
+ newnick[off] = 0;
+
+ silc_free(client_entry->nickname);
+ client_entry->nickname = newnick;
+ silc_free(clients);
+}
/*
- client_entry.h
+ idlist.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2006 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 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
*/
-#ifndef CLIENT_ENTRY_H
-#define CLIENT_ENTRY_H
+#ifndef IDLIST_H
+#define IDLIST_H
-SilcClientEntry silc_client_add_client(SilcClient client,
- SilcClientConnection conn,
- char *nickname, char *username,
- char *userinfo, SilcClientID *id,
- SilcUInt32 mode);
+/* Prototypes. These are used only by the library. Application should not
+ call these directly. */
+
+SilcClientEntry
+silc_client_add_client(SilcClient client, SilcClientConnection conn,
+ char *nickname, char *username,
+ char *userinfo, SilcClientID *id, SilcUInt32 mode);
void silc_client_update_client(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
const char *username,
const char *userinfo,
SilcUInt32 mode);
-SilcBool silc_client_change_nickname(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *new_nick,
- SilcClientID *new_id,
- const unsigned char *idp,
- SilcUInt32 idp_len);
-void silc_client_del_client_entry(SilcClient client,
+void silc_client_del_client_entry(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry);
-SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry);
-SilcClientEntry silc_client_get_client(SilcClient client,
+SilcClientEntry silc_idlist_get_client(SilcClient client,
SilcClientConnection conn,
- SilcClientID *client_id);
+ const char *nickname,
+ const char *format,
+ bool query);
SilcChannelEntry silc_client_add_channel(SilcClient client,
SilcClientConnection conn,
const char *channel_name,
- SilcUInt32 mode,
+ SilcUInt32 mode,
SilcChannelID *channel_id);
-SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
- SilcChannelEntry channel);
-bool silc_client_replace_channel_id(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcChannelID *new_id);
SilcServerEntry silc_client_add_server(SilcClient client,
SilcClientConnection conn,
const char *server_name,
SilcServerEntry server_entry,
const char *server_name,
const char *server_info);
-SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn,
- SilcServerEntry server);
-SilcBool silc_client_nickname_parse(SilcClient client,
+bool silc_client_replace_channel_id(SilcClient client,
SilcClientConnection conn,
- char *nickname,
- char **ret_nick);
-SilcUInt16 silc_client_get_clients_by_list(SilcClient client,
- SilcClientConnection conn,
- SilcUInt32 list_count,
- SilcBuffer client_id_list,
- SilcGetClientCallback completion,
- void *context);
+ SilcChannelEntry channel,
+ SilcChannelID *new_id);
+void silc_client_nickname_format(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry);
-#endif /* CLIENT_ENTRY_H */
+#endif
--- /dev/null
+/*
+
+ protocol.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2004 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 "silcincludes.h"
+#include "silcclient.h"
+#include "client_internal.h"
+
+SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
+SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
+SILC_TASK_CALLBACK(silc_client_protocol_rekey);
+
+/*
+ * Key Exhange protocol functions
+ */
+
+/* Function that is called when SKE protocol sends packets to network. */
+
+void silc_client_protocol_ke_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ /* Send the packet immediately */
+ silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+}
+
+/* Public key verification callback. Called by the application. */
+
+typedef struct {
+ SilcSKE ske;
+ SilcSKEVerifyCbCompletion completion;
+ void *completion_context;
+} *VerifyKeyContext;
+
+static void silc_client_verify_key_cb(bool success, void *context)
+{
+ VerifyKeyContext verify = (VerifyKeyContext)context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Call the completion callback back to the SKE */
+ verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
+ SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+ verify->completion_context);
+
+ silc_free(verify);
+}
+
+/* Callback that is called when we have received KE payload from
+ responder. We try to verify the public key now. */
+
+void silc_client_protocol_ke_verify_key(SilcSKE ske,
+ unsigned char *pk_data,
+ SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
+ void *context,
+ SilcSKEVerifyCbCompletion completion,
+ void *completion_context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ VerifyKeyContext verify;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ verify = silc_calloc(1, sizeof(*verify));
+ verify->ske = ske;
+ verify->completion = completion;
+ verify->completion_context = completion_context;
+
+ /* Verify public key from user. */
+ client->internal->ops->verify_public_key(client, ctx->sock->user_data,
+ ctx->sock->type,
+ pk_data, pk_len, pk_type,
+ silc_client_verify_key_cb, verify);
+}
+
+/* Sets the negotiated key material into use for particular connection. */
+
+void silc_client_protocol_ke_set_keys(SilcSKE ske,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ SilcCipher cipher,
+ SilcPKCS pkcs,
+ SilcHash hash,
+ SilcHmac hmac,
+ SilcSKEDiffieHellmanGroup group,
+ bool is_responder)
+{
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ const char *cname = silc_cipher_get_name(cipher);
+
+ SILC_LOG_DEBUG(("Setting new keys into use"));
+
+ /* Allocate cipher to be used in the communication */
+ silc_cipher_alloc((char *)cname, &conn->internal->send_key);
+ silc_cipher_alloc((char *)cname, &conn->internal->receive_key);
+ silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
+ &conn->internal->hmac_send);
+ silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
+ &conn->internal->hmac_receive);
+
+ if (is_responder == TRUE) {
+ silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->send_key, keymat->receive_iv);
+ silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->receive_key, keymat->send_iv);
+ silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key,
+ keymat->hmac_key_len);
+ silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key,
+ keymat->hmac_key_len);
+ } else {
+ silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->send_key, keymat->send_iv);
+ silc_cipher_set_key(conn->internal->receive_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->receive_key, keymat->receive_iv);
+ silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key,
+ keymat->hmac_key_len);
+ silc_hmac_set_key(conn->internal->hmac_receive, keymat->receive_hmac_key,
+ keymat->hmac_key_len);
+ }
+
+ /* Rekey stuff */
+ conn->internal->rekey = silc_calloc(1, sizeof(*conn->internal->rekey));
+ conn->internal->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
+ keymat->enc_key_len / 8);
+ conn->internal->rekey->enc_key_len = keymat->enc_key_len / 8;
+
+ if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
+ conn->internal->rekey->pfs = TRUE;
+ conn->internal->rekey->ske_group = silc_ske_group_get_number(group);
+
+ /* Save the HASH function */
+ silc_hash_alloc(silc_hash_get_name(hash), &conn->internal->hash);
+}
+
+/* Checks the version string of the server. */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+ SilcUInt32 len, void *context)
+{
+ SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
+ SilcClient client = (SilcClient)ske->user_data;
+ SilcUInt32 l_protocol_version = 0, r_protocol_version = 0;
+
+ if (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL,
+ NULL, NULL)) {
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "We don't support server version `%s'",
+ version);
+ return SILC_SKE_STATUS_BAD_VERSION;
+ }
+
+ if (!silc_parse_version_string(client->internal->silc_client_version,
+ &l_protocol_version, NULL, NULL,
+ NULL, NULL)) {
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "We don't support server version `%s'",
+ version);
+ return SILC_SKE_STATUS_BAD_VERSION;
+ }
+
+ /* If remote is too new, don't connect */
+ if (l_protocol_version < r_protocol_version) {
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "We don't support server version `%s'",
+ version);
+ return SILC_SKE_STATUS_BAD_VERSION;
+ }
+
+ ske->sock->version = r_protocol_version;
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Callback that is called by the SKE to indicate that it is safe to
+ continue the execution of the protocol. Is given as argument to the
+ silc_ske_initiator_finish or silc_ske_responder_phase_2 functions.
+ This is called due to the fact that the public key verification
+ process is asynchronous and we must not continue the protocl until
+ the public key has been verified and this callback is called. */
+
+static void silc_client_protocol_ke_continue(SilcSKE ske,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientConnection conn = ctx->sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (ske->status != SILC_SKE_STATUS_OK) {
+ /* Call failure client operation */
+ client->internal->ops->failure(client, conn, protocol,
+ (void *)ske->status);
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Send Ok to the other end. We will end the protocol as server
+ sends Ok to us when we will take the new keys into use. Do this
+ if we are initiator. This is happens when this callback was sent
+ to silc_ske_initiator_finish function. */
+ if (ctx->responder == FALSE) {
+ silc_ske_end(ctx->ske);
+
+ /* End the protocol on the next round */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+
+ /* Advance protocol state and call the next state if we are responder.
+ This happens when this callback was sent to silc_ske_responder_phase_2
+ function. */
+ if (ctx->responder == TRUE) {
+ protocol->state++;
+ silc_protocol_execute(protocol, client->schedule, 0, 1);
+ }
+}
+
+/* Performs key exchange protocol. This is used for both initiator
+ and responder key exchange. This may be called recursively. */
+
+SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientConnection conn = ctx->sock->user_data;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start Protocol
+ */
+ SilcSKE ske;
+
+ /* Allocate Key Exchange object */
+ ctx->ske = ske = silc_ske_alloc(client->rng, client);
+
+ silc_ske_set_callbacks(ske, ctx->send_packet, NULL,
+ ctx->verify,
+ silc_client_protocol_ke_continue,
+ silc_ske_check_version,
+ context);
+
+ if (ctx->responder == TRUE) {
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Start the key exchange by processing the received security
+ properties packet from initiator. */
+ status =
+ silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+ client->internal->silc_client_version,
+ ctx->packet->buffer, TRUE);
+ } else {
+ SilcSKEStartPayload *start_payload;
+
+ /* Assemble security properties. */
+ silc_ske_assemble_security_properties(
+ ske, SILC_SKE_SP_FLAG_MUTUAL,
+ client->internal->silc_client_version,
+ &start_payload);
+
+ /* Start the key exchange by sending our security properties
+ to the remote end. */
+ status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
+ start_payload);
+ }
+
+ /* Return now if the procedure is pending */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Advance protocol state and call the next state if we are responder */
+ protocol->state++;
+ if (ctx->responder == TRUE)
+ silc_protocol_execute(protocol, client->schedule, 0, 1);
+ }
+ break;
+ case 2:
+ {
+ /*
+ * Phase 1
+ */
+ if (ctx->responder == TRUE) {
+ /* Sends the selected security properties to the initiator. */
+ status = silc_ske_responder_phase_1(ctx->ske);
+ } else {
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Call Phase-1 function. This processes the Key Exchange Start
+ paylaod reply we just got from the responder. The callback
+ function will receive the processed payload where we will
+ save it. */
+ status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer);
+ }
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Advance protocol state and call next state if we are initiator */
+ protocol->state++;
+ if (ctx->responder == FALSE)
+ silc_protocol_execute(protocol, client->schedule, 0, 1);
+ }
+ break;
+ case 3:
+ {
+ /*
+ * Phase 2
+ */
+ if (ctx->responder == TRUE) {
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Process the received Key Exchange 1 Payload packet from
+ the initiator. This also creates our parts of the Diffie
+ Hellman algorithm. The silc_client_protocol_ke_continue will
+ be called after the public key has been verified. */
+ status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
+ } else {
+ /* Call the Phase-2 function. This creates Diffie Hellman
+ key exchange parameters and sends our public part inside
+ Key Exhange 1 Payload to the responder. */
+ status = silc_ske_initiator_phase_2(ctx->ske,
+ client->public_key,
+ client->private_key,
+ SILC_SKE_PK_TYPE_SILC);
+ protocol->state++;
+ }
+
+ /* Return now if the procedure is pending */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+ }
+ break;
+ case 4:
+ {
+ /*
+ * Finish protocol
+ */
+ if (ctx->responder == TRUE) {
+ /* This creates the key exchange material and sends our
+ public parts to the initiator inside Key Exchange 2 Payload. */
+ status =
+ silc_ske_responder_finish(ctx->ske,
+ client->public_key, client->private_key,
+ SILC_SKE_PK_TYPE_SILC);
+
+ /* End the protocol on the next round */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ } else {
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+ status));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+
+ /* Finish the protocol. This verifies the Key Exchange 2 payload
+ sent by responder. The silc_client_protocol_ke_continue will
+ be called after the public key has been verified. */
+ status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
+ }
+
+ /* Return now if the procedure is pending */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+
+ if (status != SILC_SKE_STATUS_OK) {
+ if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Received unsupported server %s public key",
+ ctx->sock->hostname);
+ } else {
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Error during key exchange protocol with server %s",
+ ctx->sock->hostname);
+ }
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ return;
+ }
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ {
+ /*
+ * End protocol
+ */
+ SilcSKEKeyMaterial *keymat;
+ int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher);
+ int hash_len = silc_hash_len(ctx->ske->prop->hash);
+
+ /* Process the key material */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ status = silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
+ keymat);
+ if (status != SILC_SKE_STATUS_OK) {
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ silc_ske_free_key_material(keymat);
+ return;
+ }
+ ctx->keymat = keymat;
+
+ /* Send Ok to the other end if we are responder. If we are initiator
+ we have sent this already. */
+ if (ctx->responder == TRUE)
+ silc_ske_end(ctx->ske);
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_schedule_task_del(client->schedule, ctx->timeout_task);
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_ERROR:
+ /*
+ * Error during protocol
+ */
+
+ /* Send abort notification */
+ silc_ske_abort(ctx->ske, ctx->ske->status);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * Received failure from remote.
+ */
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_schedule_task_del(client->schedule, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+/*
+ * Connection Authentication protocol functions
+ */
+
+static int
+silc_client_get_public_key_auth(SilcClient client,
+ SilcClientConnection conn,
+ unsigned char *auth_data,
+ SilcUInt32 *auth_data_len,
+ SilcSKE ske)
+{
+ int len;
+ SilcPKCS pkcs;
+ SilcBuffer auth;
+
+ /* Use our default key */
+ pkcs = client->pkcs;
+
+ /* Make the authentication data. Protocol says it is HASH plus
+ KE Start Payload. */
+ len = ske->hash_len + ske->start_payload_copy->len;
+ auth = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(auth, len);
+ silc_buffer_format(auth,
+ SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+ SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+ ske->start_payload_copy->len),
+ SILC_STR_END);
+
+ if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
+ auth->len, auth_data, auth_data_len)) {
+ silc_buffer_free(auth);
+ return TRUE;
+ }
+
+ silc_buffer_free(auth);
+ return FALSE;
+}
+
+/* Continues the connection authentication protocol. This funtion may
+ be called directly or used as SilcAskPassphrase callback. */
+
+static void
+silc_client_conn_auth_continue(unsigned char *auth_data,
+ SilcUInt32 auth_data_len, void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientConnAuthInternalContext *ctx =
+ (SilcClientConnAuthInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcBuffer packet;
+ int payload_len = 0;
+ unsigned char *autf8 = NULL;
+
+ SILC_LOG_DEBUG(("Sending authentication to server"));
+
+ /* Passphrase must be UTF-8 encoded, if it isn't encode it */
+ if (ctx->auth_meth == SILC_AUTH_PASSWORD &&
+ !silc_utf8_valid(auth_data, auth_data_len)) {
+ payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
+ SILC_STRING_ASCII);
+ autf8 = silc_calloc(payload_len, sizeof(*autf8));
+ auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
+ SILC_STRING_ASCII, autf8, payload_len);
+ auth_data = autf8;
+ }
+
+ payload_len = 4 + auth_data_len;
+ packet = silc_buffer_alloc(payload_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(payload_len),
+ SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+ SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
+ SILC_STR_END);
+
+ /* Send the packet to server */
+ silc_client_packet_send(client, ctx->sock,
+ SILC_PACKET_CONNECTION_AUTH,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ silc_free(autf8);
+
+ /* Next state is end of protocol */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+}
+
+SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientConnAuthInternalContext *ctx =
+ (SilcClientConnAuthInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientConnection conn = ctx->sock->user_data;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start protocol. We send authentication data to the server
+ * to be authenticated.
+ */
+ unsigned char *auth_data = NULL;
+ SilcUInt32 auth_data_len = 0;
+ unsigned char sign[2048 + 1];
+
+ switch(ctx->auth_meth) {
+ case SILC_AUTH_NONE:
+ /* No authentication required */
+ break;
+
+ case SILC_AUTH_PASSWORD:
+ /* Password authentication */
+ if (ctx->auth_data && ctx->auth_data_len) {
+ auth_data = ctx->auth_data;
+ auth_data_len = ctx->auth_data_len;
+ break;
+ }
+
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Password authentication required by server %s",
+ ctx->sock->hostname);
+ client->internal->ops->ask_passphrase(client, conn,
+ silc_client_conn_auth_continue,
+ protocol);
+ return;
+ break;
+
+ case SILC_AUTH_PUBLIC_KEY:
+ if (!ctx->auth_data) {
+ /* Public key authentication */
+ silc_client_get_public_key_auth(client, conn, sign, &auth_data_len,
+ ctx->ske);
+ auth_data = sign;
+ } else {
+ auth_data = ctx->auth_data;
+ auth_data_len = ctx->auth_data_len;
+ }
+
+ break;
+ }
+
+ silc_client_conn_auth_continue(auth_data,
+ auth_data_len, protocol);
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ {
+ /*
+ * End protocol. Nothing special to be done here.
+ */
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ }
+ break;
+
+ case SILC_PROTOCOL_STATE_ERROR:
+ {
+ /*
+ * Error. Send notify to remote.
+ */
+ unsigned char error[4];
+
+ SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
+
+ /* Error in protocol. Send FAILURE packet. Although I don't think
+ this could ever happen on client side. */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
+ NULL, 0, NULL, NULL, error, 4, TRUE);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ }
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * Received failure from remote.
+ */
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+}
+
+/*
+ * Re-key protocol routines
+ */
+
+/* Actually takes the new keys into use. */
+
+static void
+silc_client_protocol_rekey_validate(SilcClient client,
+ SilcClientRekeyInternalContext *ctx,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ bool send)
+{
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+
+ if (ctx->responder == TRUE) {
+ if (send) {
+ silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->send_key, keymat->receive_iv);
+ silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key,
+ keymat->hmac_key_len);
+ } else {
+ silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->receive_key, keymat->send_iv);
+ silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key,
+ keymat->hmac_key_len);
+ }
+ } else {
+ if (send) {
+ silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key,
+ keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->send_key, keymat->send_iv);
+ silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key,
+ keymat->hmac_key_len);
+ } else {
+ silc_cipher_set_key(conn->internal->receive_key,
+ keymat->receive_enc_key, keymat->enc_key_len);
+ silc_cipher_set_iv(conn->internal->receive_key, keymat->receive_iv);
+ silc_hmac_set_key(conn->internal->hmac_receive,
+ keymat->receive_hmac_key, keymat->hmac_key_len);
+ }
+ }
+
+ /* Save the current sending encryption key */
+ if (!send) {
+ memset(conn->internal->rekey->send_enc_key, 0,
+ conn->internal->rekey->enc_key_len);
+ silc_free(conn->internal->rekey->send_enc_key);
+ conn->internal->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
+ keymat->enc_key_len / 8);
+ conn->internal->rekey->enc_key_len = keymat->enc_key_len / 8;
+ }
+}
+
+/* This function actually re-generates (when not using PFS) the keys and
+ takes them into use. */
+
+static void
+silc_client_protocol_rekey_generate(SilcClient client,
+ SilcClientRekeyInternalContext *ctx,
+ bool send)
+{
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcSKEKeyMaterial *keymat;
+ SilcUInt32 key_len = silc_cipher_get_key_len(conn->internal->send_key);
+ SilcUInt32 hash_len = silc_hash_len(conn->internal->hash);
+
+ SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)",
+ send ? "sending" : "receiving"));
+
+ /* Generate the new key */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ silc_ske_process_key_material_data(conn->internal->rekey->send_enc_key,
+ conn->internal->rekey->enc_key_len,
+ 16, key_len, hash_len,
+ conn->internal->hash, keymat);
+
+ /* Set the keys into use */
+ silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat, send);
+
+ silc_ske_free_key_material(keymat);
+}
+
+/* This function actually re-generates (with PFS) the keys and
+ takes them into use. */
+
+static void
+silc_client_protocol_rekey_generate_pfs(SilcClient client,
+ SilcClientRekeyInternalContext *ctx,
+ bool send)
+{
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcSKEKeyMaterial *keymat;
+ SilcUInt32 key_len = silc_cipher_get_key_len(conn->internal->send_key);
+ SilcUInt32 hash_len = silc_hash_len(conn->internal->hash);
+ unsigned char *tmpbuf;
+ SilcUInt32 klen;
+
+ SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)",
+ send ? "sending" : "receiving"));
+
+ /* Encode KEY to binary data */
+ tmpbuf = silc_mp_mp2bin(ctx->ske->KEY, 0, &klen);
+
+ /* Generate the new key */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len,
+ conn->internal->hash, keymat);
+
+ /* Set the keys into use */
+ silc_client_protocol_rekey_validate(client, ctx, ctx->sock, keymat, send);
+
+ memset(tmpbuf, 0, klen);
+ silc_free(tmpbuf);
+ silc_ske_free_key_material(keymat);
+}
+
+/* Packet sending callback. This function is provided as packet sending
+ routine to the Key Exchange functions. */
+
+static void
+silc_client_protocol_rekey_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ /* Send the packet immediately */
+ silc_client_packet_send(client, ctx->sock, type, NULL, 0, NULL, NULL,
+ packet->data, packet->len, FALSE);
+}
+
+/* Performs re-key as defined in the SILC protocol specification. */
+
+SILC_TASK_CALLBACK(silc_client_protocol_rekey)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+ SilcSKEStatus status;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+ protocol->state = SILC_PROTOCOL_STATE_START;
+
+ SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+ switch(protocol->state) {
+ case SILC_PROTOCOL_STATE_START:
+ {
+ /*
+ * Start protocol.
+ */
+
+ if (ctx->responder == TRUE) {
+ /*
+ * We are receiving party
+ */
+
+ if (ctx->pfs == TRUE) {
+ /*
+ * Use Perfect Forward Secrecy, ie. negotiate the key material
+ * using the SKE protocol.
+ */
+
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error during Re-key"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+
+ if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ }
+
+ ctx->ske = silc_ske_alloc(client->rng, client);
+ ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
+ silc_ske_group_get_by_number(conn->internal->rekey->ske_group,
+ &ctx->ske->prop->group);
+
+ silc_ske_set_callbacks(ctx->ske,
+ silc_client_protocol_rekey_send_packet,
+ NULL, NULL, NULL, silc_ske_check_version,
+ context);
+
+ status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+
+ /* Advance the protocol state */
+ protocol->state++;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use */
+ silc_client_packet_queue_purge(client, ctx->sock);
+ silc_client_packet_send(client, ctx->sock,
+ SILC_PACKET_REKEY_DONE,
+ NULL, 0, NULL, NULL, NULL, 0, FALSE);
+
+ /* After we send REKEY_DONE we must set the sending encryption
+ key to the new key since all packets after this packet must
+ encrypted with the new key. */
+ silc_client_protocol_rekey_generate(client, ctx, TRUE);
+ silc_client_packet_queue_purge(client, ctx->sock);
+
+ /* The protocol ends in next stage. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+
+ } else {
+ /*
+ * We are the initiator of this protocol
+ */
+
+ /* Start the re-key by sending the REKEY packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY,
+ NULL, 0, NULL, NULL, NULL, 0, FALSE);
+
+ if (ctx->pfs == TRUE) {
+ /*
+ * Use Perfect Forward Secrecy, ie. negotiate the key material
+ * using the SKE protocol.
+ */
+ ctx->ske = silc_ske_alloc(client->rng, client);
+ ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
+ silc_ske_group_get_by_number(conn->internal->rekey->ske_group,
+ &ctx->ske->prop->group);
+
+ silc_ske_set_callbacks(ctx->ske,
+ silc_client_protocol_rekey_send_packet,
+ NULL, NULL, NULL, silc_ske_check_version,
+ context);
+
+ status = silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0);
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+
+ /* Advance the protocol state */
+ protocol->state++;
+ } else {
+ /*
+ * Do normal and simple re-key.
+ */
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use
+ now. */
+ silc_client_packet_queue_purge(client, ctx->sock);
+ silc_client_packet_send(client, ctx->sock,
+ SILC_PACKET_REKEY_DONE,
+ NULL, 0, NULL, NULL, NULL, 0, FALSE);
+
+ /* After we send REKEY_DONE we must set the sending encryption
+ key to the new key since all packets after this packet must
+ encrypted with the new key. */
+ silc_client_protocol_rekey_generate(client, ctx, TRUE);
+ silc_client_packet_queue_purge(client, ctx->sock);
+
+ /* The protocol ends in next stage. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ }
+ }
+ }
+ break;
+
+ case 2:
+ /*
+ * Second state, used only when oding re-key with PFS.
+ */
+ if (ctx->responder == TRUE) {
+ if (ctx->pfs == TRUE) {
+ /*
+ * Send our KE packe to the initiator now that we've processed
+ * the initiator's KE packet.
+ */
+ status = silc_ske_responder_finish(ctx->ske, NULL, NULL,
+ SILC_SKE_PK_TYPE_SILC);
+
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+ }
+
+ } else {
+ if (ctx->pfs == TRUE) {
+ /*
+ * The packet type must be KE packet
+ */
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error during Re-key"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+
+ if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ }
+
+ status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
+ if (status != SILC_SKE_STATUS_OK) {
+ SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
+ status));
+
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+ }
+ }
+
+ /* Send the REKEY_DONE to indicate we will take new keys into use
+ now. */
+ silc_client_packet_queue_purge(client, ctx->sock);
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE,
+ NULL, 0, NULL, NULL, NULL, 0, FALSE);
+
+ /* After we send REKEY_DONE we must set the sending encryption
+ key to the new key since all packets after this packet must
+ encrypted with the new key. */
+ silc_client_protocol_rekey_generate_pfs(client, ctx, TRUE);
+ silc_client_packet_queue_purge(client, ctx->sock);
+
+ /* The protocol ends in next stage. */
+ protocol->state = SILC_PROTOCOL_STATE_END;
+ break;
+
+ case SILC_PROTOCOL_STATE_END:
+ /*
+ * End protocol
+ */
+
+ if (!ctx->packet) {
+ SILC_LOG_WARNING(("Error during Re-key"));
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 300000);
+ return;
+ }
+
+ if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
+ /* Error in protocol */
+ protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute(protocol, client->schedule, 0, 0);
+ }
+
+ /* We received the REKEY_DONE packet and all packets after this is
+ encrypted with the new key so set the decryption key to the new key */
+ if (ctx->pfs == TRUE)
+ silc_client_protocol_rekey_generate_pfs(client, ctx, FALSE);
+ else
+ silc_client_protocol_rekey_generate(client, ctx, FALSE);
+ silc_client_packet_queue_purge(client, ctx->sock);
+
+ /* Protocol has ended, call the final callback */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_ERROR:
+ /*
+ * Error occured
+ */
+
+ if (ctx->pfs == TRUE) {
+ /* Send abort notification */
+ silc_ske_abort(ctx->ske, ctx->ske->status);
+ }
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * We have received failure from remote
+ */
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ silc_protocol_execute_final(protocol, client->schedule);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_UNKNOWN:
+ break;
+ }
+
+}
+
+/* Registers protocols used in client */
+
+void silc_client_protocols_register(void)
+{
+ silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+ silc_client_protocol_connection_auth);
+ silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ silc_client_protocol_key_exchange);
+ silc_protocol_register(SILC_PROTOCOL_CLIENT_REKEY,
+ silc_client_protocol_rekey);
+}
+
+/* Unregisters protocols */
+
+void silc_client_protocols_unregister(void)
+{
+ silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+ silc_client_protocol_connection_auth);
+ silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ silc_client_protocol_key_exchange);
+ silc_protocol_unregister(SILC_PROTOCOL_CLIENT_REKEY,
+ silc_client_protocol_rekey);
+}
--- /dev/null
+/*
+
+ protocol.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2004 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 PROTOCOL_H
+#define PROTOCOL_H
+
+/* SILC client protocol types */
+#define SILC_PROTOCOL_CLIENT_NONE 0
+#define SILC_PROTOCOL_CLIENT_CONNECTION_AUTH 1
+#define SILC_PROTOCOL_CLIENT_KEY_EXCHANGE 2
+#define SILC_PROTOCOL_CLIENT_REKEY 3
+/* #define SILC_PROTOCOL_CLIENT_MAX 255 */
+
+/* Internal context for key exchange protocol */
+typedef struct {
+ void *client;
+ SilcSocketConnection sock;
+ SilcRng rng;
+ int responder;
+
+ void *dest_id; /* Destination ID from packet */
+ SilcIdType dest_id_type; /* Destination ID type */
+
+ SilcTask timeout_task;
+ SilcPacketContext *packet;
+
+ SilcSKESendPacketCb send_packet; /* SKE's packet sending callback */
+ SilcSKEVerifyCb verify; /* SKE's key verify callback */
+ SilcSKE ske; /* The SKE object */
+ SilcSKEKeyMaterial *keymat; /* The negotiated key material */
+ void *context; /* Internal context */
+} SilcClientKEInternalContext;
+
+/* Internal context for connection authentication protocol */
+typedef struct {
+ void *client;
+ SilcSocketConnection sock;
+ SilcClientConnectionStatus status;
+
+ /* SKE object from Key Exchange protocol. */
+ SilcSKE ske;
+
+ /* Auth method that must be used. This is resolved before this
+ connection authentication protocol is started. */
+ SilcProtocolAuthMeth auth_meth;
+
+ /* Destinations ID from KE protocol context */
+ void *dest_id;
+ SilcIdType dest_id_type;
+
+ /* Authentication data if we alreay know it. This is filled before
+ starting the protocol if we know the authentication data. Otherwise
+ these are and remain NULL. */
+ unsigned char *auth_data;
+ SilcUInt32 auth_data_len;
+
+ SilcTask timeout_task;
+} SilcClientConnAuthInternalContext;
+
+/* Internal context for the rekey protocol */
+typedef struct {
+ void *client;
+ void *context;
+ SilcSocketConnection sock;
+ bool responder; /* TRUE if we are receiving party */
+ bool pfs; /* TRUE if PFS is to be used */
+ SilcSKE ske; /* Defined if PFS is used */
+ SilcPacketContext *packet;
+} SilcClientRekeyInternalContext;
+
+/* Prototypes */
+void silc_client_protocols_register(void);
+void silc_client_protocols_unregister(void);
+void silc_client_protocol_ke_send_packet(SilcSKE ske,
+ SilcBuffer packet,
+ SilcPacketType type,
+ void *context);
+void silc_client_protocol_ke_verify_key(SilcSKE ske,
+ unsigned char *pk_data,
+ SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
+ void *context,
+ SilcSKEVerifyCbCompletion completion,
+ void *completion_context);
+void silc_client_protocol_ke_set_keys(SilcSKE ske,
+ SilcSocketConnection sock,
+ SilcSKEKeyMaterial *keymat,
+ SilcCipher cipher,
+ SilcPKCS pkcs,
+ SilcHash hash,
+ SilcHmac hmac,
+ SilcSKEDiffieHellmanGroup group,
+ bool is_responder);
+
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2007 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
* DESCRIPTION
*
* This interface defines the SILC Client Library API for the application.
- * The Client Library is a full featured SILC client without user interface.
- * A simple interface called SILC Client Operations (SilcClientOperations)
- * is provided for applications to implmeent the necessary functions to use
- * the client library. The silcclient.h header file includes client library
- * API, such as command handling and message sending. The silcclient_entry.h
- * header file includes entry handling, such as channel and user entry
- * handling.
- *
- * Practically all functions in the Client Library API accepts SilcClient
- * and SilcClientConnection as their first two argument. The first argument
- * is the actual SilcClient context and the second is the SilcClientConnection
- * context of the connection in question. Application may create and handle
- * multiple connections in one SilcClient. Connections can be created to
- * servers and other clients.
- *
- * The Client Library support multiple threads and is threads safe if used
- * correctly. Messages can be sent from multiple threads without any
- * locking. Messages however are always received only in one thread unless
- * message waiting (see silc_client_private_message_wait as an example) is
- * used. The threads can be turned on and off by giving a parameter to the
- * SilcClient. When turned on, each new connection to remote host is always
- * executed in an own thread. All tasks related to that connection are then
- * executed in that thread. This means that client operation callbacks for
- * that connections may be called from threads and application will need to
- * employ concurrency control if the callbacks need to access shared data
- * in the application. Messages are also received in that thread.
+ * The client operations are defined first. These are callback functions that
+ * the application MUST implement since the library may call the functions
+ * at any time. At the end of file is the API for the application that
+ * it can use from the library. This is the only file that the application
+ * may include from the SIlC Client Library.
+ *
+ * o SILC Client Operations
+ *
+ * These functions must be implemented by the application calling the SILC
+ * client library. The client library can call these functions at any time.
+ *
+ * To use this structure: define a static SilcClientOperations variable,
+ * fill it and pass its pointer to silc_client_alloc function.
+ *
+ * o SILC Client Library API
+ *
+ * This is the API that is published by the SILC Client Library for the
+ * applications. These functions are implemented in the SILC Client Library.
+ * Application may freely call these functions from the library.
*
***/
#endif
#include "client.h"
-#include "silcclient_entry.h"
/* General definitions */
-/****d* silcclient/SilcClientAPI/SilcClientConnectionStatus
+/****s* silcclient/SilcClientAPI/SilcClient
*
* NAME
*
- * typedef enum { ... } SilcClientConnectionStatus
+ * typedef struct SilcClientStruct { ... } *SilcClient
*
* DESCRIPTION
*
- * This type is returned to the `connect' client operation to indicate
- * the status of the created connection. It can indicate if it was
- * successful or whether an error occurred.
+ * This is the actual SILC Client structure which represents one
+ * SILC Client. It is allocated with the silc_client_alloc function
+ * and given as argument to all SILC Client Library functions. It
+ * is initialized with silc_client_init function, and freed with
+ * silc_client_free function.
*
* SOURCE
*/
-typedef enum {
- SILC_CLIENT_CONN_SUCCESS, /* Successfully connected */
- SILC_CLIENT_CONN_SUCCESS_RESUME, /* Successfully connected and
- resumed old detached session */
- SILC_CLIENT_CONN_DISCONNECTED, /* Remote host disconnected */
- SILC_CLIENT_CONN_ERROR, /* Error occurred during connecting */
- SILC_CLIENT_CONN_ERROR_KE, /* Key Exchange failed */
- SILC_CLIENT_CONN_ERROR_AUTH, /* Authentication failed */
- SILC_CLIENT_CONN_ERROR_RESUME, /* Resuming failed */
- SILC_CLIENT_CONN_ERROR_TIMEOUT, /* Timeout during connecting */
-} SilcClientConnectionStatus;
+struct SilcClientStruct {
+ /*
+ * The following fields are set by application. Strings MUST be UTF-8
+ * encoded strings.
+ */
+ char *nickname; /* Nickname, MAY be set by application */
+ char *username; /* Username, MUST be set by application */
+ char *hostname; /* hostname, MUST be set by application */
+ char *realname; /* Real name, MUST be set be application */
+
+ SilcPublicKey public_key; /* Public key of user, set by application */
+ SilcPrivateKey private_key; /* Private key of user, set by application */
+ SilcPKCS pkcs; /* PKCS allocated by application */
+
+ /*
+ * The following fields are set by the library
+ */
+
+ /* Scheduler, set by library. Application may use this pointer. */
+ SilcSchedule schedule;
+
+ /* Random Number Generator. Application should use this as its primary
+ random number generator. */
+ SilcRng rng;
+
+ /* Application specific user data pointer. Client library does not
+ touch this. This the context sent as argument to silc_client_alloc.
+ Application can use it freely. */
+ void *application;
+
+ /* Generic hash context for application usage */
+ SilcHash md5hash;
+ SilcHash sha1hash;
+
+ /* Internal data for client library. Application cannot access this
+ data at all. */
+ SilcClientInternal internal;
+};
/***/
-/****f* silcclient/SilcClientAPI/SilcClientRunning
+/****s* silcclient/SilcClientAPI/SilcClientConnection
*
- * SYNOPSIS
+ * NAME
*
- * typedef void (*SilcClientRunning)(SilcClient client, void *context);
+ * typedef struct SilcClientConnectionStruct { ... }
+ * *SilcClientConnection
*
* DESCRIPTION
*
- * The callback given as argument to silc_client_init function. Once
- * this is called the client library is running and application may
- * start using the Client library API.
+ * This structure represents a connection. When connection is created
+ * to server this is context is returned to the application in the
+ * "connected" client operation. It includes all the important
+ * data for the session, such as nickname, local and remote IDs, and
+ * other information. All strings in the structure are UTF-8 encoded.
*
- ***/
-typedef void (*SilcClientRunning)(SilcClient client, void *context);
+ * SOURCE
+ */
+struct SilcClientConnectionStruct {
+ /*
+ * Local data
+ */
+ char *nickname; /* Current nickname */
+ SilcClientEntry local_entry; /* Own Client Entry */
+ SilcClientID *local_id; /* Current Client ID */
+ unsigned char *local_id_data; /* Current Client ID decoded */
+ SilcUInt32 local_id_data_len;
+
+ /*
+ * Remote data
+ */
+ char *remote_host; /* Remote host name, UTF-8 encoded */
+ int remote_port; /* Remote port */
+ SilcServerID *remote_id; /* Remote Server ID */
+ unsigned char *remote_id_data; /* Remote Server ID decoded */
+ SilcUInt32 remote_id_data_len;
+
+ /*
+ * Common data
+ */
+
+ /* Current command identifier for a command that was sent last.
+ Application may get the value from this variable to find out the
+ command identifier for last command. */
+ SilcUInt16 cmd_ident;
+
+ /* User data context. Library does not touch this. Application may
+ freely set and use this pointer for its needs. */
+ void *context;
-/****f* silcclient/SilcClientAPI/SilcClientStopped
- *
- * SYNOPSIS
- *
- * typedef void (*SilcClientStopped)(SilcClient client, void *context);
- *
- * DESCRIPTION
- *
- * The callback given as argument to silc_client_stop. Once this is
- * called the client library has stopped and can be freed by calling
- * silc_client_free. Note that this won't be called if there are
- * active connections in the client. Connections must first be closed
- * by calling silc_client_close_connection or by sending QUIT command to
- * the server connection.
- *
- ***/
-typedef void (*SilcClientStopped)(SilcClient client, void *context);
+ /* Pointer back to the SilcClient. Application may use this. */
+ SilcClient client;
-/****f* silcclient/SilcClientAPI/SilcClientConnectCallback
- *
- * SYNOPSIS
- *
- * void (*SilcClientConnectCallback)(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientConnectionStatus status,
- * SilcStatus error,
- * const char *message,
- * void *context);
- *
- * DESCRIPTION
- *
- * Connect callbak given as argument to silc_client_connect_to_server,
- * silc_client_connect_to_client and silc_client_key_exchange functions.
- * It is called to indicate the status of the connection, indicated
- * by the `status'. It is called after the connection has been
- * established to the remote host and when connection is disconnected
- * by the remote host. The `context' is the context given as argument
- * to the connecting function. If the `status' is an error the `error'
- * may indicate more detailed error. If `error' is SILC_STATUS_OK no
- * detailed error message is available.
- *
- * When the `status' is SILC_CLIENT_CONN_DISCONNECTED the `error' will
- * indicate the reason for disconnection. If the `message' is non-NULL
- * it delivers error or disconnection message.
- *
- * The `conn' is the connection to the remote host. In case error
- * occurred the `conn' may be NULL, however, in some cases a valid `conn'
- * is returned even in error. If `conn' is non-NULL the receiver is
- * responsible of closing the connection with silc_client_close_connection
- * function, except when SILC_CLINET_CONN_DISCONNECTED or some error
- * was received. In these cases the library will close the connection.
- *
- ***/
-typedef void (*SilcClientConnectCallback)(SilcClient client,
- SilcClientConnection conn,
- SilcClientConnectionStatus status,
- SilcStatus error,
- const char *message,
- void *context);
+ /* Current channel. Application may use and set this pointer if needed. */
+ SilcChannelEntry current_channel;
-/****s* silcclient/SilcClientAPI/SilcClient
+ /* Socket connection object for this connection. Application may
+ use this if needed. The sock->user_data is back pointer to this
+ structure. */
+ SilcSocketConnection sock;
+
+ /* Internal data for client library. Application cannot access this
+ data at all. */
+ SilcClientConnectionInternal internal;
+};
+/***/
+
+/****s* silcclient/SilcClientAPI/SilcClientEntry
*
* NAME
*
- * typedef struct SilcClientStruct { ... } *SilcClient
+ * typedef struct SilcClientEntryStruct { ... } *SilcClientEntry
*
* DESCRIPTION
*
- * This is the actual SILC Client structure which represents one
- * SILC Client. It is allocated with the silc_client_alloc function
- * and given as argument to all SILC Client Library functions. It
- * is initialized with silc_client_init function, and freed with
- * silc_client_free function.
- *
- * This context represents the client. Each connection to remote server
- * is represented by SilcClientConnection context.
+ * This structure represents a client or a user in the SILC network.
+ * The local user has this structure also and it can be accessed from
+ * SilcClientConnection structure. All other users in the SILC network
+ * that are accessed using the Client Library routines will have their
+ * own SilcClientEntry structure. For example, when finding users by
+ * their nickname the Client Library returns this structure back to
+ * the application. All strings in the structure are UTF-8 encoded.
*
* SOURCE
*/
-struct SilcClientStruct {
- char *username; /* Username */
- char *hostname; /* hostname */
- char *realname; /* Real name */
- SilcSchedule schedule; /* Client scheduler */
- SilcRng rng; /* Random number generator */
- void *application; /* Application specific context, set with
- silc_client_alloc. */
-
- /* Internal data for client library. Application cannot access this. */
- SilcClientInternal internal;
+struct SilcClientEntryStruct {
+ /* General information */
+ char *nickname; /* nickname */
+ char *username; /* username */
+ char *hostname; /* hostname */
+ char *server; /* SILC server name */
+ char *realname; /* Realname (userinfo) */
+
+ /* Mode, ID and other information */
+ SilcUInt32 mode; /* User mode in SILC, see SilcUserMode */
+ SilcClientID *id; /* The Client ID */
+ SilcDList attrs; /* Requested Attributes (maybe NULL) */
+ unsigned char *fingerprint; /* Fingerprint of client's public key */
+ SilcUInt32 fingerprint_len; /* Length of the fingerprint */
+ SilcPublicKey public_key; /* User's public key, may be NULL */
+
+ /* Private message keys */
+ SilcCipher send_key; /* Private message key for sending */
+ SilcCipher receive_key; /* Private message key for receiving */
+ SilcHmac hmac_send; /* Private mesage key HMAC for sending */
+ SilcHmac hmac_receive; /* Private mesage key HMAC for receiving */
+ unsigned char *key; /* Set only if application provided the
+ key material. NULL if the library
+ generated the key. */
+ SilcUInt32 key_len; /* Key length */
+ SilcClientKeyAgreement ke; /* Current key agreement context or NULL */
+
+ /* SilcClientEntry status information */
+ SilcEntryStatus status; /* Status mask */
+ SilcHashTable channels; /* All channels client has joined */
+ SilcUInt16 resolve_cmd_ident; /* Command identifier when resolving */
+ unsigned int generated : 1; /* TRUE if library generated `key' */
+ unsigned int valid : 1; /* FALSE if this entry is not valid */
+ unsigned int prv_resp : 1; /* TRUE if private message key indicator
+ has been received (responder). */
+
+ /* Application specific data. Application may set here whatever it wants. */
+ void *context;
};
/***/
-/****s* silcclient/SilcClientAPI/SilcClientConnection
+/****s* silcclient/SilcClientAPI/SilcChannelEntry
*
* NAME
*
- * typedef struct SilcClientConnectionStruct { ... }
- * *SilcClientConnection
+ * typedef struct SilcChannelEntryStruct { ... } *SilcChannelEntry
*
* DESCRIPTION
*
- * This structure represents a connection. It is allocated and freed by
- * the library. It is returned to application in SilcClientConnectCallback.
- * It includes all the important data for the session such as local
- * client entry (which includes current nickname), local and remote IDs,
- * and other information. All strings in the structure are UTF-8 encoded.
+ * This structure represents a channel in the SILC network. All
+ * channels that the client are aware of or have joined in will be
+ * represented as SilcChannelEntry. The structure includes information
+ * about the channel. All strings in the structure are UTF-8 encoded.
*
* SOURCE
*/
-struct SilcClientConnectionStruct {
- SilcClientEntry local_entry; /* Our own Client Entry */
- SilcClientID *local_id; /* Our current Client ID */
-
- char *remote_host; /* Remote host name */
- int remote_port; /* Remote port */
- SilcID remote_id; /* Remote ID */
-
- SilcChannelEntry current_channel; /* Current joined channel */
- SilcPublicKey public_key; /* Public key used in this connection */
- SilcPrivateKey private_key; /* Private key */
- SilcPacketStream stream; /* Connection to remote host */
- SilcConnectionType type; /* Connection type */
- SilcClientConnectCallback callback; /* Connection callback */
- void *callback_context; /* Connection context */
- SilcClient client; /* Pointer back to SilcClient */
+struct SilcChannelEntryStruct {
+ /* General information */
+ char *channel_name; /* Channel name */
+ SilcChannelID *id; /* Channel ID */
+ SilcUInt32 mode; /* Channel mode, ChannelModes. */
+ char *topic; /* Current topic, may be NULL */
+ SilcPublicKey founder_key; /* Founder key, may be NULL */
+ SilcUInt32 user_limit; /* User limit on channel */
+
+ /* All clients that has joined this channel. The key to the table is the
+ SilcClientEntry and the context is SilcChannelUser context. */
+ SilcHashTable user_list;
+
+ /* Channel keys */
+ SilcCipher channel_key; /* The channel key */
+ unsigned char *key; /* Raw key data */
+ SilcUInt32 key_len; /* Raw key data length */
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE]; /* Current IV */
+ SilcHmac hmac; /* Current HMAC */
+
+ /* Channel private keys */
+ SilcDList private_keys; /* List of private keys or NULL */
+ SilcChannelPrivateKey curr_key; /* Current private key */
+
+ /* SilcChannelEntry status information */
+ SilcDList old_channel_keys;
+ SilcDList old_hmacs;
+ SilcUInt16 resolve_cmd_ident; /* Command identifier when
+ resolving this entry */
/* Application specific data. Application may set here whatever it wants. */
void *context;
-
- /* Internal data for client library. Application cannot access this. */
- SilcClientConnectionInternal internal;
};
/***/
};
/***/
-/****s* silcclient/SilcClientAPI/SilcClientStats
+/****s* silcclient/SilcClientAPI/SilcServerEntry
*
* NAME
*
- * typedef struct { ... } SilcClientStats;
+ * typedef struct SilcServerEntryStruct { ... } *SilcServerEntry
*
* DESCRIPTION
*
- * This structure holds SILC network statistics returned by the
- * SILC_COMMAND_STATS command reply to the application.
+ * This structure represents a server in the SILC network. All servers
+ * that the client is aware of and have for example resolved with
+ * SILC_COMMAND_INFO command have their on SilcServerEntry structure.
+ * All strings in the structure are UTF-8 encoded.
*
* SOURCE
*/
-typedef struct {
- SilcUInt32 starttime; /* SILC server start time */
- SilcUInt32 uptime; /* SILC server uptime*/
- SilcUInt32 my_clients; /* Number of clients in the server */
- SilcUInt32 my_channels; /* Number of channel in the server */
- SilcUInt32 my_server_ops; /* Number of server operators in the server */
- SilcUInt32 my_router_ops; /* Number of router operators in the router */
- SilcUInt32 cell_clients; /* Number of clients in the cell */
- SilcUInt32 cell_channels; /* Number of channels in the cell */
- SilcUInt32 cell_servers; /* Number of server in the cell */
- SilcUInt32 clients; /* All clients in SILC network */
- SilcUInt32 channels; /* All channels in SILC network */
- SilcUInt32 servers; /* All servers in SILC network */
- SilcUInt32 routers; /* All routers in SILC network */
- SilcUInt32 server_ops; /* All server operators in SILC network */
- SilcUInt32 router_ops; /* All router operators in SILC network */
-} SilcClientStats;
+struct SilcServerEntryStruct {
+ /* General information */
+ char *server_name; /* Server name */
+ char *server_info; /* Server info */
+ SilcServerID *server_id; /* Server ID */
+ SilcUInt16 resolve_cmd_ident; /* Command identifier when
+ resolving this entry */
+
+ /* Application specific data. Application may set here whatever it wants. */
+ void *context;
+};
/***/
/****d* silcclient/SilcClientAPI/SilcKeyAgreementStatus
SILC_KEY_AGREEMENT_ABORTED, /* The protocol aborted */
SILC_KEY_AGREEMENT_ALREADY_STARTED, /* Already started */
SILC_KEY_AGREEMENT_SELF_DENIED, /* Negotiationg with itself denied */
- SILC_KEY_AGREEMENT_NO_MEMORY, /* System out of memory */
} SilcKeyAgreementStatus;
/***/
SilcClientConnection conn,
SilcClientEntry client_entry,
SilcKeyAgreementStatus status,
- SilcSKEKeyMaterial key,
+ SilcSKEKeyMaterial *key,
void *context);
/****s* silcclient/SilcClientAPI/SilcPrivateMessageKeys
*
* DESCRIPTION
*
- * Structure to hold the list of private message keys. The list of these
- * structures is returned by the silc_client_list_private_message_keys
+ * Structure to hold the list of private message keys. The array of this
+ * structure is returned by the silc_client_list_private_message_keys
* function.
*
* SOURCE
SilcClientEntry client_entry; /* The remote client entry */
char *cipher; /* The cipher name */
unsigned char *key; /* The original key, If the appliation
- provided it. This is NULL if
+ provided it. This is NULL if the
+ library generated the key or if
the SKE key material was used. */
SilcUInt32 key_len; /* The key length */
} *SilcPrivateMessageKeys;
char *name; /* Application given name */
SilcCipher cipher; /* The cipher and key */
SilcHmac hmac; /* The HMAC and hmac key */
+ unsigned char *key; /* The key data */
+ SilcUInt32 key_len; /* The key length */
};
/***/
*
* SYNOPSIS
*
- * typedef void (*SilcVerifyPublicKey)(SilcBool success, void *context);
+ * typedef void (*SilcVerifyPublicKey)(bool success, void *context);
*
* DESCRIPTION
*
* either success or failure.
*
***/
-typedef void (*SilcVerifyPublicKey)(SilcBool success, void *context);
+typedef void (*SilcVerifyPublicKey)(bool success, void *context);
/****f* silcclient/SilcClientAPI/SilcGetAuthMeth
*
* SYNOPSIS
*
- * typedef void (*SilcGetAuthMeth)(SilcBool success,
- * SilcAuthMethod auth_meth,
- * void *auth, SilcUInt32 auth_len,
- * void *context);
+ * typedef void (*SilcGetAuthMeth)(bool success,
+ * SilcProtocolAuthMeth auth_meth,
+ * const unsigned char *auth_data,
+ * SilcUInt32 auth_data_len, void *context);
*
* DESCRIPTION
*
- * Authentication data resolving callback. This is called by the
- * application to return the resolved authentication data. The client
+ * Authentication method resolving callback. This is called by the
+ * application to return the resolved authentication method. The client
* library has called the get_auth_method client operation and given
- * this function pointer as argument. The `auth_meth' is the selected
- * authentication method. The `auth_data' and the `auth_data_len'
+ * this function pointer as argument. The `success' will indicate whether
+ * the authentication method could be resolved. The `auth_meth' is the
+ * resolved authentication method. The `auth_data' and the `auth_data_len'
* are the resolved authentication data. The `context' is the libary's
* context sent to the get_auth_method client operation.
*
- * If the `auth_method' is SILC_AUTH_PASSWORD then `auth' and `auth_len'
- * is the passphrase and its length. If it is SILC_AUTH_PUBLIC_KEY the
- * `auth' must be NULL. The library will use the private key given as
- * argument to silc_client_connect_to_server, silc_client_connect_to_client
- * or silc_client_key_exchange. If it is SILC_AUTH_NONE, both `auth' and
- * `auth_len' are ignored.
- *
***/
-typedef void (*SilcGetAuthMeth)(SilcAuthMethod auth_meth,
- void *auth, SilcUInt32 auth_len,
- void *context);
+typedef void (*SilcGetAuthMeth)(bool success,
+ SilcProtocolAuthMeth auth_meth,
+ const unsigned char *auth_data,
+ SilcUInt32 auth_data_len, void *context);
/****d* silcclient/SilcClientAPI/SilcClientMessageType
*
SILC_CLIENT_MESSAGE_INFO, /* Informational */
SILC_CLIENT_MESSAGE_WARNING, /* Warning */
SILC_CLIENT_MESSAGE_ERROR, /* Error */
- SILC_CLIENT_MESSAGE_COMMAND_ERROR, /* Error during command */
SILC_CLIENT_MESSAGE_AUDIT, /* Auditable */
} SilcClientMessageType;
/***/
+/****d* silcclient/SilcClientAPI/SilcClientConnectionStatus
+ *
+ * NAME
+ *
+ * typedef enum { ... } SilcClientConnectionStatus
+ *
+ * DESCRIPTION
+ *
+ * This type is returned to the `connect' client operation to indicate
+ * the status of the created connection. It can indicate if it was
+ * successful or whether an error occurred.
+ *
+ * SOURCE
+ */
+typedef enum {
+ SILC_CLIENT_CONN_SUCCESS, /* Successfully connected */
+ SILC_CLIENT_CONN_SUCCESS_RESUME, /* Successfully connected and
+ resumed old detached session */
+ SILC_CLIENT_CONN_ERROR, /* Unknown error occurred during
+ connecting */
+ SILC_CLIENT_CONN_ERROR_KE, /* Key Exchange failed */
+ SILC_CLIENT_CONN_ERROR_AUTH, /* Authentication failed */
+ SILC_CLIENT_CONN_ERROR_RESUME, /* Resuming failed */
+ SILC_CLIENT_CONN_ERROR_TIMEOUT, /* Timeout during connecting */
+} SilcClientConnectionStatus;
+/***/
+
/****s* silcclient/SilcClientAPI/SilcClientOperations
*
* NAME
message). */
void (*private_message)(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcMessagePayload payload,
- SilcMessageFlags flags, const unsigned char *message,
+ SilcMessageFlags flags,
+ const unsigned char *message,
SilcUInt32 message_len);
/* Notify message to the client. The notify arguments are sent in the
void (*notify)(SilcClient client, SilcClientConnection conn,
SilcNotifyType type, ...);
- /* Command handler. This function is called always after application has
- called a command. It will be called to indicate that the command
- was processed. It will also be called if error occurs while processing
- the command. The `success' indicates whether the command was sent
- or if error occurred. The `status' indicates the actual error.
- The `argc' and `argv' are the command line arguments sent to the
- command by application. Note that, this is not reply to the command
- from server, this is merely and indication to application that the
- command was processed. */
+ /* Command handler. This function is called always in the command function.
+ If error occurs it will be called as well. `conn' is the associated
+ client connection. `cmd_context' is the command context that was
+ originally sent to the command. `success' is FALSE if error occurred
+ during command. `command' is the command being processed. It must be
+ noted that this is not reply from server. This is merely called just
+ after application has called the command. Just to tell application
+ that the command really was processed. */
void (*command)(SilcClient client, SilcClientConnection conn,
- SilcBool success, SilcCommand command, SilcStatus status,
- SilcUInt32 argc, unsigned char **argv);
+ SilcClientCommandContext cmd_context, bool success,
+ SilcCommand command, SilcStatus status);
/* Command reply handler. This function is called always in the command reply
function. If error occurs it will be called as well. Normal scenario
ID. For example, if Client ID is receives application receives
SilcClientEntry. */
void (*command_reply)(SilcClient client, SilcClientConnection conn,
- SilcCommand command, SilcStatus status,
- SilcStatus error, va_list ap);
+ SilcCommandPayload cmd_payload, bool success,
+ SilcCommand command, SilcStatus status, ...);
+
+ /* Called to indicate that connection was either successfully established
+ or connecting failed. This is also the first time application receives
+ the SilcClientConnection object which it should save somewhere.
+ The `status' indicated whether the connection were successful. If it
+ is error value the application must always call the function
+ silc_client_close_connection. */
+ void (*connected)(SilcClient client, SilcClientConnection conn,
+ SilcClientConnectionStatus status);
+
+ /* Called to indicate that connection was disconnected to the server.
+ The `status' may tell the reason of the disconnection, and if the
+ `message' is non-NULL it may include the disconnection message
+ received from server. Application must not call the
+ silc_client_close_connection in this callback. The 'conn' is also
+ invalid after this function returns back to library. */
+ void (*disconnected)(SilcClient client, SilcClientConnection conn,
+ SilcStatus status, const char *message);
/* Find authentication method and authentication data by hostname and
- port. The hostname may be IP address as well. The `auth_method' is
- the authentication method the remote connection requires. It is
- however possible that remote accepts also some other authentication
- method. Application should use the method that may have been
- configured for this connection. If none has been configured it should
- use the required `auth_method'. If the `auth_method' is
- SILC_AUTH_NONE, server does not require any authentication or the
- required authentication method is not known. The `completion'
- callback must be called to deliver the chosen authentication method
- and data. The `conn' may be NULL. */
+ port. The hostname may be IP address as well. When the authentication
+ method has been resolved the `completion' callback with the found
+ authentication method and authentication data is called. The `conn'
+ may be NULL. */
void (*get_auth_method)(SilcClient client, SilcClientConnection conn,
char *hostname, SilcUInt16 port,
- SilcAuthMethod auth_method,
SilcGetAuthMeth completion, void *context);
/* Verifies received public key. The `conn_type' indicates which entity
- (server or client) has sent the public key. If user decides to trust
- the key the application may save the key as trusted public key for
- later use. The `completion' must be called after the public key has
- been verified. */
+ (server, client etc.) has sent the public key. If user decides to trust
+ the application may save the key as trusted public key for later
+ use. The `completion' must be called after the public key has been
+ verified. */
void (*verify_public_key)(SilcClient client, SilcClientConnection conn,
- SilcConnectionType conn_type,
- SilcPublicKey public_key,
+ SilcSocketType conn_type, unsigned char *pk,
+ SilcUInt32 pk_len, SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context);
/* Ask (interact, that is) a passphrase from user. The passphrase is
void (*ask_passphrase)(SilcClient client, SilcClientConnection conn,
SilcAskPassphrase completion, void *context);
- /* Called to indicate that incoming key agreement request has been
- received. If the application wants to perform key agreement it may
- call silc_client_perform_key_agreement to initiate key agreementn or
- silc_client_send_key_agreement to provide connection point to the
- remote client in case the `hostname' is NULL. If key agreement is
- not desired this request can be ignored. The `protocol' is either
- value 0 for TCP or value 1 for UDP. */
- void (*key_agreement)(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *hostname, SilcUInt16 protocol,
- SilcUInt16 port);
+ /* Notifies application that failure packet was received. This is called
+ if there is some protocol active in the client. The `protocol' is the
+ protocol context. The `failure' is opaque pointer to the failure
+ indication. Note, that the `failure' is protocol dependant and
+ application must explicitly cast it to correct type. Usually `failure'
+ is 32 bit failure type (see protocol specs for all protocol failure
+ types). */
+ void (*failure)(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure);
+
+ /* Asks whether the user would like to perform the key agreement protocol.
+ This is called after we have received an key agreement packet or an
+ reply to our key agreement packet. This returns TRUE if the user wants
+ the library to perform the key agreement protocol and FALSE if it is not
+ desired (application may start it later by calling the function
+ silc_client_perform_key_agreement). If TRUE is returned also the
+ `completion' and `context' arguments must be set by the application. */
+ bool (*key_agreement)(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry, const char *hostname,
+ SilcUInt16 port, SilcKeyAgreementCallback *completion,
+ void **context);
/* Notifies application that file transfer protocol session is being
requested by the remote client indicated by the `client_entry' from
void (*ftp)(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry, SilcUInt32 session_id,
const char *hostname, SilcUInt16 port);
+
+ /* Delivers SILC session detachment data indicated by `detach_data' to the
+ application. If application has issued SILC_COMMAND_DETACH command
+ the client session in the SILC network is not quit. The client remains
+ in the network but is detached. The detachment data may be used later
+ to resume the session in the SILC Network. The appliation is
+ responsible of saving the `detach_data', to for example in a file.
+
+ The detachment data can be given as argument to the functions
+ silc_client_connect_to_server, or silc_client_add_connection when
+ creating connection to remote server, inside SilcClientConnectionParams
+ structure. If it is provided the client library will attempt to resume
+ the session in the network. After the connection is created
+ successfully, the application is responsible of setting the user
+ interface for user into the same state it was before detaching (showing
+ same channels, channel modes, etc). It can do this by fetching the
+ information (like joined channels) from the client library. */
+ void (*detach)(SilcClient client, SilcClientConnection conn,
+ const unsigned char *detach_data,
+ SilcUInt32 detach_data_len);
} SilcClientOperations;
/***/
+/****f* silcclient/SilcClientAPI/SilcNicknameFormatParse
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcNicknameFormatParse)(const char *nickname,
+ * char **ret_nickname);
+ *
+ * DESCRIPTION
+ *
+ * A callback function provided by the application for the library in
+ * SilcClientParams structure. This function parses the formatted
+ * nickname string `nickname' and returns the true nickname to the
+ * `ret_nickname' pointer. The library can call this function at
+ * any time.
+ *
+ ***/
+typedef void (*SilcNicknameFormatParse)(const char *nickname,
+ char **ret_nickname);
+
/****s* silcclient/SilcClientAPI/SilcClientParams
*
* NAME
* SOURCE
*/
typedef struct {
- /* If this boolean is set to TRUE then the client library will use
- threads. Any of the callback functions in the SilcClientOperations
- and other callbacks may be called at any time in a thread. The
- application may need to employ appropriate concurrency control
- in the callbacks to protect application specific data. */
- SilcBool threads;
+ /* Number of maximum tasks the client library's scheduler can handle.
+ If set to zero, the default value will be used (200). For WIN32
+ systems this should be set to 64 as it is the hard limit dictated
+ by the WIN32. */
+ int task_max;
+
+ /* Rekey timeout in seconds. The client will perform rekey in this
+ time interval. If set to zero, the default value will be used. */
+ unsigned int rekey_secs;
+
+ /* Connection authentication method request timeout. If server does not
+ reply back the current authentication method when we've requested it
+ in this time interval we'll assume the reply will not come at all.
+ If set to zero, the default value (2 seconds) will be used. */
+ unsigned int connauth_request_secs;
/* Nickname format string. This can be used to order the client library
to save the nicknames in the library in a certain format. Since
nicknames are not unique in SILC it is possible to have multiple same
nicknames. Using this format string it is possible to order the library
- to separate the multiple same nicknames from each other. If this is
- empty then default format is used which is the default nickname
- without anything else. The string MUST be NULL terminated.
+ to separate the multiple same nicknames from each other. The format
+ types are defined below and they can appear in any order in the format
+ string. If this is NULL then default format is used which is the
+ default nickname without anything else. The string MUST be NULL
+ terminated.
Following format types are available:
"%a!%n@%s" (fe. nick@server, 2!nick@server)
"%n@%H" (fe. nick@host.domain.com)
- Note that there must always be some separator characters around '%n'
- format. It is not possible to put format characters before or after
- '%n' without separators (such ash '@'). Also note that the separator
- character should be a character that cannot be part of normal nickname.
+ By default this format is employed to the nicknames by the libary
+ only when there appears multiple same nicknames. If the library has
+ only one nickname cached the nickname is saved as is and without the
+ defined format. If you want always to save the nickname in the defined
+ format set the boolean field `nickname_force_format' to value TRUE.
*/
char nickname_format[32];
is employed only if the library will receive a nickname that is
already saved in the cache. It is recommended to leave this to FALSE
value. */
- SilcBool nickname_force_format;
+ bool nickname_force_format;
+
+ /* A callback function provided by the application for the library to
+ parse the nickname from the formatted nickname string. Even though
+ the libary formats the nicknames the application knows generally the
+ format better so this function should be provided for the library
+ if the application sets the `nickname_format' field. The library
+ will call this to get the true nickname from the provided formatted
+ nickname string whenever it needs the true nickname. */
+ SilcNicknameFormatParse nickname_parse;
+
+ /* If this is set to TRUE then the client will ignore all incoming
+ Requested Attributes queries and does not reply anything back. This
+ usually leads into situation where server does not anymore send
+ the queries after seeing that client does not reply anything back.
+ If your application does not support Requested Attributes or you do
+ not want to use them set this to TRUE. See SilcAttribute and
+ silc_client_attribute_add for more information on attributes. */
+ bool ignore_requested_attributes;
/* If this is set to TRUE, the silcclient library will not register and
deregister the cipher, pkcs, hash and hmac algorithms. The application
itself will need to handle that. */
- SilcBool dont_register_crypto_library;
+ bool dont_register_crypto_library;
} SilcClientParams;
/***/
*
* SYNOPSIS
*
- * SilcBool silc_client_init(SilcClient client, const char *username,
- * const char *hostname, const char *realname,
- * SilcClientRunning running, void *context);
+ * bool silc_client_init(SilcClient client);
+ *
+ * DESCRIPTION
+ *
+ * Initializes the client. This makes all the necessary steps to make
+ * the client ready to be run. One must call silc_client_run to run the
+ * client. Returns FALSE if error occurred, TRUE otherwise.
+ *
+ ***/
+bool silc_client_init(SilcClient client);
+
+/****f* silcclient/SilcClientAPI/silc_client_run
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_run(SilcClient client);
+ *
+ * DESCRIPTION
+ *
+ * Runs the client. This starts the scheduler from the utility library.
+ * When this functions returns the execution of the appliation is over.
+ * The client must be initialized before calling this.
+ *
+ ***/
+void silc_client_run(SilcClient client);
+
+/****f* silcclient/SilcClientAPI/silc_client_run_one
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_run_one(SilcClient client);
+ *
+ * DESCRIPTION
+ *
+ * Runs the client and returns immeadiately. This function is used when
+ * the SILC Client object indicated by the `client' is run under some
+ * other scheduler, or event loop or main loop. On GUI applications,
+ * for example this may be desired to used to run the client under the
+ * GUI application's main loop. Typically the GUI application would
+ * register an idle task that calls this function multiple times in
+ * a second to quickly process the SILC specific data.
+ *
+ ***/
+void silc_client_run_one(SilcClient client);
+
+/****f* silcclient/SilcClientAPI/silc_client_stop
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_stop(SilcClient client);
*
* DESCRIPTION
*
- * Initializes the client. This makes all the necessary steps to make
- * the client ready to be run. One must call silc_client_run to run the
- * client. Returns FALSE if error occurred, TRUE otherwise.
+ * Stops the client. This is called to stop the client and thus to stop
+ * the program. The client context must be freed with the silc_client_free
+ * function.
+ *
+ ***/
+void silc_client_stop(SilcClient client);
+
+
+/* Connecting functions (client.c) */
+
+/****s* silcclient/SilcClientAPI/SilcClientConnectionParams
+ *
+ * NAME
+ *
+ * typedef struct { ... } SilcClientConnectionParams;
+ *
+ * DESCRIPTION
+ *
+ * Client connection parameters. This can be filled by the application
+ * and given as argument to silc_client_connect_to_server or to
+ * silc_client_add_connection.
+ *
+ * SOURCE
+ */
+typedef struct {
+ /* The SILC session detachment data that was returned by `detach' client
+ operation when the application detached from the network. Application
+ is responsible of saving the data and giving it as argument here
+ for resuming the session in the SILC network.
+
+ If this is provided here the client library will attempt to resume
+ the session in the network. After the connection is created
+ successfully, the application is responsible of setting the user
+ interface for user into the same state it was before detaching (showing
+ same channels, channel modes, etc). It can do this by fetching the
+ information (like joined channels) from the client library. */
+ unsigned char *detach_data;
+ SilcUInt32 detach_data_len;
+
+} SilcClientConnectionParams;
+/***/
+
+/****f* silcclient/SilcClientAPI/silc_client_connect_to_server
+ *
+ * SYNOPSIS
+ *
+ * int silc_client_connect_to_server(SilcClient client,
+ * SilcClientConnectionParams *params,
+ * int port, char *host, void *context);
+ *
+ * DESCRIPTION
+ *
+ * Connects to remote server. This is the main routine used to connect
+ * to SILC server. Returns -1 on error and the created socket otherwise.
+ * The `context' is user context that is saved into the SilcClientConnection
+ * that is created after the connection is created. Note that application
+ * may handle the connecting process outside the library. If this is the
+ * case then this function is not used at all. When the connecting is
+ * done the `connect' client operation is called, and the `context' is
+ * accessible with conn->context, conn being SilcClientConnection.
+ * If the `params' is provided they are used by the routine.
+ *
+ ***/
+int silc_client_connect_to_server(SilcClient client,
+ SilcClientConnectionParams *params,
+ int port, char *host, void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_add_connection
+ *
+ * SYNOPSIS
+ *
+ *
+ * SilcClientConnection
+ * silc_client_add_connection(SilcClient client,
+ * SilcClientConnectionParams *params,
+ * char *hostname, int port, void *context);
+ *
+ * DESCRIPTION
+ *
+ * Allocates and adds new connection to the client. This adds the allocated
+ * connection to the connection table and returns a pointer to it. A client
+ * can have multiple connections to multiple servers. Every connection must
+ * be added to the client using this function. User data `context' may
+ * be sent as argument. If the `params' is provided they are used by
+ * the routine.
+ *
+ * NOTES
+ *
+ * This function is normally used only if the application performed
+ * the connecting outside the library, and did not called the
+ * silc_client_connect_to_server function at all. The library
+ * however may use this internally.
+ *
+ ***/
+SilcClientConnection
+silc_client_add_connection(SilcClient client,
+ SilcClientConnectionParams *params,
+ char *hostname, int port, void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_del_connection
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_del_connection(SilcClient client,
+ * SilcClientConnection conn);
+ *
+ * DESCRIPTION
+ *
+ * Removes connection from client. Frees all memory. The library
+ * call this function automatically for all connection contexts.
+ * The application however may free the connection contexts it has
+ * allocated.
+ *
+ ***/
+void silc_client_del_connection(SilcClient client, SilcClientConnection conn);
+
+/****f* silcclient/SilcClientAPI/silc_client_add_socket
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_add_socket(SilcClient client,
+ * SilcSocketConnection sock);
+ *
+ * DESCRIPTION
+ *
+ * Adds listener socket to the listener sockets table. This function is
+ * used to add socket objects that are listeners to the client. This should
+ * not be used to add other connection objects.
+ *
+ ***/
+void silc_client_add_socket(SilcClient client, SilcSocketConnection sock);
+
+/****f* silcclient/SilcClientAPI/silc_client_del_socket
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_del_socket(SilcClient client,
+ * SilcSocketConnection sock);
+ *
+ * DESCRIPTION
+ *
+ * Deletes listener socket from the listener sockets table. If the
+ * application has added a socket with silc_client_add_socket it must
+ * also free it using this function.
+ *
+ ***/
+void silc_client_del_socket(SilcClient client, SilcSocketConnection sock);
+
+/****f* silcclient/SilcClientAPI/silc_client_start_key_exchange
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_start_key_exchange(SilcClient client,
+ * SilcClientConnection conn,
+ * int fd);
+ *
+ * DESCRIPTION
+ *
+ * Start SILC Key Exchange (SKE) protocol to negotiate shared secret
+ * key material between client and server. This function can be called
+ * directly if application is performing its own connecting and does not
+ * use the connecting provided by this library. This function is normally
+ * used only if the application performed the connecting outside the
+ * library. The library however may use this internally. After the
+ * key exchange is performed the `connect' client operation is called.
+ *
+ * NOTES
+ *
+ * The silc_client_add_connection must be called before calling this
+ * function to create the SilcClientConnection context for this
+ * connection.
+ *
+ ***/
+void silc_client_start_key_exchange(SilcClient client,
+ SilcClientConnection conn,
+ int fd);
+
+/****f* silcclient/SilcClientAPI/silc_client_close_connection
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_close_connection(SilcClient client,
+ * SilcClientConnection conn);
+ *
+ * DESCRIPTION
+ *
+ * Closes connection to remote end. Free's all allocated data except
+ * for some information such as nickname etc. that are valid at all time.
+ * Usually application does not need to directly call this, except
+ * when explicitly closing the connection, or if an error occurs
+ * during connection to server (see 'connect' client operation for
+ * more information).
+ *
+ ***/
+void silc_client_close_connection(SilcClient client,
+ SilcClientConnection conn);
+
+
+/* Message sending functions (client_channel.c and client_prvmsg.c) */
+
+/****f* silcclient/SilcClientAPI/silc_client_send_channel_message
+ *
+ * SYNOPSIS
+ *
+ * bool silc_client_send_channel_message(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcChannelEntry channel,
+ * SilcChannelPrivateKey key,
+ * SilcMessageFlags flags,
+ * unsigned char *data,
+ * SilcUInt32 data_len,
+ * bool_force_send);
+ *
+ * DESCRIPTION
+ *
+ * Sends packet to the `channel'. Packet to channel is always encrypted
+ * differently from "normal" packets. SILC header of the packet is
+ * encrypted with the next receiver's key and the rest of the packet is
+ * encrypted with the channel specific key. Padding and HMAC is computed
+ * with the next receiver's key. The `data' is the channel message. If
+ * the `force_send' is TRUE then the packet is sent immediately.
+ *
+ * If `key' is provided then that private key is used to encrypt the
+ * channel message. If it is not provided, private keys has not been
+ * set at all, the normal channel key is used automatically. If private
+ * keys are set then the first key (the key that was added first as
+ * private key) is used.
+ *
+ * If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
+ * digitally signed with the SILC key pair.
+ *
+ * Returns TRUE if the message was sent, and FALSE if error occurred or
+ * the sending is not allowed due to channel modes (like sending is
+ * blocked).
+ *
+ ***/
+bool silc_client_send_channel_message(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcChannelPrivateKey key,
+ SilcMessageFlags flags,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send);
+
+/****f* silcclient/SilcClientAPI/silc_client_send_private_message
+ *
+ * SYNOPSIS
+ *
+ * bool silc_client_send_private_message(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientEntry client_entry,
+ * SilcMessageFlags flags,
+ * unsigned char *data,
+ * SilcUInt32 data_len,
+ * bool force_send);
+ *
+ * DESCRIPTION
+ *
+ * Sends private message to remote client. If private message key has
+ * not been set with this client then the message will be encrypted using
+ * normal session keys. Private messages are special packets in SILC
+ * network hence we need this own function for them. This is similar
+ * to silc_client_packet_send_to_channel except that we send private
+ * message. The `data' is the private message. If the `force_send' is
+ * TRUE the packet is sent immediately.
+ *
+ * If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
+ * digitally signed with the SILC key pair.
+ *
+ * Returns TRUE if the message was sent, and FALSE if error occurred.
+ *
+ ***/
+bool silc_client_send_private_message(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ SilcMessageFlags flags,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send);
+
+
+/* Client and Channel entry retrieval (idlist.c) */
+
+/****f* silcclient/SilcClientAPI/SilcGetClientCallback
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcGetClientCallback)(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientEntry *clients,
+ * SilcUInt32 clients_count,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Callback function given to the silc_client_get_client function. The
+ * found entries are allocated into the `clients' array. The array must
+ * not be freed by the receiver, the library will free it later. If the
+ * `clients' is NULL, no such clients exist in the SILC Network.
+ *
+ ***/
+typedef void (*SilcGetClientCallback)(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ SilcUInt32 clients_count,
+ void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_get_clients
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_get_clients(SilcClient client,
+ * SilcClientConnection conn,
+ * const char *nickname,
+ * const char *server,
+ * SilcGetClientCallback completion,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Finds client entry or entries by the `nickname' and `server'. The
+ * completion callback will be called when the client entries has been
+ * found. After the server returns the client information it is cached
+ * and can be accesses locally at a later time. The resolving is done
+ * with IDENTIFY command. The `server' may be NULL.
+ *
+ * NOTES
+ *
+ * NOTE: This function is always asynchronous and resolves the client
+ * information from the server. Thus, if you already know the client
+ * information then use the silc_client_get_client_by_id function to
+ * get the client entry since this function may be very slow and should
+ * be used only to initially get the client entries.
+ *
+ * Since this routine resolves with IDENTIFY command only the relevant
+ * information (user's nickname and username) is resolved. For example,
+ * user's real name, channel list and others are not resolved. Caller
+ * can/must resolve those separately if they are needed (for example,
+ * with silc_client_get_client_by_id_resolve).
+ *
+ ***/
+void silc_client_get_clients(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *server,
+ SilcGetClientCallback completion,
+ void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_get_clients_whois
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_get_clients_whois(SilcClient client,
+ * SilcClientConnection conn,
+ * const char *nickname,
+ * const char *server,
+ * SilcBuffer attributes,
+ * SilcGetClientCallback completion,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Finds client entry or entries by the `nickname' and `server'. The
+ * completion callback will be called when the client entries has been
+ * found. After the server returns the client information it is cached
+ * and can be accesses locally at a later time. The resolving is done
+ * with WHOIS command. The `server' may be NULL.
+ *
+ * If the `attributes' is non-NULL then the buffer includes Requested
+ * Attributes which can be used to fetch very detailed information
+ * about the user. If it is NULL then only normal WHOIS query is
+ * made (for more information about attributes see SilcAttribute).
+ * Caller may create the `attributes' with silc_client_attributes_request
+ * function.
+ *
+ * NOTES
+ *
+ * The resolving is done with WHOIS command. For this reason this
+ * command may take a long time because it resolves detailed user
+ * information.
+ *
+ ***/
+void silc_client_get_clients_whois(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *server,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_get_clients_local
+ *
+ * SYNOPSIS
+ *
+ * SilcClientEntry *silc_client_get_clients_local(SilcClient client,
+ * SilcClientConnection conn,
+ * const char *nickname,
+ * const char *format,
+ * SilcUInt32 *clients_count);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_client_get_clients function but does not resolve anything
+ * from the server. This checks local cache and returns all matching
+ * clients from the local cache. If none was found this returns NULL.
+ * The `nickname' is the real nickname of the client, and the `format'
+ * is the formatted nickname to find exact match from multiple found
+ * entries. The format must be same as given in the SilcClientParams
+ * structure to the client library. If the `format' is NULL all found
+ * clients by `nickname' are returned. The caller must return the
+ * returned array.
+ *
+ ***/
+SilcClientEntry *silc_client_get_clients_local(SilcClient client,
+ SilcClientConnection conn,
+ const char *nickname,
+ const char *format,
+ SilcUInt32 *clients_count);
+
+/****f* silcclient/SilcClientAPI/silc_client_get_clients_by_channel
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_get_clients_by_channel(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcChannelEntry channel,
+ * SilcGetClientCallback completion,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Gets client entries by the channel indicated by `channel'. Thus,
+ * it resovles the users currently on that channel. If all users are
+ * already resolved this returns the users from the channel. If the
+ * users are resolved only partially this resolves the complete user
+ * information. If no users are resolved on this channel at all, this
+ * calls USERS command to resolve all users on the channel. The `completion'
+ * will be called after the entries are available. When server returns
+ * the client information it will be cached and can be accessed locally
+ * at a later time.
+ *
+ * This function can be used for example in SILC_COMMAND_JOIN command
+ * reply handling in application to resolve users on that channel. It
+ * also can be used after calling silc_client_get_channel_resolve to
+ * resolve users on that channel.
*
- * The `username' and `hostname' strings must be given and they must be
- * UTF-8 encoded. The `username' is the client's username in the
- * operating system, `hostname' is the client's host name and the
- * `realname' is the user's real name.
+ * NOTES
*
- * The `running' callback is called after the client is running after
- * silc_client_run or silc_client_run_one has been called. Application
- * may start using the Client library API after that. Setting the
- * callback is optional, but recommended.
+ * The resolving is done with WHOIS command. For this reason this
+ * command may take a long time because it resolves detailed user
+ * information.
*
***/
-SilcBool silc_client_init(SilcClient client, const char *username,
- const char *hostname, const char *realname,
- SilcClientRunning running, void *context);
+void silc_client_get_clients_by_channel(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcGetClientCallback completion,
+ void *context);
-/****f* silcclient/SilcClientAPI/silc_client_run
+/****f* silcclient/SilcClientAPI/silc_client_get_clients_by_list
*
* SYNOPSIS
*
- * void silc_client_run(SilcClient client);
+ * void silc_client_get_clients_by_list(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcUInt32 list_count,
+ * SilcBuffer client_id_list,
+ * SilcGetClientCallback completion,
+ * void *context);
*
* DESCRIPTION
*
- * Runs the client. This starts the scheduler from the utility library.
- * When this functions returns the execution of the application is over.
- * The client must be initialized before calling this.
+ * Gets client entries by the list of client ID's `client_id_list'. This
+ * always resolves those client ID's it does not know yet from the server
+ * so this function might take a while. The `client_id_list' is a list
+ * of ID Payloads added one after other. JOIN command reply and USERS
+ * command reply for example returns this sort of list. The `completion'
+ * will be called after the entries are available. When server returns
+ * the client information it will be cached and can be accessed locally
+ * at a later time.
+ *
+ * NOTES
+ *
+ * The resolving is done with IDENTIFY command. This means that only
+ * the relevant information of user (it's nickname and username) is
+ * resolved. For example, user's real name, channel lists and others
+ * are not resolved. Caller can/must resolve those separately if they
+ * are needed (for example, with silc_client_get_client_by_id_resolve).
*
***/
-void silc_client_run(SilcClient client);
+void silc_client_get_clients_by_list(SilcClient client,
+ SilcClientConnection conn,
+ SilcUInt32 list_count,
+ SilcBuffer client_id_list,
+ SilcGetClientCallback completion,
+ void *context);
-/****f* silcclient/SilcClientAPI/silc_client_run_one
+/****f* silcclient/SilcClientAPI/silc_client_get_client_by_id
*
* SYNOPSIS
*
- * void silc_client_run_one(SilcClient client);
+ * SilcClientEntry silc_client_get_client_by_id(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientID *client_id);
*
* DESCRIPTION
*
- * Runs the client and returns immeadiately. This function is used when
- * the SILC Client object indicated by the `client' is run under some
- * other scheduler, or event loop or main loop. On GUI applications,
- * for example this may be desired to used to run the client under the
- * GUI application's main loop. Typically the GUI application would
- * register an idle task that calls this function multiple times in
- * a second to quickly process the SILC specific data.
+ * Find entry for client by the client's ID. Returns the entry or NULL
+ * if the entry was not found. This checks the local cache and does
+ * not resolve anything from server.
*
***/
-void silc_client_run_one(SilcClient client);
+SilcClientEntry silc_client_get_client_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientID *client_id);
-/****f* silcclient/SilcClientAPI/silc_client_stop
+/****f* silcclient/SilcClientAPI/silc_client_get_client_by_id_resolve
*
* SYNOPSIS
*
- * void silc_client_stop(SilcClient client, SilcClientStopped stopped,
- * void *context);
+ * void
+ * silc_client_get_client_by_id_resolve(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientID *client_id,
+ * SilcBuffer attributes,
+ * SilcGetClientCallback completion,
+ * void *context);
*
* DESCRIPTION
*
- * Stops the client. This is called to stop the client and thus to stop
- * the program. The client context must be freed with the silc_client_free
- * function. All connections that exist in this client must be closed
- * before calling this function. Connections can be closed by calling
- * silc_client_close_connection.
+ * Same as silc_client_get_client_by_id but will always resolve the
+ * information from the server. Use this only if you know that you
+ * do not have the entry and the only thing you know about the client
+ * is its ID. When server returns the client information it will be
+ * cache and can be accessed locally at a later time. The resolving
+ * is done by sending WHOIS command.
*
- * The `stopped' will be called once the client and all connections have
- * finished. The client may be freed after that. Note that the `stopped'
- * won't be called before all connections have finished. Setting the
- * callback is optional.
+ * If the `attributes' is non-NULL then the buffer includes Requested
+ * Attributes which can be used to fetch very detailed information
+ * about the user. If it is NULL then only normal WHOIS query is
+ * made (for more information about attributes see SilcAttribute).
+ * Caller may create the `attributes' with silc_client_attributes_request
+ * function.
*
***/
-void silc_client_stop(SilcClient client, SilcClientStopped stopped,
- void *context);
-
-/* Connecting functions */
+void silc_client_get_client_by_id_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientID *client_id,
+ SilcBuffer attributes,
+ SilcGetClientCallback completion,
+ void *context);
-/****s* silcclient/SilcClientAPI/SilcClientConnectionParams
+/****f* silcclient/SilcClientAPI/silc_client_del_client
*
- * NAME
+ * SYNOPSIS
*
- * typedef struct { ... } SilcClientConnectionParams;
+ * bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
+ * SilcClientEntry client_entry)
*
* DESCRIPTION
*
- * Client connection parameters. This can be filled by the application
- * and given as argument to silc_client_connect_to_server,
- * silc_client_connect_to_client, silc_client_key_exchange or
- * silc_client_send_key_agreement.
+ * Removes client from local cache by the client entry indicated by
+ * the `client_entry'. Returns TRUE if the deletion were successful.
*
- * SOURCE
- */
-typedef struct {
- /* If this is provided the user's nickname in the network will be the
- string given here. If it is given, it must be UTF-8 encoded. If this
- string is not given, the user's username by default is used as nickname.
- The nickname may later be changed by using NICK command. The maximum
- length for the nickname string is 128 bytes. */
- char *nickname;
-
- /* If this key repository pointer is non-NULL then public key received in
- the key exchange protocol will be verified from this repository. If
- this is not provided then the `verify_public_key' client operation will
- be called back to application. If the boolean `verify_notfound' is set
- to TRUE then the `verify_public_key' client operation will be called
- in case the public key is not found in `repository'. Only public keys
- added with at least SILC_SKR_USAGE_KEY_AGREEMENT in the repository will
- be checked, other keys will be ignored. */
- SilcSKR repository;
- SilcBool verify_notfound;
-
- /* Authentication data. Application may set here the authentication data
- and authentication method to be used in connecting. If `auth_set'
- boolean is TRUE then authentication data is provided by application.
- If the authentication method is public key authentication then the key
- pair given as argument when connecting will be used and `auth' field
- is NULL. If it is passphrase authentication, it can be provided in
- `auth' and `auth_len' fields. If `auth_set' is FALSE
- the `get_auth_method' client operation will be called to get the
- authentication method and data from application. */
- SilcBool auth_set;
- SilcAuthMethod auth_method;
- void *auth;
- SilcUInt32 auth_len;
-
- /* If this boolean is set to TRUE then the connection will use UDP instead
- of TCP. If UDP is set then also the next `local_ip' and `local_port'
- must be set. */
- SilcBool udp;
-
- /* The `local_ip' specifies the local IP address used with the connection.
- It must be non-NULL if `udp' boolean is TRUE. If the `local_port' is
- non-zero it will be used as local port with UDP connection. The remote
- host will also send packets to the specified address and port. If the
- `bind_ip' is non-NULL a listener is bound to that address instead of
- `local_ip'. */
- char *local_ip;
- char *bind_ip;
- int local_port;
-
- /* If this boolean is set to TRUE then the key exchange is done with
- perfect forward secrecy. */
- SilcBool pfs;
-
- /* If this boolean is set to TRUE then connection authentication protocol
- is not performed during connecting. Only key exchange protocol is
- performed. This usually must be set to TRUE when connecting to another
- client, but must be FALSE with server connections. */
- SilcBool no_authentication;
-
- /* The SILC session detachment data that was returned in the `command_reply'
- client operation for SILC_COMMAND_DETACH command. If this is provided
- here the client library will attempt to resume the session in the network.
- After the connection is created and the session has been resumed the
- client will receive SILC_COMMAND_NICK command_reply for the client's
- nickname in the network and SILC_COMMAND_JOIN command reply for all the
- channels that the client has joined in the network. It may also receive
- SILC_COMMAND_UMODE command reply to set user's mode on the network. */
- unsigned char *detach_data;
- SilcUInt32 detach_data_len;
-
- /* Connection timeout. If non-zero, the connection will timeout unless
- the SILC connection is completed in the specified amount of time. */
- SilcUInt32 timeout_secs;
-
- /* Rekey timeout in seconds. The client will perform rekey in this
- time interval. If set to zero, the default value will be used
- (3600 seconds, 1 hour). */
- SilcUInt32 rekey_secs;
-
- /* If this is set to TRUE then the client will ignore all incoming
- Requested Attributes queries and does not reply anything back. This
- usually leads into situation where server does not anymore send
- the queries after seeing that client does not reply anything back.
- If your application does not support Requested Attributes or you do
- not want to use them set this to TRUE. See SilcAttribute and
- silc_client_attribute_add for more information on attributes. */
- SilcBool ignore_requested_attributes;
-
-} SilcClientConnectionParams;
-/***/
+ ***/
+bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry);
-/****f* silcclient/SilcClientAPI/silc_client_connect_to_server
+/****f* silcclient/SilcClientAPI/SilcGetChannelCallback
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_client_connect_to_server(SilcClient client,
- * SilcClientConnectionParams *params,
- * SilcPublicKey public_key,
- * SilcPrivateKey private_key,
- * char *remote_host, int port,
- * SilcClientConnectCallback callback,
- * void *context);
+ * typedef void (*SilcGetChannelCallback)(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcChannelEntry *channels,
+ * SilcUInt32 channels_count,
+ * void *context);
*
* DESCRIPTION
*
- * Connects to remote server `remote_host' at port `port'. This function
- * can be used to create connection to remote SILC server and start
- * SILC session in the SILC network. The `params' may be provided
- * to provide various connection parameters. The `public_key' and the
- * `private_key' is your identity used in this connection. When
- * authentication method is based on digital signatures, this key pair
- * will be used. The `callback' with `context' will be called after the
- * connection has been created. It will also be called later when remote
- * host disconnects.
- *
- * If application wishes to create the network connection itself, use
- * the silc_client_key_exchange after creating the connection to start
- * key exchange and authentication with the server.
- *
- * Returns SilcAsyncOperation which can be used to cancel the connecting,
- * or NULL on error. Note that the returned pointer becomes invalid
- * after the `callback' is called.
+ * Callback function given to the silc_client_get_channel_* functions.
+ * The found entries are allocated into the `channels' array. The array
+ * must not be freed by the receiver, the library will free it later.
+ * If the `channel' is NULL, no such channel exist in the SILC Network.
*
***/
-SilcAsyncOperation
-silc_client_connect_to_server(SilcClient client,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *remote_host, int port,
- SilcClientConnectCallback callback,
- void *context);
+typedef void (*SilcGetChannelCallback)(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry *channels,
+ SilcUInt32 channels_count,
+ void *context);
-/****f* silcclient/SilcClientAPI/silc_client_connect_to_client
+/****f* silcclient/SilcClientAPI/silc_client_get_channel
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_client_connect_to_client(SilcClient client,
- * SilcClientConnectionParams *params,
- * SilcPublicKey public_key,
- * SilcPrivateKey private_key,
- * char *remote_host, int port,
- * SilcClientConnectCallback callback,
- * void *context);
+ * SilcChannelEntry silc_client_get_channel(SilcClient client,
+ * SilcClientConnection conn,
+ * char *channel_name);
*
* DESCRIPTION
*
- * Connects to remote client `remote_host' at port `port'. This function
- * can be used to create peer-to-peer connection to another SILC client,
- * for example, for direct conferencing, or file transfer or for other
- * purposes. The `params' may be provided to provide various connection
- * parameters. The `public_key' and the `private_key' is your identity
- * used in this connection. The `callback' with `context' will be called
- * after the connection has been created. It will also be called later
- * when remote host disconnects.
- *
- * If application wishes to create the network connection itself, use
- * the silc_client_key_exchange after creating the connection to start
- * key exchange with the client.
- *
- * Returns SilcAsyncOperation which can be used to cancel the connecting,
- * or NULL on error. Note that the returned pointer becomes invalid
- * after the `callback' is called.
+ * Finds entry for channel by the channel name. Returns the entry or NULL
+ * if the entry was not found. It is found only if the client is joined
+ * to the channel. Use silc_client_get_channel_resolve or
+ * silc_client_get_channel_by_id_resolve to resolve channel that client
+ * is not joined.
*
***/
-SilcAsyncOperation
-silc_client_connect_to_client(SilcClient client,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *remote_host, int port,
- SilcClientConnectCallback callback,
- void *context);
+SilcChannelEntry silc_client_get_channel(SilcClient client,
+ SilcClientConnection conn,
+ char *channel_name);
-/****f* silcclient/SilcClientAPI/silc_client_key_exchange
+/****f* silcclient/SilcClientAPI/silc_client_get_channel_resolve
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_client_key_exchange(SilcClient client,
- * SilcClientConnectionParams *params,
- * SilcPublicKey public_key,
- * SilcPrivateKey private_key,
- * SilcStream stream,
- * SilcConnectionType conn_type,
- * SilcClientConnectCallback callback,
- * void *context);
+ * void silc_client_get_channel_resolve(SilcClient client,
+ * SilcClientConnection conn,
+ * char *channel_name,
+ * SilcGetChannelCallback completion,
+ * void *context);
*
* DESCRIPTION
*
- * Starts key exchange protocol and authentication protocol in the
- * connection indicated by `stream'. This function can be be used to
- * start SILC session with remote host (usually server) when the caller
- * has itself created the connection, instead of calling the function
- * silc_client_connect_to_server or silc_client_connect_to_client. If
- * one of those functions was used this function must not be called as
- * in that case the key exchange is performed automatically.
- *
- * Use this function only if you have created the connection by yourself.
- * After creating the connection the socket must be wrapped into a
- * socket stream. See silcsocketstream.h for more information. Note that
- * the `stream' must have valid remote IP address (and optionally also
- * hostname) and port set.
- *
- * The `params' may be provided to provide various connection parameters.
- * The `public_key' and the `private_key' is your identity used in this
- * session. The `callback' with `context' will be called after the session
- * has been set up. It will also be called later when remote host
- * disconnects. The `conn_type' is the type of session this is going to
- * be.
- *
- * Returns SilcAsyncOperation which can be used to cancel the connecting,
- * or NULL on error. Note that the returned pointer becomes invalid
- * after the `callback' is called.
- *
- * EXAMPLE
+ * Resolves entry for channel by the channel name from the server.
+ * The resolving is done with IDENTIFY command. Note that users on
+ * the channel are not resolved at the same time. Use for example
+ * silc_client_get_clients_by_channel to resolve all users on a channel.
*
- * int sock;
- *
- * // Create remote connection stream. Resolve hostname and IP also.
- * sock = create_connection(remote_host, port);
- * silc_socket_tcp_stream_create(sock, TRUE, FALSE, schedule,
- * stream_create_cb, app);
- *
- * // Stream callback delivers our new SilcStream context
- * void stream_create_cb(SilcSocketStreamStatus status, SilcStream stream,
- * void *context)
- * {
- * ...
- * if (status != SILC_SOCKET_OK)
- * error(status);
- *
- * // Start key exchange
- * silc_client_key_exchange(client, NULL, public_key, private_key,
- * stream, SILC_CONN_SERVER, connection_cb, app);
- * ...
- * }
- *
- ***/
-SilcAsyncOperation
-silc_client_key_exchange(SilcClient client,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcStream stream,
- SilcConnectionType conn_type,
- SilcClientConnectCallback callback,
- void *context);
+ ***/
+void silc_client_get_channel_resolve(SilcClient client,
+ SilcClientConnection conn,
+ char *channel_name,
+ SilcGetChannelCallback completion,
+ void *context);
-/****f* silcclient/SilcClientAPI/silc_client_close_connection
+/****f* silcclient/SilcClientAPI/silc_client_get_channel_by_id
*
* SYNOPSIS
*
- * void silc_client_close_connection(SilcClient client,
- * SilcClientConnection conn);
+ * SilcChannelEntry
+ * silc_client_get_channel_by_id(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcChannelID *channel_id);
*
* DESCRIPTION
*
- * Closes the remote connection `conn'. The `conn' will become invalid
- * after this call. Usually this function is called only when explicitly
- * closing connection for example in case of error, or when the remote
- * connection was created by the application or when the remote is client
- * connection. Server connections are usually closed by sending QUIT
- * command to the server. However, this call may also be used.
+ * Finds channel entry by the channel ID. Returns the entry or NULL
+ * if the entry was not found. This checks the local cache and does
+ * not resolve anything from server.
*
***/
-void silc_client_close_connection(SilcClient client,
- SilcClientConnection conn);
-
-/* Message sending functions */
+SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelID *channel_id);
-/****f* silcclient/SilcClientAPI/silc_client_send_channel_message
+/****f* silcclient/SilcClientAPI/silc_client_get_channel_by_id_resolve
*
* SYNOPSIS
*
- * SilcBool silc_client_send_channel_message(SilcClient client,
- * SilcClientConnection conn,
- * SilcChannelEntry channel,
- * SilcChannelPrivateKey key,
- * SilcMessageFlags flags,
- * SilcHash hash,
- * unsigned char *data,
- * SilcUInt32 data_len);
+ * void
+ * silc_client_get_channel_by_id_resolve(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcChannelID *channel_id,
+ * SilcGetClientCallback completion,
+ * void *context);
*
* DESCRIPTION
*
- * Sends packet to the `channel'. Packet to channel is always encrypted
- * differently from "normal" packets. SILC header of the packet is
- * encrypted with the next receiver's key and the rest of the packet is
- * encrypted with the channel specific key. Padding and HMAC is computed
- * with the next receiver's key. The `data' is the channel message.
- *
- * If `key' is provided then that private key is used to encrypt the
- * channel message. If it is not provided, private keys has not been
- * set at all, the normal channel key is used automatically. If private
- * keys are set then the first key (the key that was added first as
- * private key) is used.
- *
- * If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
- * digitally signed with the SILC key pair. In this case the `hash'
- * pointer must be provided as well.
+ * Resolves the channel information (its name mainly) from the server
+ * by the `channel_id'. Use this only if you know that you do not have
+ * the entry cached locally. The resolving is done with IDENTIFY command.
*
- * Returns TRUE if the message was sent, and FALSE if error occurred or
- * the sending is not allowed due to channel modes (like sending is
- * blocked). This function is thread safe and private messages can be
- * sent from multiple threads.
+ * Note that users on the channel are not resolved at the same time.
+ * Use for example silc_client_get_clients_by_channel to resolve all
+ * users on a channel.
*
***/
-SilcBool silc_client_send_channel_message(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcChannelPrivateKey key,
- SilcMessageFlags flags,
- SilcHash hash,
- unsigned char *data,
- SilcUInt32 data_len);
+void silc_client_get_channel_by_id_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelID *channel_id,
+ SilcGetChannelCallback completion,
+ void *context);
-/****f* silcclient/SilcClientAPI/silc_client_send_private_message
+/****f* silcclient/SilcClientAPI/silc_client_del_channel
*
* SYNOPSIS
*
- * SilcBool silc_client_send_private_message(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry,
- * SilcMessageFlags flags,
- * SilcHash hash,
- * unsigned char *data,
- * SilcUInt32 data_len);
+ * bool silc_client_del_channel(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcChannelEntry channel)
*
* DESCRIPTION
*
- * Sends private message to remote client. If private message key has
- * not been set with this client then the message will be encrypted using
- * normal session keys. If the `flags' includes SILC_MESSAGE_FLAG_SIGNED
- * the message will be digitally signed with the SILC key pair. In this
- * case the caller must also provide the `hash' pointer.
- *
- * Returns TRUE if the message was sent, and FALSE if error occurred.
- * This function is thread safe and private messages can be sent from
- * multiple threads.
+ * Removes channel from local cache by the channel entry indicated by
+ * the `channel'. Returns TRUE if the deletion were successful.
*
***/
-SilcBool silc_client_send_private_message(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcMessageFlags flags,
- SilcHash hash,
- unsigned char *data,
- SilcUInt32 data_len);
+bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
+ SilcChannelEntry channel);
-/****f* silcclient/SilcClientAPI/silc_client_private_message_wait_init
+/****f* silcclient/SilcClientAPI/silc_client_get_server
*
* SYNOPSIS
*
- * SilcBool
- * silc_client_private_message_wait_init(SilcClient client,
- * SilcClientConnection conn);
+ * SilcServerEntry silc_client_get_server(SilcClient client,
+ * SilcClientConnection conn,
+ * char *server_name)
*
* DESCRIPTION
*
- * Initializes private message waiting functionality for the connection
- * indicated by `conn'. Once this is called private message from remote
- * connection indicated by `conn' for any client entry beloning to that
- * connection may be waited for, for example in an thread. The function
- * silc_client_private_message_wait is used to block the current thread
- * until a private message is received from a specified client entry.
- * Return FALSE on error.
+ * Finds entry for server by the server name. Returns the entry or NULL
+ * if the entry was not found.
*
***/
-SilcBool silc_client_private_message_wait_init(SilcClient client,
- SilcClientConnection conn);
+SilcServerEntry silc_client_get_server(SilcClient client,
+ SilcClientConnection conn,
+ char *server_name);
-/****f* silcclient/SilcClientAPI/silc_client_private_message_wait_uninit
+/****f* silcclient/SilcClientAPI/silc_client_get_server_by_id
*
* SYNOPSIS
*
- * void
- * silc_client_private_message_wait_uninit(SilcClient client,
- * SilcClientConnection conn);
+ * SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcServerID *server_id);
*
* DESCRIPTION
*
- * Unintializes private message waiting for connection indicated by
- * `conn'. After this call private message cannot be waited anymore.
- * This call may be called from any thread. This call will signal all
- * private message waiting threads to stop waiting.
+ * Finds entry for server by the server ID. Returns the entry or NULL
+ * if the entry was not found.
*
***/
-void silc_client_private_message_wait_uninit(SilcClient client,
- SilcClientConnection conn);
+SilcServerEntry silc_client_get_server_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcServerID *server_id);
-/****f* silcclient/SilcClientAPI/silc_client_private_message_wait
+/****f* silcclient/SilcClientAPI/silc_client_del_server
*
* SYNOPSIS
*
- * SilcBool
- * silc_client_private_message_wait(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry,
- * SilcMessagePayload *payload);
+ * bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
+ * SilcServerEntry server);
*
* DESCRIPTION
*
- * Blocks current thread or process until a private message has been
- * received from the remote client indicated by `client_entry'. Before
- * private messages can be waited the silc_client_private_message_wait_init
- * must be called. This function can be used from a thread to wait for
- * private message from the specified client. Multiple threads can be
- * created to wait messages from multiple clients. Any other private
- * message received from the connection indicated by `conn' will be
- * forwarded to the normal `private_message' client operation. The
- * private messages from `client_entry' will not be delivered to the
- * `private_message' client operation.
- *
- * Returns TRUE and the received private message into `payload'. The caller
- * must free the returned SilcMessagePayload. If this function returns
- * FALSE the private messages cannot be waited anymore. This happens
- * when some other thread calls silc_client_private_message_wait_uninit.
- * This returns FALSE also if silc_client_private_message_wait_init has
- * not been called.
+ * Removes server from local cache by the server entry indicated by
+ * the `server'. Returns TRUE if the deletion were successful.
*
***/
-SilcBool silc_client_private_message_wait(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcMessagePayload *payload);
+bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
+ SilcServerEntry server);
/****f* silcclient/SilcClientAPI/silc_client_on_channel
*
SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
SilcClientEntry client_entry);
-
-/* Command management */
+/* Command management (command.c) */
/****f* silcclient/SilcClientAPI/silc_client_command_call
*
* SYNOPSIS
*
- * SilcUInt16 silc_client_command_call(SilcClient client,
- * SilcClientConnection conn,
- * const char *command_line, ...);
+ * bool silc_client_command_call(SilcClient client,
+ * SilcClientConnection conn,
+ * const char *command_line, ...);
*
* DESCRIPTION
*
* function instead.
*
***/
-SilcUInt16 silc_client_command_call(SilcClient client,
- SilcClientConnection conn,
- const char *command_line, ...);
-
-/****f* silcclient/SilcClientAPI/SilcClientCommandReply
- *
- * SYNOPSIS
- *
- * typedef SilcBool (*SilcClientCommandReply)(SilcClient client,
- * SilcClientConnection conn,
- * SilcCommand command,
- * SilcStatus status,
- * SilcStatus error,
- * void *context,
- * va_list ap);
- *
- * DESCRIPTION
- *
- * The command reply callback function given as argument to functions
- * silc_client_command_send and silc_client_command_pending. This is
- * called to deliver the command replies to the caller. Each command
- * reply received from the server to the `command' will be delivered
- * separately to the caller by calling this callback. The `status' will
- * indicate whether there is only one reply or multiple replies. The
- * `error' will indicate if an error occurred. The `ap' will include
- * command reply arguments. They are the same arguments as for
- * `command_reply' client operation in SilcClientOperations.
- *
- * If `status' is SILC_STATUS_OK only one reply was received and error
- * did not occur. If it is SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM
- * or SILC_STATUS_LIST_END, there are will be two or more replies. The
- * first reply is SILC_STATUS_LIST_START and last one SILC_STATUS_LIST_END.
- *
- * If FALSE is returned in this function this callback will not be called
- * again for `command' even if there are more comand replies. By returning
- * FALSE the caller my stop the command reply handling when needed.
- *
- ***/
-typedef SilcBool (*SilcClientCommandReply)(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap);
+bool silc_client_command_call(SilcClient client,
+ SilcClientConnection conn,
+ const char *command_line, ...);
/****f* silcclient/SilcClientAPI/silc_client_command_send
*
* SYNOPSIS
*
- * SilcUInt16 silc_client_command_send(SilcClient client,
- * SilcClientConnection conn,
- * SilcCommand command,
- * SilcClientCommandReply reply,
- * void *reply_context,
- * SilcUInt32 argc, ...);
+ * void silc_client_command_send(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcCommand command, SilcUInt16 ident,
+ * SilcUInt32 argc, ...);
*
* DESCRIPTION
*
- * Generic function to send any command. The arguments must be given
- * already encoded into correct format and in correct order. If application
- * wants to perform the commands by itself, it can do so and send the data
+ * Generic function to send any command. The arguments must be sent already
+ * encoded into correct form and in correct order. If application wants
+ * to perform the commands by itself, it can do so and send the data
* directly to the server using this function. If application is using
* the silc_client_command_call, this function is usually not used.
+ * Note that this overriders the Client Librarys commands and sends
+ * the command packet directly to server.
+ *
* Programmer should get familiar with the SILC protocol commands
* specification when using this function, as the arguments needs to
* be encoded as specified in the protocol.
*
- * The variable arguments are a set of { type, data, data_length },
- * and the `argc' is the number of these sets.
- *
- * The `reply' callback must be provided, and it is called when the
- * command reply is received from the server. Note that, when using this
- * function the default `command_reply' client operation will not be
- * called, when reply is received.
- *
- * Returns command identifier for this sent command. It can be used
- * to additionally attach to the command reply using the function
- * silc_client_command_pending, if needed. Returns 0 on error,
+ * The variable arguments are a pair of { type, data, data_length },
+ * and the `argc' is the number of these pairs.
*
* EXAMPLE
*
- * silc_client_command_send(client, conn, SILC_COMMAND_WHOIS,
- * my_whois_command_reply, cmd_ctx,
- * 1, 1, nickname, strlen(nickname));
+ * silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, 0, 1,
+ * 1, nickname, strlen(nickname));
*
***/
-SilcUInt16 silc_client_command_send(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcClientCommandReply reply,
- void *reply_context,
- SilcUInt32 argc, ...);
+void silc_client_command_send(SilcClient client, SilcClientConnection conn,
+ SilcCommand command, SilcUInt16 ident,
+ SilcUInt32 argc, ...);
/****f* silcclient/SilcClientAPI/silc_client_command_pending
*
*
* void silc_client_command_pending(SilcClientConnection conn,
* SilcCommand reply_cmd,
- * SilcUInt16 cmd-ident,
+ * SilcUInt16 ident,
* SilcCommandCb callback,
* void *context);
*
* SilcClientCommandReplyContext which includes the internals of the
* command reply.
*
- * The `cmd_ident' is a command identifier which was set for the earlier
+ * The `ident' is a command identifier which was set for the earlier
* sent command. The command reply will include the same identifier
* and pending command callback will be called when the reply is
* received with the same command identifier. It is possible to
* my_ping_handler, my_ping_context);
*
***/
-SilcBool silc_client_command_pending(SilcClientConnection conn,
- SilcCommand command,
- SilcUInt16 cmd_ident,
- SilcClientCommandReply reply,
- void *context);
+void silc_client_command_pending(SilcClientConnection conn,
+ SilcCommand reply_cmd,
+ SilcUInt16 ident,
+ SilcCommandCb callback,
+ void *context);
-/* Private Message key management */
+/* Private Message key management (client_prvmsg.c) */
/****f* silcclient/SilcClientAPI/silc_client_add_private_message_key
*
* SYNOPSIS
*
- * SilcBool
- * silc_client_add_private_message_key(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry,
- * const char *cipher,
- * const char *hmac,
- * unsigned char *key,
- * SilcUInt32 key_len);
+ * bool silc_client_add_private_message_key(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientEntry client_entry,
+ * const char *cipher,
+ * const char *hmac,
+ * unsigned char *key,
+ * SilcUInt32 key_len,
+ * bool generate_key,
+ * bool responder);
*
* DESCRIPTION
*
- * Adds a static private message key to the client library. The key
- * will be used to encrypt all private message between the client and
- * the remote client indicated by the `client_entry'. The `key' can
- * be for example a pre-shared-key, passphrase or similar shared secret
- * string. The `cipher' and `hmac' MAY be provided but SHOULD be NULL
- * to assure that the requirements of the SILC protocol are met. The
- * API, however, allows to allocate any cipher and HMAC.
+ * Adds private message key to the client library. The key will be used to
+ * encrypt all private message between the client and the remote client
+ * indicated by the `client_entry'. If the `key' is NULL and the boolean
+ * value `generate_key' is TRUE the library will generate random key.
+ * The `key' maybe for example pre-shared-key, passphrase or similar.
+ * The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
+ * that the requirements of the SILC protocol are met. The API, however,
+ * allows to allocate any cipher and HMAC.
*
- * If the private message key is added to client without first receiving
- * a request for it from the remote `client_entry' this function will
- * send the request to `client_entry'. Note that, the actual key is
- * not sent to the network.
+ * If `responder' is TRUE then the sending and receiving keys will be
+ * set according the client being the receiver of the private key. If
+ * FALSE the client is being the sender (or negotiator) of the private
+ * key.
*
* It is not necessary to set key for normal private message usage. If the
* key is not set then the private messages are encrypted using normal
- * session keys. Setting the private key, however, increases the security.
+ * session keys. Setting the private key, however, increases the security.
*
* Returns FALSE if the key is already set for the `client_entry', TRUE
* otherwise.
*
***/
-SilcBool silc_client_add_private_message_key(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *cipher,
- const char *hmac,
- unsigned char *key,
- SilcUInt32 key_len);
+bool silc_client_add_private_message_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *cipher,
+ const char *hmac,
+ unsigned char *key,
+ SilcUInt32 key_len,
+ bool generate_key,
+ bool responder);
/****f* silcclient/SilcClientAPI/silc_client_add_private_message_key_ske
*
* SYNOPSIS
*
- * SilcBool
+ * bool
* silc_client_add_private_message_key_ske(SilcClient client,
* SilcClientConnection conn,
* SilcClientEntry client_entry,
* const char *cipher,
* const char *hmac,
- * SilcSKEKeyMaterial key);
+ * SilcSKEKeyMaterial *key);
*
* DESCRIPTION
*
* Same as silc_client_add_private_message_key but takes the key material
- * from the SKE key material structure. This structure is received if
+ * from the SKE key material structure. This structure is received if
* the application uses the silc_client_send_key_agreement to negotiate
- * the key material. The `cipher' and `hmac' SHOULD be provided as it is
+ * the key material. The `cipher' and `hmac' SHOULD be provided as it is
* negotiated also in the SKE protocol.
*
***/
-SilcBool silc_client_add_private_message_key_ske(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *cipher,
- const char *hmac,
- SilcSKEKeyMaterial key);
+bool silc_client_add_private_message_key_ske(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *cipher,
+ const char *hmac,
+ SilcSKEKeyMaterial *key,
+ bool responder);
/****f* silcclient/SilcClientAPI/silc_client_del_private_message_key
*
* SYNOPSIS
*
- * SilcBool silc_client_del_private_message_key(SilcClient client,
+ * bool silc_client_del_private_message_key(SilcClient client,
* SilcClientConnection conn,
* SilcClientEntry client_entry);
*
* client. Returns FALSE on error, TRUE otherwise.
*
***/
-SilcBool silc_client_del_private_message_key(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry);
+bool silc_client_del_private_message_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry);
/****f* silcclient/SilcClientAPI/silc_client_list_private_message_keys
*
SilcClientConnection conn,
SilcUInt32 *key_count);
+/****f* silcclient/SilcClientAPI/silc_client_send_private_message_key_request
+ *
+ * SYNOPSIS
+ *
+ * bool
+ * silc_client_send_private_message_key_request(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientEntry client_entry);
+ *
+ * DESCRIPTION
+ *
+ * This function can be used to send an private message key indicator
+ * request to the remote client indicated by 'client_entry'. This can
+ * be used when setting a static or pre-shared private message key.
+ * The sender of this packet is the initiator and must set the 'responder'
+ * argument in silc_client_add_private_message_key function to FALSE.
+ * The receiver of this indicator request must set it to TRUE, if the
+ * receiver decides to set a private message key. By using this
+ * function applications may automate initiator/responder setting in
+ * private message key functions, without asking from user which one is
+ * the initiator and which one is responder.
+ *
+ * NOTES
+ *
+ * The sender of this packet must set the private message key for
+ * 'client_entry' before calling this function. The 'responder'
+ * argument MUST be set to FALSE when setting the key.
+ *
+ ***/
+bool
+silc_client_send_private_message_key_request(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry);
+
/****f* silcclient/SilcClientAPI/silc_client_free_private_message_keys
*
* SYNOPSIS
SilcUInt32 key_count);
-/* Channel private key management */
+/* Channel private key management (client_channel.c,
+ SilcChannelPrivateKey is defined in idlist.h) */
/****f* silcclient/SilcClientAPI/silc_client_add_channel_private_key
*
* SYNOPSIS
*
- * SilcBool silc_client_add_channel_private_key(SilcClient client,
+ * bool silc_client_add_channel_private_key(SilcClient client,
* SilcClientConnection conn,
* SilcChannelEntry channel,
* const char *name,
* as channel private key. However, this API allows it.
*
***/
-SilcBool silc_client_add_channel_private_key(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- const char *name,
- char *cipher,
- char *hmac,
- unsigned char *key,
- SilcUInt32 key_len,
- SilcChannelPrivateKey *ret_key);
+bool silc_client_add_channel_private_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ const char *name,
+ char *cipher,
+ char *hmac,
+ unsigned char *key,
+ SilcUInt32 key_len,
+ SilcChannelPrivateKey *ret_key);
/****f* silcclient/SilcClientAPI/silc_client_del_channel_private_keys
*
* SYNOPSIS
*
- * SilcBool silc_client_del_channel_private_keys(SilcClient client,
+ * bool silc_client_del_channel_private_keys(SilcClient client,
* SilcClientConnection conn,
* SilcChannelEntry channel);
*
* on error, TRUE otherwise.
*
***/
-SilcBool silc_client_del_channel_private_keys(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel);
+bool silc_client_del_channel_private_keys(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel);
/****f* silcclient/SilcClientAPI/silc_client_del_channel_private_key
*
* SYNOPSIS
*
- * SilcBool silc_client_del_channel_private_key(SilcClient client,
+ * bool silc_client_del_channel_private_key(SilcClient client,
* SilcClientConnection conn,
* SilcChannelEntry channel,
* SilcChannelPrivateKey key);
* on error, TRUE otherwise.
*
***/
-SilcBool silc_client_del_channel_private_key(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcChannelPrivateKey key);
+bool silc_client_del_channel_private_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcChannelPrivateKey key);
/****f* silcclient/SilcClientAPI/silc_client_list_channel_private_keys
*
* SYNOPSIS
*
- * SilcDList
+ * SilcChannelPrivateKey *
* silc_client_list_channel_private_keys(SilcClient client,
* SilcClientConnection conn,
- * SilcChannelEntry channel);
+ * SilcChannelEntry channel,
+ * SilcUInt32 *key_count);
+ *
+ * DESCRIPTION
+ *
+ * Returns array (pointers) of private keys associated to the `channel'.
+ * The caller must free the array by calling the function
+ * silc_client_free_channel_private_keys. The pointers in the array may be
+ * used to delete the specific key by giving the pointer as argument to the
+ * function silc_client_del_channel_private_key.
+ *
+ ***/
+SilcChannelPrivateKey *
+silc_client_list_channel_private_keys(SilcClient client,
+ SilcClientConnection conn,
+ SilcChannelEntry channel,
+ SilcUInt32 *key_count);
+
+/****f* silcclient/SilcClientAPI/silc_client_free_channel_private_keys
+ *
+ * SYNOPSIS
+ *
+ * void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
+ * SilcUInt32 key_count);
*
* DESCRIPTION
*
- * Returns list of private keys associated to the `channel'. The caller
- * must free the returned list with silc_dlist_uninit. The pointers in
- * the list may be used to delete the specific key by giving the pointer
- * as argument to the function silc_client_del_channel_private_key. Each
- * entry in the list is SilcChannelPrivateKey.
+ * Frees the SilcChannelPrivateKey array.
*
***/
-SilcDList silc_client_list_channel_private_keys(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel);
+void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
+ SilcUInt32 key_count);
/****f* silcclient/SilcClientAPI/silc_client_current_channel_private_key
*
SilcChannelPrivateKey key);
-/* Key Agreement routines */
+/* Key Agreement routines (client_keyagr.c) */
/****f* silcclient/SilcClientAPI/silc_client_send_key_agreement
*
* void silc_client_send_key_agreement(SilcClient client,
* SilcClientConnection conn,
* SilcClientEntry client_entry,
- * SilcClientConnectionParams *params,
- * SilcPublicKey public_key,
- * SilcPrivateKey private_key,
+ * char *hostname,
+ * int port,
+ * SilcUInt32 timeout_secs,
* SilcKeyAgreementCallback completion,
* void *context);
*
* DESCRIPTION
*
* Sends key agreement request to the remote client indicated by the
- * `client_entry'.
- *
- * If `params' is non-NULL and it has the `local_ip' and `local_port' set
- * the caller will provide the connection endpoint for the key agreement
- * connection. The `bind_ip' can be used to bind to that IP instead of
- * `local_ip'. If the `udp' is set to TRUE the connection will be UDP
- * instead of TCP. Caller may also set the `repository', `verify_notfound'
- * and `timeout_secs' fields in `params'. Other fields are ignored.
- * If `params' is NULL, then the `client_entry' is expected to provide
- * the connection endpoint for us. It is recommended the `timeout_secs'
- * is specified in case the remote client does not reply anything to
- * the request.
- *
- * The `public_key' and `private_key' is our identity in the key agreement.
- *
- * In case we do not provide the connection endpoint, we will receive
- * the `key_agreement' client operation when the remote send its own
- * key agreement request packet. We may then there start the key
- * agreement with silc_client_perform_key_agreement. If we provided the
- * the connection endpoint, the client operation will not be called.
- *
- * There can be only one active key agreement for `client_entry'. Old
- * key agreement may be aborted by calling silc_client_abort_key_agreement.
+ * `client_entry'. If the caller provides the `hostname' and the `port'
+ * arguments then the library will bind the client to that hostname and
+ * that port for the key agreement protocol. It also sends the `hostname'
+ * and the `port' in the key agreement packet to the remote client. This
+ * would indicate that the remote client may initiate the key agreement
+ * protocol to the `hostname' on the `port'. If port is zero then the
+ * bound port is undefined (the operating system defines it).
+ *
+ * If the `hostname' and `port' is not provided then empty key agreement
+ * packet is sent to the remote client. The remote client may reply with
+ * the same packet including its hostname and port. If the library receives
+ * the reply from the remote client the `key_agreement' client operation
+ * callback will be called to verify whether the user wants to perform the
+ * key agreement or not.
*
- * EXAMPLE
+ * NOTES
+ *
+ * NOTE: If the application provided the `hostname' and the `port' and the
+ * remote side initiates the key agreement protocol it is not verified
+ * from the user anymore whether the protocol should be executed or not.
+ * By setting the `hostname' and `port' the user gives permission to
+ * perform the protocol (we are responder in this case).
*
- * // Send key agreement request (we don't provide connection endpoint)
- * silc_client_send_key_agreement(client, conn, remote_client,
- * NULL, public_key, private_key,
- * my_keyagr_completion, my_context);
+ * NOTE: If the remote side decides not to initiate the key agreement
+ * or decides not to reply with the key agreement packet then we cannot
+ * perform the key agreement at all. If the key agreement protocol is
+ * performed the `completion' callback with the `context' will be called.
+ * If remote side decides to ignore the request the `completion' will be
+ * called after the specified timeout, `timeout_secs'.
*
- * // Another example where we provide connection endpoint (TCP).
- * SilcClientConnectionParams params;
- * memset(¶ms, 0, sizeof(params));
- * params.local_ip = local_ip;
- * params.local_port = local_port;
- * params.timeout_secs = 60;
- * silc_client_send_key_agreement(client, conn, remote_client,
- * ¶ms, public_key, private_key,
- * my_keyagr_completion, my_context);
+ * NOTE: If the `hostname' and the `port' was not provided the `completion'
+ * will not be called at all since this does nothing more than sending
+ * a packet to the remote host.
+ *
+ * NOTE: There can be only one active key agreement for one client entry.
+ * Before setting new one, the old one must be finished (it is finished
+ * after calling the completion callback) or the function
+ * silc_client_abort_key_agreement must be called.
*
***/
void silc_client_send_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
+ const char *hostname,
+ const char *bindhost,
+ int port,
+ SilcUInt32 timeout_secs,
SilcKeyAgreementCallback completion,
void *context);
* silc_client_perform_key_agreement(SilcClient client,
* SilcClientConnection conn,
* SilcClientEntry client_entry,
- * SilcClientConnectionParams *params,
- * SilcPublicKey public_key,
- * SilcPrivateKey private_key,
- * char *hostname, int port,
+ * char *hostname,
+ * int port,
* SilcKeyAgreementCallback completion,
* void *context);
*
* DESCRIPTION
*
- * Performs the key agreement protocol. Application may use this to
- * initiate the key agreement protocol. Usually this is called after
- * receiving the `key_agreement' client operation.
+ * Performs the actual key agreement protocol. Application may use this
+ * to initiate the key agreement protocol. This can be called for example
+ * after the application has received the `key_agreement' client operation,
+ * and did not return TRUE from it.
*
* The `hostname' is the remote hostname (or IP address) and the `port'
- * is the remote port. The `completion' callback with the `context' will
+ * is the remote port. The `completion' callback with the `context' will
* be called after the key agreement protocol.
*
- * The `params' is connection parameters and it may be used to define
- * the key agreement connection related parameters. It may be NULL.
+ * NOTES
+ *
+ * NOTE: If the application returns TRUE in the `key_agreement' client
+ * operation the library will automatically start the key agreement. In this
+ * case the application must not call this function. However, application
+ * may choose to just ignore the `key_agreement' client operation (and
+ * merely just print information about it on the screen) and call this
+ * function when the user whishes to do so (by, for example, giving some
+ * specific command). Thus, the API provides both, automatic and manual
+ * initiation of the key agreement. Calling this function is the manual
+ * initiation and returning TRUE in the `key_agreement' client operation
+ * is the automatic initiation.
*
***/
void silc_client_perform_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- char *hostname, int port,
+ char *hostname,
+ int port,
SilcKeyAgreementCallback completion,
void *context);
-/****f* silcclient/SilcClientAPI/silc_client_perform_key_agreement_stream
+/****f* silcclient/SilcClientAPI/silc_client_perform_key_agreement_fd
*
* SYNOPSIS
*
* void
- * silc_client_perform_key_agreement_stream(
- * SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry,
- * SilcClientConnectionParams *params,
- * SilcPublicKey public_key,
- * SilcPrivateKey private_key,
- * SilcStream stream,
- * SilcKeyAgreementCallback completion,
- * void *context);
+ * silc_client_perform_key_agreement_fd(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientEntry client_entry,
+ * int sock,
+ * char *hostname,
+ * SilcKeyAgreementCallback completion,
+ * void *context);
*
* DESCRIPTION
*
- * Same as silc_client_perform_key_agreement but the caller has created
- * the connection. The `stream' is the created connection.
+ * Same as above but application has created already the connection to
+ * the remote host. The `sock' is the socket to the remote connection.
+ * Application can use this function if it does not want the client library
+ * to create the connection.
*
***/
-void
-silc_client_perform_key_agreement_stream(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcStream stream,
- SilcKeyAgreementCallback completion,
- void *context);
+void silc_client_perform_key_agreement_fd(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ int sock,
+ char *hostname,
+ SilcKeyAgreementCallback completion,
+ void *context);
/****f* silcclient/SilcClientAPI/silc_client_abort_key_agreement
*
*
* SYNOPSIS
*
- * SilcBool silc_client_set_away_message(SilcClient client,
- * SilcClientConnection conn,
- * char *message);
+ * void silc_client_set_away_message(SilcClient client,
+ * SilcClientConnection conn,
+ * char *message);
*
* DESCRIPTION
*
* automatically back to the the client who send private message. If
* away message is already set this replaces the old message with the
* new one. If `message' is NULL the old away message is removed.
- * The sender may freely free the memory of the `message'. Returns
- * FALSE on error.
+ * The sender may freely free the memory of the `message'.
*
***/
-SilcBool silc_client_set_away_message(SilcClient client,
- SilcClientConnection conn,
- char *message);
+void silc_client_set_away_message(SilcClient client,
+ SilcClientConnection conn,
+ char *message);
-/****d* silcclient/SilcClientAPI/SilcClientMonitorStatus
+/****f* silcclient/SilcClientAPI/SilcConnectionAuthRequest
*
- * NAME
+ * SYNOPSIS
*
- * typedef enum { ... } SilcClientMonitorStatus;
+ * typedef void (*SilcConnectionAuthRequest)(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcAuthMethod auth_meth,
+ * void *context);
*
* DESCRIPTION
*
- * File transmission session status types. These will indicate
- * the status of the file transmission session.
+ * Connection authentication method request callback. This is called
+ * by the client library after it has received the authentication method
+ * that the application requested by calling the function
+ * silc_client_request_authentication_method.
+ *
+ ***/
+typedef void (*SilcConnectionAuthRequest)(SilcClient client,
+ SilcClientConnection conn,
+ SilcAuthMethod auth_meth,
+ void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_request_authentication_method
*
- * The SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT is called when session
- * is key exchange phase.
+ * SYNOPSIS
+ *
+ * void
+ * silc_client_request_authentication_method(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcConnectionAuthRequest
+ * callback,
+ * void *context);
*
- * The SILC_CLIENT_FILE_MONITOR_SEND is called when data is being sent
- * to remote client.
+ * DESCRIPTION
+ *
+ * This function can be used to request the current authentication method
+ * from the server. This may be called when connecting to the server
+ * and the client library requests the authentication data from the
+ * application. If the application does not know the current authentication
+ * method it can request it from the server using this function.
+ * The `callback' with `context' will be called after the server has
+ * replied back with the current authentication method.
+ *
+ ***/
+void
+silc_client_request_authentication_method(SilcClient client,
+ SilcClientConnection conn,
+ SilcConnectionAuthRequest callback,
+ void *context);
+
+/****d* silcclient/SilcClientAPI/SilcClientMonitorStatus
*
- * The SILC_CLIENT_FILE_MONITOR_RECEIVE is called when data is being
- * recieved from remote client.
+ * NAME
*
- * The SILC_CLIENT_FILE_MONITOR_CLOSED will be called when the user
- * issues silc_client_file_close. If needed, it may be ignored in the
- * monitor callback.
+ * typedef enum { ... } SilcClientMonitorStatus;
*
- * The SILC_CLIENT_FILE_MONITOR_DISCONNECT will be called if remote
- * disconnects the session connection. The silc_client_file_close must
- * be called when this status is received. The session is over when
- * this is received.
+ * DESCRIPTION
*
- * The SILC_CLIENLT_FILE_MONITOR_ERROR is called in case some error
- * occured. The SilcClientFileError will indicate more detailed error
- * condition. The silc_client_file_close must be called when this status
- * is received. The session is over when this is received.
+ * File transmission session status types. These will indicate
+ * the status of the file transmission session.
*
* SOURCE
*/
SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT, /* In key agreemenet phase */
SILC_CLIENT_FILE_MONITOR_SEND, /* Sending file */
SILC_CLIENT_FILE_MONITOR_RECEIVE, /* Receiving file */
- SILC_CLIENT_FILE_MONITOR_GET, /* Unsupported */
- SILC_CLIENT_FILE_MONITOR_PUT, /* Unsupported */
+ SILC_CLIENT_FILE_MONITOR_GET,
+ SILC_CLIENT_FILE_MONITOR_PUT,
SILC_CLIENT_FILE_MONITOR_CLOSED, /* Session closed */
- SILC_CLIENT_FILE_MONITOR_DISCONNECT, /* Session disconnected */
SILC_CLIENT_FILE_MONITOR_ERROR, /* Error during session */
} SilcClientMonitorStatus;
/***/
*/
typedef enum {
SILC_CLIENT_FILE_OK,
- SILC_CLIENT_FILE_ERROR, /* Generic error */
- SILC_CLIENT_FILE_UNKNOWN_SESSION, /* Unknown session ID */
- SILC_CLIENT_FILE_ALREADY_STARTED, /* Session already started */
- SILC_CLIENT_FILE_NO_SUCH_FILE, /* No such file */
- SILC_CLIENT_FILE_PERMISSION_DENIED, /* Permission denied */
- SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED, /* Key exchange failed */
- SILC_CLIENT_FILE_CONNECT_FAILED, /* Error during connecting */
- SILC_CLIENT_FILE_TIMEOUT, /* Connecting timedout */
- SILC_CLIENT_FILE_NO_MEMORY, /* System out of memory */
+ SILC_CLIENT_FILE_ERROR,
+ SILC_CLIENT_FILE_UNKNOWN_SESSION,
+ SILC_CLIENT_FILE_ALREADY_STARTED,
+ SILC_CLIENT_FILE_NO_SUCH_FILE,
+ SILC_CLIENT_FILE_PERMISSION_DENIED,
+ SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED,
} SilcClientFileError;
/***/
* currently transmitted amount of total `filesize'. The `client_entry'
* indicates the remote client, and the transmission session ID is the
* `session_id'. The filename being transmitted is indicated by the
- * `filepath'. The `conn' is NULL if the connection to remote client
- * does not exist yet.
+ * `filepath'.
*
***/
typedef void (*SilcClientFileMonitor)(SilcClient client,
* void *monitor_context,
* const char *local_ip,
* SilcUInt32 local_port,
- * SilcBool do_not_bind,
+ * bool do_not_bind,
* SilcClientEntry client_entry,
* const char *filepath);
* SilcUInt32 *session_id);
SilcClientFileError
silc_client_file_send(SilcClient client,
SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
SilcClientFileMonitor monitor,
void *monitor_context,
+ const char *local_ip,
+ SilcUInt32 local_port,
+ bool do_not_bind,
+ SilcClientEntry client_entry,
const char *filepath,
SilcUInt32 *session_id);
SilcClientFileError
silc_client_file_receive(SilcClient client,
SilcClientConnection conn,
- SilcClientConnectionParams *params,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
SilcClientFileMonitor monitor,
void *monitor_context,
const char *path,
*
* SYNOPSIS
*
- * SilcBool silc_client_attribute_del(SilcClient client,
+ * bool silc_client_attribute_del(SilcClient client,
* SilcClientConnection conn,
* SilcAttribute attribute,
* SilcAttributePayload attr);
* This function Returns TRUE if the attribute was found and deleted.
*
***/
-SilcBool silc_client_attribute_del(SilcClient client,
- SilcClientConnection conn,
- SilcAttribute attribute,
- SilcAttributePayload attr);
+bool silc_client_attribute_del(SilcClient client,
+ SilcClientConnection conn,
+ SilcAttribute attribute,
+ SilcAttributePayload attr);
/****f* silcclient/SilcClientAPI/silc_client_attributes_get
*
***/
SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...);
-/****f* silcclient/SilcClientAPI/silc_client_nickname_format
+/* Low level packet sending functions */
+
+/****f* silcclient/SilcClientAPI/silc_client_send_packet
*
* SYNOPSIS
*
- * SilcClientEntry
- * silc_client_nickname_format(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry,
- * SilcBool priority);
+ * bool silc_client_send_packet(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcPacketType type,
+ * const unsigned char *data,
+ * SilcUInt32 data_len);
*
* DESCRIPTION
*
- * Formats the nickname of `client_entry' according to the nickname
- * formatting rules set in SilcClientParams. If the `priority' is TRUE
- * then the `client_entry' will always get the unformatted nickname.
- * If FALSE and there are more than one same nicknames in the client
- * the nickname will be formatted.
- *
- * This returns NULL on error. Otherwise, the client entry that was
- * formatted is returned. If `priority' is FALSE this always returns
- * the `client_entry'. If it is TRUE, this may return the client entry
- * that was formatted after giving the `client_entry' the unformatted
- * nickname.
- *
- * Usually application does not need to call this function, as the library
- * automatically formats nicknames. However, if application wants to
- * for example force the `client_entry' to always have the unformatted
- * nickname it may call this function to do so.
+ * This routine can be used by application to send packets directly
+ * to a connection indicated by `conn'. Usually application does not
+ * need this routine since the Client Library handles the packet
+ * sending. The `type' indicates the packet type. If `data' is
+ * NULL then empty packet is sent. This returns FALSE if packet cannot
+ * be sent.
*
***/
-SilcClientEntry silc_client_nickname_format(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- SilcBool priority);
+bool silc_client_send_packet(SilcClient client,
+ SilcClientConnection conn,
+ SilcPacketType type,
+ const unsigned char *data,
+ SilcUInt32 data_len);
+
+#include "command.h"
+#include "command_reply.h"
+#include "idlist.h"
+#include "protocol.h"
#ifdef __cplusplus
}
+++ /dev/null
-/*
-
- silcclient_entry.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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* silcclient/Client Library Interface
- *
- * DESCRIPTION
- *
- * This header file includes the SilcClientEntry, SilcChannelEntry and
- * SilcServer entry structures and various routines to search, resolve and
- * handle these structures.
- *
- * All entries (SilcClientEntry, SilcChannelEntry and SilcServerEntry) are
- * reference counted. If application wishes to save an entry pointer it must
- * always first acquire a reference. The reference must be released once the
- * entry is not needed anymore. If application wants to read any data from
- * the entry structure it must first lock the entry. This protects access to
- * the entries in multithreaded environment. If threads are not used, locking
- * the entries is not needed. They however still must be referenced even
- * when threads are not used.
- *
- ***/
-
-#ifndef SILCCLIENT_ENTRY_H
-#define SILCCLIENT_ENTRY_H
-
-#ifndef SILCCLIENT_H
-#error "Do not include this header directly, include silcclient.h instead"
-#endif
-
-/****s* silcclient/SilcClientAPI/SilcClientEntry
- *
- * NAME
- *
- * typedef struct SilcClientEntryStruct { ... } *SilcClientEntry;
- *
- * DESCRIPTION
- *
- * This structure represents a client or a user in the SILC network.
- * The local user has this structure also and it can be accessed from
- * SilcClientConnection structure. All other users in the SILC network
- * that are accessed using the Client Library routines will have their
- * own SilcClientEntry structure. For example, when finding users by
- * their nickname the Client Library returns this structure back to
- * the application. All strings in the structure are UTF-8 encoded.
- *
- * Application may store its own pointer into the context pointer in
- * this structure.
- *
- * NOTES
- *
- * If application wants to store nickname or any of the other strings
- * it should always duplicated them.
- *
- * None of the string arrays are set if the first character is '\0'.
- * All string arrays are always zero ('\0') terminated.
- *
- * If application stores the SilcClientEntry it must always take
- * a reference of it by calling silc_client_ref_client function. The
- * reference must be released after it is not needed anymore by calling
- * silc_client_unref_client function.
- *
- * SOURCE
- */
-struct SilcClientEntryStruct {
- char nickname[128 + 1]; /* Nickname */
- char username[128 + 1]; /* Username */
- char hostname[256 + 1]; /* Hostname */
- char server [256 + 1]; /* SILC server name */
- char *realname; /* Realname (userinfo) */
- char *nickname_normalized; /* Normalized nickname */
-
- SilcClientID id; /* The Client ID */
- SilcUInt32 mode; /* User mode in SILC, see SilcUserMode */
- SilcPublicKey public_key; /* User's public key, may be NULL */
- SilcHashTable channels; /* Channels client has joined */
- SilcDList attrs; /* Requested Attributes (maybe NULL) */
- unsigned char fingerprint[20]; /* SHA-1 fingerprint of the public key */
-
- void *context; /* Application specific context */
- SilcClientEntryInternal internal;
-};
-/***/
-
-/****s* silcclient/SilcClientAPI/SilcChannelEntry
- *
- * NAME
- *
- * typedef struct SilcChannelEntryStruct { ... } *SilcChannelEntry;
- *
- * DESCRIPTION
- *
- * This structure represents a channel in the SILC network. All
- * channels that the client are aware of or have joined in will be
- * represented as SilcChannelEntry. The structure includes information
- * about the channel. All strings in the structure are UTF-8 encoded.
- *
- * Application may store its own pointer into the context pointer in
- * this structure.
- *
- * NOTES
- *
- * If application stores the SilcChannelEntry it must always take
- * a reference of it by calling silc_client_ref_channel function. The
- * reference must be released after it is not needed anymore by calling
- * silc_client_unref_channel function.
- *
- * SOURCE
- */
-struct SilcChannelEntryStruct {
- char *channel_name; /* Channel name */
- char *topic; /* Current topic, may be NULL */
- SilcPublicKey founder_key; /* Founder key, may be NULL */
- SilcDList channel_pubkeys; /* Channel public keys, may be NULL */
- SilcChannelID id; /* Channel ID */
- SilcUInt32 mode; /* Channel mode, ChannelModes. */
- SilcUInt32 user_limit; /* User limit on channel */
- SilcHashTable user_list; /* Joined users. Key to hash table is
- SilcClientEntry, context is
- SilcChannelUser. */
-
- void *context; /* Application specific context */
- SilcChannelEntryInternal internal;
-};
-/***/
-
-/****s* silcclient/SilcClientAPI/SilcServerEntry
- *
- * NAME
- *
- * typedef struct SilcServerEntryStruct { ... } *SilcServerEntry;
- *
- * DESCRIPTION
- *
- * This structure represents a server in the SILC network. All servers
- * that the client is aware of and have for example resolved with
- * SILC_COMMAND_INFO command have their on SilcServerEntry structure.
- * Server's public key is present only if it has been retrieved using
- * SILC_COMMAND_GETKEY command. All strings in the structure are UTF-8
- * encoded.
- *
- * Application may store its own pointer into the context pointer in
- * this structure.
- *
- * NOTES
- *
- * If application stores the SilcServerEntry it must always take
- * a reference of it by calling silc_client_ref_server function. The
- * reference must be released after it is not needed anymore by calling
- * silc_client_unref_server function.
- *
- * SOURCE
- */
-struct SilcServerEntryStruct {
- /* General information */
- char *server_name; /* Server name */
- char *server_info; /* Server info */
- SilcServerID id; /* Server ID */
- SilcPublicKey public_key; /* Server public key, may be NULL */
-
- void *context; /* Application specific context */
- SilcServerEntryInternal internal;
-};
-/***/
-
-/* SilcClientEntry routines */
-
-/****f* silcclient/SilcClientAPI/SilcGetClientCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcGetClientCallback)(SilcClient client,
- * SilcClientConnection conn,
- * SilcStatus status,
- * SilcDList clients,
- * void *context);
- *
- * DESCRIPTION
- *
- * Callback function given to various client search functions. The
- * found entries are allocated into the `clients' list. The list must
- * not be freed by the receiver, the library will free it later. If the
- * `clients' is NULL, no such clients exist in the SILC network, and
- * the `status' will include the error. Each entry in the `clients'
- * is SilcClientEntry.
- *
- * NOTES
- *
- * If the application stores any of the SilcClientEntry pointers from
- * the `clients' list it must reference it with silc_client_ref_client
- * function.
- *
- * Application must not free the returned `clients' list.
- *
- ***/
-typedef void (*SilcGetClientCallback)(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList clients,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_lock_client
- *
- * SYNOPSIS
- *
- * void silc_client_lock_client(SilcClientEntry client_entry);
- *
- * DESCRIPTION
- *
- * Acquires lock for the client entry indicate by `client_entry'. When
- * application wants to access `client_entry' it must lock the entry
- * before reading any data from the `client_entry'. The lock must be
- * unlocked with silc_client_unlock_client.
- *
- * NOTES
- *
- * The entry must be unlocked before calling any Client Library API
- * functions where the entry is given as argument, unless otherwise stated.
- *
- * The entry should not be locked for long periods of time. For example,
- * it is not appropriate to hold the lock while waiting user interface to
- * be drawn. The appropriate way is to read the data and duplicate it if
- * necessary, unlock the entry, then draw on the user interface.
- *
- * This function is not needed if application is not multithreaded.
- *
- ***/
-void silc_client_lock_client(SilcClientEntry client_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_unlock_client
- *
- * SYNOPSIS
- *
- * void silc_client_unlock_client(SilcClientEntry client_entry);
- *
- * DESCRIPTION
- *
- * Releases the lock acquired with silc_client_lock_client.
- *
- ***/
-void silc_client_unlock_client(SilcClientEntry client_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_ref_client
- *
- * SYNOPSIS
- *
- * SilcClientEntry
- * silc_client_ref_client(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry);
- *
- * DESCRIPTION
- *
- * Takes a reference of the client entry indicated by `client_entry'
- * The reference must be released by calling silc_client_unref_client
- * after it is not needed anymore. Returns `client_entry'.
- *
- ***/
-SilcClientEntry silc_client_ref_client(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_unref_client
- *
- * SYNOPSIS
- *
- * void silc_client_unref_client(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry);
- *
- * DESCRIPTION
- *
- * Releases the client entry reference indicated by `client_entry'.
- *
- ***/
-void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_list_free
- *
- * SYNOPSIS
- *
- * void silc_client_list_free(SilcClient client,
- * SilcClientConnection conn,
- * SilcDList client_list);
- *
- * DESCRIPTION
- *
- * Free's client entry list that has been returned by various library
- * routines.
- *
- ***/
-void silc_client_list_free(SilcClient client, SilcClientConnection conn,
- SilcDList client_list);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_clients
- *
- * SYNOPSIS
- *
- * SilcUInt16 silc_client_get_clients(SilcClient client,
- * SilcClientConnection conn,
- * const char *nickname,
- * const char *server,
- * SilcGetClientCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Finds client entry or entries by the `nickname' and `server'. The
- * completion callback will be called when the client entries has been
- * found. After the server returns the client information it is cached
- * and can be accesses locally at a later time. The resolving is done
- * with IDENTIFY command. The `server' may be NULL. Returns 0 on
- * error and the command identifier used with the command otherwise.
- *
- * NOTES
- *
- * This function is always asynchronous and resolves the client
- * information from the server. Thus, if you already know the client
- * information then use the silc_client_get_client_by_id function to
- * get the client entry since this function may be very slow and should
- * be used only to initially get the client entries.
- *
- * This function resolves only the relevant information (user's nickname
- * and username). It does not resolve for example user's real name,
- * joined channel list or other information. To resolve all the details
- * use silc_client_get_clients_whois instead.
- *
- ***/
-SilcUInt16 silc_client_get_clients(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *server,
- SilcGetClientCallback completion,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_clients_whois
- *
- * SYNOPSIS
- *
- * SilcUInt16
- * silc_client_get_clients_whois(SilcClient client,
- * SilcClientConnection conn,
- * const char *nickname,
- * const char *server,
- * SilcBuffer attributes,
- * SilcGetClientCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Finds client entry or entries by the `nickname' and `server'. The
- * completion callback will be called when the client entries has been
- * found. After the server returns the client information it is cached
- * and can be accesses locally at a later time. The resolving is done
- * with WHOIS command. The `server' may be NULL. Returns 0 on error,
- * and the command identifier used with the command otherwise.
- *
- * If the `attributes' is non-NULL then the buffer includes Requested
- * Attributes which can be used to fetch very detailed information
- * about the user. If it is NULL then only normal WHOIS query is
- * made (for more information about attributes see SilcAttribute).
- * Caller may create the `attributes' with silc_client_attributes_request
- * function.
- *
- * NOTES
- *
- * The resolving is done with WHOIS command. For this reason this
- * command may take a long time because it resolves detailed user
- * information.
- *
- ***/
-SilcUInt16 silc_client_get_clients_whois(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *server,
- SilcBuffer attributes,
- SilcGetClientCallback completion,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_clients_local
- *
- * SYNOPSIS
- *
- * SilcDList silc_client_get_clients_local(SilcClient client,
- * SilcClientConnection conn,
- * const char *nickname,
- * const char *format);
- *
- * DESCRIPTION
- *
- * Same as silc_client_get_clients function but does not resolve anything
- * from the server. This checks local cache and returns all matching
- * clients from the local cache. If none was found this returns NULL.
- * The `nickname' is the real nickname of the client, and the `format'
- * is the formatted nickname to find exact match from multiple found
- * entries. The format must be same as given in the SilcClientParams
- * structure to the client library. If the `format' is NULL all found
- * clients by `nickname' are returned. The caller must free the
- * returned list by silc_client_list_free function.
- *
- * NOTES
- *
- * If the application stores any of the SilcClientEntry pointers from
- * the returned list it must reference it with silc_client_ref_client
- * function.
- *
- * Application must free the returned list with silc_client_list_free
- * function.
- *
- ***/
-SilcDList silc_client_get_clients_local(SilcClient client,
- SilcClientConnection conn,
- const char *nickname,
- const char *format);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_clients_by_channel
- *
- * SYNOPSIS
- *
- * void silc_client_get_clients_by_channel(SilcClient client,
- * SilcClientConnection conn,
- * SilcChannelEntry channel,
- * SilcGetClientCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Gets client entries by the channel indicated by `channel'. Thus,
- * it resovles the users currently on that channel. If all users are
- * already resolved this returns the users from the channel. If the
- * users are resolved only partially this resolves the complete user
- * information. If no users are resolved on this channel at all, this
- * calls USERS command to resolve all users on the channel. The `completion'
- * will be called after the entries are available. When server returns
- * the client information it will be cached and can be accessed locally
- * at a later time.
- *
- * This function can be used for example in SILC_COMMAND_JOIN command
- * reply handling in application to resolve users on that channel. It
- * also can be used after calling silc_client_get_channel_resolve to
- * resolve users on that channel.
- *
- * NOTES
- *
- * The resolving is done with WHOIS command. For this reason this
- * command may take a long time because it resolves detailed user
- * information.
- *
- ***/
-void silc_client_get_clients_by_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel,
- SilcGetClientCallback completion,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_client_by_id
- *
- * SYNOPSIS
- *
- * SilcClientEntry silc_client_get_client_by_id(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientID *client_id);
- *
- * DESCRIPTION
- *
- * Find client entry by the client's ID. Returns the entry or NULL
- * if the entry was not found. This checks the local cache and does
- * not resolve anything from server.
- *
- * NOTES
- *
- * The returned SilcClientEntry has been referenced by the library and
- * the caller must call silc_client_unref_client after the entry is not
- * needed anymore.
- *
- ***/
-SilcClientEntry silc_client_get_client_by_id(SilcClient client,
- SilcClientConnection conn,
- SilcClientID *client_id);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_client_by_id_resolve
- *
- * SYNOPSIS
- *
- * SilcUInt16
- * silc_client_get_client_by_id_resolve(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientID *client_id,
- * SilcBuffer attributes,
- * SilcGetClientCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Same as silc_client_get_client_by_id but will always resolve the
- * information from the server. Use this only if you know that you
- * do not have the entry and the only thing you know about the client
- * is its ID. When server returns the client information it will be
- * cache and can be accessed locally at a later time. The resolving
- * is done by sending WHOIS command.
- *
- * Returns command identifier for the resolving. It can be used to attach
- * a pending command to it, if needed. Returns 0 on error.
- *
- * If the `attributes' is non-NULL then the buffer includes Requested
- * Attributes which can be used to fetch very detailed information
- * about the user. If it is NULL then only normal WHOIS query is
- * made (for more information about attributes see SilcAttribute).
- * Caller may create the `attributes' with silc_client_attributes_request
- * function.
- *
- ***/
-SilcUInt16
-silc_client_get_client_by_id_resolve(SilcClient client,
- SilcClientConnection conn,
- SilcClientID *client_id,
- SilcBuffer attributes,
- SilcGetClientCallback completion,
- void *context);
-
-/* SilcChannelEntry routines */
-
-/****f* silcclient/SilcClientAPI/SilcGetChannelCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcGetChannelCallback)(SilcClient client,
- * SilcClientConnection conn,
- * SilcStatus status,
- * SilcDList channels,
- * void *context);
- *
- * DESCRIPTION
- *
- * Callback function given to various channel resolving functions.
- * The found entries are included in the `channels' list and each entry
- * in the list is SilcChannelEntry. If `channels' is NULL then no such
- * channel exist in the network and the `status' will indicate the error.
- *
- * NOTES
- *
- * If the application stores any of the SilcChannelEntry pointers from
- * the `channels' list it must reference it with silc_client_ref_channel
- * function.
- *
- * Application must not free the returned `channels' list.
- *
- ***/
-typedef void (*SilcGetChannelCallback)(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList channels,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_lock_channel
- *
- * SYNOPSIS
- *
- * void silc_client_lock_channel(SilcChannelEntry channel_entry);
- *
- * DESCRIPTION
- *
- * Acquires lock for the channel entry indicate by `channel_entry'. When
- * application wants to access `channel_entry' it must lock the entry
- * before reading any data from the `channel_entry'. The lock must be
- * unlocked with silc_client_unlock_channel.
- *
- * NOTES
- *
- * The entry must be unlocked before calling any Client Library API
- * functions where the entry is given as argument, unless otherwise stated.
- *
- * The entry should not be locked for long periods of time. For example,
- * it is not appropriate to hold the lock while waiting user interface to
- * be drawn. The appropriate way is to read the data and duplicate it if
- * necessary, unlock the entry, then draw on the user interface.
- *
- * This function is not needed if application is not multithreaded.
- *
- ***/
-void silc_client_lock_channel(SilcChannelEntry channel_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_unlock_channel
- *
- * SYNOPSIS
- *
- * void silc_client_unlock_channel(SilcChannelEntry channel_entry);
- *
- * DESCRIPTION
- *
- * Releases the lock acquired with silc_client_lock_channel.
- *
- ***/
-void silc_client_unlock_channel(SilcChannelEntry channel_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_ref_channel
- *
- * SYNOPSIS
- *
- * SilcChannelEntry
- * silc_client_ref_channel(SilcClient client,
- * SilcClientConnection conn,
- * SilcChannelEntry channel_entry);
- *
- * DESCRIPTION
- *
- * Takes a reference of the channel entry indicated by `channel_entry'
- * The reference must be released by calling silc_client_unref_channel
- * after it is not needed anymore. Returns `channel_entry'.
- *
- ***/
-SilcChannelEntry silc_client_ref_channel(SilcClient client,
- SilcClientConnection conn,
- SilcChannelEntry channel_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_unref_channel
- *
- * SYNOPSIS
- *
- * void silc_client_unref_channel(SilcClient client,
- * SilcClientConnection conn,
- * SilcChannelEntry channel_entry);
- *
- * DESCRIPTION
- *
- * Releases the channel entry reference indicated by `channel_entry'.
- *
- ***/
-void silc_client_unref_channel(SilcClient client, SilcClientConnection conn,
- SilcChannelEntry channel_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_list_free_channel
- *
- * SYNOPSIS
- *
- * void silc_client_list_free_channel(SilcClient client,
- * SilcClientConnection conn,
- * SilcDList channel_list);
- *
- * DESCRIPTION
- *
- * Free's channel entry list that has been returned by various library
- * routines.
- *
- ***/
-void silc_client_list_free_channels(SilcClient client,
- SilcClientConnection conn,
- SilcDList channel_list);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_channel
- *
- * SYNOPSIS
- *
- * SilcChannelEntry silc_client_get_channel(SilcClient client,
- * SilcClientConnection conn,
- * char *channel_name);
- *
- * DESCRIPTION
- *
- * Finds entry for channel by the channel name. Returns the entry or NULL
- * if the entry was not found. It is found only if the client is joined
- * to the channel. Use silc_client_get_channel_resolve or
- * silc_client_get_channel_by_id_resolve to resolve channel that client
- * is not joined.
- *
- * NOTES
- *
- * The returned SilcChannelEntry has been referenced by the library and
- * the caller must call silc_client_unref_channel after the entry is not
- * needed anymore.
- *
- ***/
-SilcChannelEntry silc_client_get_channel(SilcClient client,
- SilcClientConnection conn,
- char *channel_name);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_channel_resolve
- *
- * SYNOPSIS
- *
- * void silc_client_get_channel_resolve(SilcClient client,
- * SilcClientConnection conn,
- * char *channel_name,
- * SilcGetChannelCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Resolves entry for channel by the channel name from the server.
- * The resolving is done with IDENTIFY command. Note that users on
- * the channel are not resolved at the same time. Use for example
- * silc_client_get_clients_by_channel to resolve all users on a channel.
- *
- ***/
-void silc_client_get_channel_resolve(SilcClient client,
- SilcClientConnection conn,
- char *channel_name,
- SilcGetChannelCallback completion,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_channel_by_id
- *
- * SYNOPSIS
- *
- * SilcChannelEntry
- * silc_client_get_channel_by_id(SilcClient client,
- * SilcClientConnection conn,
- * SilcChannelID *channel_id);
- *
- * DESCRIPTION
- *
- * Finds channel entry by the channel ID. Returns the entry or NULL
- * if the entry was not found. This checks the local cache and does
- * not resolve anything from server.
- *
- * NOTES
- *
- * The returned SilcChannelEntry has been referenced by the library and
- * the caller must call silc_client_unref_channel after the entry is not
- * needed anymore.
- *
- ***/
-SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
- SilcClientConnection conn,
- SilcChannelID *channel_id);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_channel_by_id_resolve
- *
- * SYNOPSIS
- *
- * SilcUInt16
- * silc_client_get_channel_by_id_resolve(SilcClient client,
- * SilcClientConnection conn,
- * SilcChannelID *channel_id,
- * SilcGetClientCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Resolves the channel information (its name mainly) from the server
- * by the `channel_id'. Use this only if you know that you do not have
- * the entry cached locally. The resolving is done with IDENTIFY command.
- *
- * Returns command identifier for the resolving. It can be used to attach
- * a pending command to it, if needed. Returns 0 on error.
- *
- * Note that users on the channel are not resolved at the same time.
- * Use for example silc_client_get_clients_by_channel to resolve all
- * users on a channel.
- *
- ***/
-SilcUInt16
-silc_client_get_channel_by_id_resolve(SilcClient client,
- SilcClientConnection conn,
- SilcChannelID *channel_id,
- SilcGetChannelCallback completion,
- void *context);
-
-/* SilcServerEntry routines */
-
-/****f* silcclient/SilcClientAPI/SilcGetServerCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcGetServerCallback)(SilcClient client,
- * SilcClientConnection conn,
- * SilcStatus status,
- * SilcDList servers,
- * void *context);
- *
- * DESCRIPTION
- *
- * Callback function given to various server resolving functions.
- * The found entries are included in the `servers' list and each entry
- * in the list is SilcServerEntry. If `server' is NULL then no such
- * server exist in the network and the `status' will indicate the error.
- *
- * NOTES
- *
- * If the application stores any of the SilcServerEntry pointers from
- * the `server' list it must reference it with silc_client_ref_server
- * function.
- *
- * Application must not free the returned `server' list.
- *
- ***/
-typedef void (*SilcGetServerCallback)(SilcClient client,
- SilcClientConnection conn,
- SilcStatus status,
- SilcDList servers,
- void *context);
-
-/****f* silcclient/SilcClientAPI/silc_client_lock_server
- *
- * SYNOPSIS
- *
- * void silc_client_lock_server(SilcServerEntry server_entry);
- *
- * DESCRIPTION
- *
- * Acquires lock for the server entry indicate by `server_entry'. When
- * application wants to access `server_entry' it must lock the entry
- * before reading any data from the `server_entry'. The lock must be
- * unlocked with silc_client_unlock_server.
- *
- * NOTES
- *
- * The entry must be unlocked before calling any Client Library API
- * functions where the entry is given as argument, unless otherwise stated.
- *
- * The entry should not be locked for long periods of time. For example,
- * it is not appropriate to hold the lock while waiting user interface to
- * be drawn. The appropriate way is to read the data and duplicate it if
- * necessary, unlock the entry, then draw on the user interface.
- *
- * This function is not needed if application is not multithreaded.
- *
- ***/
-void silc_client_lock_server(SilcServerEntry server_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_unlock_server
- *
- * SYNOPSIS
- *
- * void silc_client_unlock_server(SilcServerEntry server_entry);
- *
- * DESCRIPTION
- *
- * Releases the lock acquired with silc_client_lock_server.
- *
- ***/
-void silc_client_unlock_server(SilcServerEntry server_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_ref_server
- *
- * SYNOPSIS
- *
- * SilcServerEntry
- * silc_client_ref_server(SilcClient client,
- * SilcClientConnection conn,
- * SilcServerEntry server_entry);
- *
- * DESCRIPTION
- *
- * Takes a reference of the server entry indicated by `server_entry'
- * The reference must be released by calling silc_client_unref_server
- * after it is not needed anymore. Returns `server_entry'.
- *
- ***/
-SilcServerEntry silc_client_ref_server(SilcClient client,
- SilcClientConnection conn,
- SilcServerEntry server_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_unref_server
- *
- * SYNOPSIS
- *
- * void silc_client_unref_server(SilcClient client,
- * SilcClientConnection conn,
- * SilcServerEntry server_entry);
- *
- * DESCRIPTION
- *
- * Releases the server entry reference indicated by `server_entry'.
- *
- ***/
-void silc_client_unref_server(SilcClient client, SilcClientConnection conn,
- SilcServerEntry server_entry);
-
-/****f* silcclient/SilcClientAPI/silc_client_list_free_server
- *
- * SYNOPSIS
- *
- * void silc_client_list_free_server(SilcClient client,
- * SilcClientConnection conn,
- * SilcDList server_list);
- *
- * DESCRIPTION
- *
- * Free's server entry list that has been returned by various library
- * routines.
- *
- ***/
-void silc_client_list_free_servers(SilcClient client,
- SilcClientConnection conn,
- SilcDList server_list);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_server
- *
- * SYNOPSIS
- *
- * SilcServerEntry silc_client_get_server(SilcClient client,
- * SilcClientConnection conn,
- * char *server_name)
- *
- * DESCRIPTION
- *
- * Finds entry for server by the server name. Returns the entry or NULL
- * if the entry was not found.
- *
- ***/
-SilcServerEntry silc_client_get_server(SilcClient client,
- SilcClientConnection conn,
- char *server_name);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_server_by_id
- *
- * SYNOPSIS
- *
- * SilcServerEntry silc_client_get_server_by_id(SilcClient client,
- * SilcClientConnection conn,
- * SilcServerID *server_id);
- *
- * DESCRIPTION
- *
- * Finds entry for server by the server ID. Returns the entry or NULL
- * if the entry was not found.
- *
- ***/
-SilcServerEntry silc_client_get_server_by_id(SilcClient client,
- SilcClientConnection conn,
- SilcServerID *server_id);
-
-/****f* silcclient/SilcClientAPI/silc_client_get_server_by_id_resolve
- *
- * SYNOPSIS
- *
- * SilcUInt16
- * silc_client_get_server_by_id_resolve(SilcClient client,
- * SilcClientConnection conn,
- * SilcServerID *server_id,
- * SilcGetServerCallback completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Resolves the server information by the `server_id'. The resolved
- * server is returned into the `completion' callback.
- *
- * Returns command identifier for the resolving. It can be used to attach
- * a pending command to it, if needed. Returns 0 on error.
- *
- ***/
-SilcUInt16
-silc_client_get_server_by_id_resolve(SilcClient client,
- SilcClientConnection conn,
- SilcServerID *server_id,
- SilcGetServerCallback completion,
- void *context);
-
-#endif /* SILCCLIENT_ENTRY_H */
+++ /dev/null
-#
-# Makefile.am
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2006 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_silcclient
-
-test_silcclient_SOURCES = test_silcclient.c
-
-LIBS = $(SILC_COMMON_LIBS)
-LDADD = -L.. -L../.. -lsilc -lsilcclient
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-/* SILC Client library tests */
-
-#include "silc.h"
-#include "silcclient.h"
-
-SilcBool success;
-SilcClientOperations ops;
-
-SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...)
-{
- return NULL;
-}
-
-
-/******* MyBot code **********************************************************/
-
-/* This is context for our MyBot client */
-typedef struct {
- SilcClient client; /* The actual SILC Client */
- SilcClientConnection conn; /* Connection to the server */
- SilcPublicKey public_key; /* My public key */
- SilcPrivateKey private_key; /* My private key */
-} *MyBot;
-
-/* Connect callback */
-
-static void
-silc_connected(SilcClient client, SilcClientConnection conn,
- SilcClientConnectionStatus status,
- SilcStatus error, const char *message,
- void *context)
-{
- MyBot mybot = client->application;
-
- if (status == SILC_CLIENT_CONN_DISCONNECTED) {
- SILC_LOG_DEBUG(("Disconnected %s", message ? message : ""));
- silc_client_stop(client);
- return;
- }
-
- if (status != SILC_CLIENT_CONN_SUCCESS &&
- status != SILC_CLIENT_CONN_SUCCESS_RESUME) {
- SILC_LOG_DEBUG(("Error connecting to server %d", status));
- silc_client_stop(client);
- return;
- }
-
- SILC_LOG_DEBUG(("Connected to server"));
-
- /* Save the connection context */
- mybot->conn = conn;
-}
-
-/* Start the MyBot, by creating the SILC Client entity by using the
- SILC Client Library API. */
-int mybot_start(void)
-{
- MyBot mybot;
- SilcClientParams params;
-
- /* Allocate the MyBot structure */
- mybot = silc_calloc(1, sizeof(*mybot));
- if (!mybot) {
- perror("Out of memory");
- return 1;
- }
-
- memset(¶ms, 0, sizeof(params));
- params.threads = TRUE;
- mybot->client = silc_client_alloc(&ops, ¶ms, mybot, NULL);
- if (!mybot->client) {
- perror("Could not allocate SILC Client");
- return 1;
- }
-
- /* Now we initialize the client. */
- if (!silc_client_init(mybot->client, silc_get_username(),
- silc_net_localhost(), "I am the MyBot")) {
- perror("Could not init client");
- return 1;
- }
-
- if (!silc_load_key_pair("mybot.pub", "mybot.prv", "",
- &mybot->public_key,
- &mybot->private_key)) {
- /* The keys don't exist. Let's generate us a key pair then! There's
- nice ready routine for that too. Let's do 2048 bit RSA key pair. */
- fprintf(stdout, "MyBot: Key pair does not exist, generating it.\n");
- if (!silc_create_key_pair("rsa", 2048, "mybot.pub", "mybot.prv", NULL, "",
- &mybot->public_key,
- &mybot->private_key, FALSE)) {
- perror("Could not generated key pair");
- return 1;
- }
- }
-
- /* And, then we are ready to go. Since we are really simple client we
- don't have user interface and we don't have to deal with message loops
- or interactivity. That's why we can just hand over the execution
- to the library by calling silc_client_run. */
- silc_client_run(mybot->client);
-
- /* When we get here, we have quit the client, so clean up and exit */
- silc_client_free(mybot->client);
- silc_free(mybot);
- return 0;
-}
-
-/******* SILC Client Operations **********************************************/
-
-/* The SILC Client Library requires these "client operations". They are
- functions that the library may call at any time to indicate to application
- that something happened, like message was received, or authentication
- is required or something else. Since our MyBot is really simple client
- we don't need most of the operations, so we just define them and don't
- do anything in them. */
-
-static void
-silc_running(SilcClient client, void *application)
-{
- MyBot mybot = application;
-
- SILC_LOG_DEBUG(("Client is running"));
-
- /* Start connecting to server. This is asynchronous connecting so the
- connection is actually created later after we run the client. */
- silc_client_connect_to_server(mybot->client, NULL,
- mybot->public_key, mybot->private_key,
- "10.2.1.100", 1334,
- silc_connected, mybot);
-}
-
-
-/* "say" client operation is a message from the client library to the
- application. It may include error messages or something else. We
- just dump them to screen. */
-
-static void
-silc_say(SilcClient client, SilcClientConnection conn,
- SilcClientMessageType type, char *msg, ...)
-{
- char str[200];
- va_list va;
- va_start(va, msg);
- vsnprintf(str, sizeof(str) - 1, msg, va);
- fprintf(stdout, "MyBot: %s\n", str);
- va_end(va);
-}
-
-
-/* Message for a channel. The `sender' is the sender of the message
- The `channel' is the channel. The `message' is the message. Note
- that `message' maybe NULL. The `flags' indicates message flags
- and it is used to determine how the message can be interpreted
- (like it may tell the message is multimedia message). */
-
-static void
-silc_channel_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessagePayload payload,
- SilcChannelPrivateKey key,
- SilcMessageFlags flags, const unsigned char *message,
- SilcUInt32 message_len)
-{
- /* Yay! We got a message from channel. */
-
- if (flags & SILC_MESSAGE_FLAG_SIGNED)
- fprintf(stdout, "[SIGNED] <%s> %s\n", sender->nickname, message);
- else
- fprintf(stdout, "<%s> %s\n", sender->nickname, message);
-}
-
-
-/* Private message to the client. The `sender' is the sender of the
- message. The message is `message'and maybe NULL. The `flags'
- indicates message flags and it is used to determine how the message
- can be interpreted (like it may tell the message is multimedia
- message). */
-
-static void
-silc_private_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcMessagePayload payload,
- SilcMessageFlags flags,
- const unsigned char *message,
- SilcUInt32 message_len)
-{
- /* MyBot does not support private message receiving */
-}
-
-
-/* Notify message to the client. The notify arguments are sent in the
- same order as servers sends them. The arguments are same as received
- from the server except for ID's. If ID is received application receives
- the corresponding entry to the ID. For example, if Client ID is received
- application receives SilcClientEntry. Also, if the notify type is
- for channel the channel entry is sent to application (even if server
- does not send it because client library gets the channel entry from
- the Channel ID in the packet's header). */
-
-static void
-silc_notify(SilcClient client, SilcClientConnection conn,
- SilcNotifyType type, ...)
-{
- char *str;
- va_list va;
-
- va_start(va, type);
-
- /* Here we can receive all kinds of different data from the server, but
- our simple bot is interested only in receiving the "not-so-important"
- stuff, just for fun. :) */
- switch (type) {
- case SILC_NOTIFY_TYPE_NONE:
- /* Received something that we are just going to dump to screen. */
- str = va_arg(va, char *);
- fprintf(stdout, "--- %s\n", str);
- break;
-
- case SILC_NOTIFY_TYPE_MOTD:
- /* Received the Message of the Day from the server. */
- str = va_arg(va, char *);
- fprintf(stdout, "%s", str);
- fprintf(stdout, "\n");
- break;
-
- default:
- /* Ignore rest */
- break;
- }
-
- va_end(va);
-}
-
-
-/* Command handler. This function is called always in the command function.
- If error occurs it will be called as well. `conn' is the associated
- client connection. `cmd_context' is the command context that was
- originally sent to the command. `success' is FALSE if error occurred
- during command. `command' is the command being processed. It must be
- noted that this is not reply from server. This is merely called just
- after application has called the command. Just to tell application
- that the command really was processed. */
-
-static void
-silc_command(SilcClient client, SilcClientConnection conn,
- SilcBool success, SilcCommand command, SilcStatus status,
- SilcUInt32 argc, unsigned char **argv)
-{
- /* If error occurred in client library with our command, print the error */
- if (status != SILC_STATUS_OK)
- fprintf(stderr, "MyBot: COMMAND %s: %s\n",
- silc_get_command_name(command),
- silc_get_status_message(status));
-}
-
-
-/* Command reply handler. This function is called always in the command reply
- function. If error occurs it will be called as well. Normal scenario
- is that it will be called after the received command data has been parsed
- and processed. The function is used to pass the received command data to
- the application.
-
- `conn' is the associated client connection. `cmd_payload' is the command
- payload data received from server and it can be ignored. It is provided
- if the application would like to re-parse the received command data,
- however, it must be noted that the data is parsed already by the library
- thus the payload can be ignored. `success' is FALSE if error occurred.
- In this case arguments are not sent to the application. The `status' is
- the command reply status server returned. The `command' is the command
- reply being processed. The function has variable argument list and each
- command defines the number and type of arguments it passes to the
- application (on error they are not sent). */
-
-static void
-silc_command_reply(SilcClient client, SilcClientConnection conn,
- SilcCommand command, SilcStatus status,
- SilcStatus error, va_list ap)
-{
- /* If error occurred in client library with our command, print the error */
- if (status != SILC_STATUS_OK)
- fprintf(stderr, "MyBot: COMMAND REPLY %s: %s\n",
- silc_get_command_name(command),
- silc_get_status_message(status));
-
-}
-
-/* Find authentication method and authentication data by hostname and
- port. The hostname may be IP address as well. When the authentication
- method has been resolved the `completion' callback with the found
- authentication method and authentication data is called. The `conn'
- may be NULL. */
-
-static void
-silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, SilcUInt16 port,
- SilcGetAuthMeth completion,
- void *context)
-{
- /* MyBot assumes that there is no authentication requirement in the
- server and sends nothing as authentication. We just reply with
- TRUE, meaning we know what is the authentication method. :). */
- completion(TRUE, SILC_AUTH_NONE, NULL, 0, context);
-}
-
-
-/* Verifies received public key. The `conn_type' indicates which entity
- (server, client etc.) has sent the public key. If user decides to trust
- the application may save the key as trusted public key for later
- use. The `completion' must be called after the public key has been
- verified. */
-
-static void
-silc_verify_public_key(SilcClient client, SilcClientConnection conn,
- SilcConnectionType conn_type,
- SilcPublicKey public_key,
- SilcVerifyPublicKey completion, void *context)
-{
- silc_show_public_key(public_key);
- completion(TRUE, context);
-}
-
-
-/* Ask (interact, that is) a passphrase from user. The passphrase is
- returned to the library by calling the `completion' callback with
- the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
- if not then the library will attempt to encode. */
-
-static void
-silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
- SilcAskPassphrase completion, void *context)
-{
- /* MyBot does not support asking passphrases from users since there
- is no user in our little client. We just reply with nothing. */
- completion(NULL, 0, context);
-}
-
-
-/* Asks whether the user would like to perform the key agreement protocol.
- This is called after we have received an key agreement packet or an
- reply to our key agreement packet. This returns TRUE if the user wants
- the library to perform the key agreement protocol and FALSE if it is not
- desired (application may start it later by calling the function
- silc_client_perform_key_agreement). If TRUE is returned also the
- `completion' and `context' arguments must be set by the application. */
-
-static void
-silc_key_agreement(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry, const char *hostname,
- SilcUInt16 port)
-{
- /* MyBot does not support incoming key agreement protocols, it's too
- simple for that. */
- return FALSE;
-}
-
-
-/* Notifies application that file transfer protocol session is being
- requested by the remote client indicated by the `client_entry' from
- the `hostname' and `port'. The `session_id' is the file transfer
- session and it can be used to either accept or reject the file
- transfer request, by calling the silc_client_file_receive or
- silc_client_file_close, respectively. */
-
-static void
-silc_ftp(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry, SilcUInt32 session_id,
- const char *hostname, SilcUInt16 port)
-{
- /* MyBot does not support file transfer, it's too simple for that too. */
-}
-
-
-/* Delivers SILC session detachment data indicated by `detach_data' to the
- application. If application has issued SILC_COMMAND_DETACH command
- the client session in the SILC network is not quit. The client remains
- in the network but is detached. The detachment data may be used later
- to resume the session in the SILC Network. The appliation is
- responsible of saving the `detach_data', to for example in a file.
-
- The detachment data can be given as argument to the functions
- silc_client_connect_to_server, or silc_client_add_connection when
- creating connection to remote server, inside SilcClientConnectionParams
- structure. If it is provided the client library will attempt to resume
- the session in the network. After the connection is created
- successfully, the application is responsible of setting the user
- interface for user into the same state it was before detaching (showing
- same channels, channel modes, etc). It can do this by fetching the
- information (like joined channels) from the client library. */
-
-static void
-silc_detach(SilcClient client, SilcClientConnection conn,
- const unsigned char *detach_data, SilcUInt32 detach_data_len)
-{
- /* Oh, and MyBot does not support session detaching either. */
-}
-
-/* Our client operations for the MyBot. This structure is filled with
- functions and given as argument to the silc_client_alloc function.
- Even though our little bot does not need all these functions we must
- provide them since the SILC Client Library wants them all. */
-/* This structure and all the functions were taken from the
- lib/silcclient/client_ops_example.c. */
-SilcClientOperations ops = {
- silc_say,
- silc_channel_message,
- silc_private_message,
- silc_notify,
- silc_command,
- silc_command_reply,
- silc_get_auth_method,
- silc_verify_public_key,
- silc_ask_passphrase,
- silc_key_agreement,
- silc_ftp,
- silc_detach,
- silc_running
-};
-
-int main(int argc, char **argv)
-{
- SilcSchedule schedule;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_quick(TRUE);
- silc_log_set_debug_string("*client*,*packet*,*net*,*stream*,*ske*,*buffer*");
- }
-
- /* Start the bot */
- mybot_start();
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
@LINK=silcstatus.html:SILC Status Types
@LINK=silcmode.html:SILC Modes
@LINK=silcid.html:SILC ID Interface
+@LINK=silcidcache.html:SILC ID Cache Interface
@LINK=silcargument.html:SILC Argument Interface
@LINK=silcattrs.html:SILC Attributes Interface
@LINK=silcpacket.html:Packet Protocol Interface
-@LINK=silcpubkey.html:SILC Public Key Payload Interface
-->
<big><b>SILC Core Library</b></big>
noinst_LTLIBRARIES = libsilccore.la
-libsilccore_la_SOURCES = \
- silcid.c \
- silcmessage.c \
- silcchannel.c \
- silccommand.c \
- silcpacket.c \
- silcargument.c \
- silcnotify.c \
- silcauth.c \
- silcattrs.c \
- silcstatus.c \
- silcpubkey.c
+libsilccore_la_SOURCES = \
+ silcid.c \
+ silcidcache.c \
+ silcmessage.c \
+ silcchannel.c \
+ silccommand.c \
+ silcpacket.c \
+ silcargument.c \
+ silcnotify.c \
+ silcauth.c \
+ silcattrs.c \
+ silcstatus.c
#ifdef SILC_DIST_TOOLKIT
include_HEADERS = \
silcauth.h \
silcchannel.h \
silcmessage.h \
- silcmessage_i.h \
silccommand.h \
+ silcidcache.h \
silcid.h \
silcmode.h \
silcnotify.h \
silcpacket.h \
silcargument.h \
silcstatus.h \
- silcattrs.h \
- silcpubkey.h
+ silcattrs.h
SILC_EXTRA_DIST = tests
#endif SILC_DIST_TOOLKIT
+++ /dev/null
-The SILC Core Library
-
-This library contains the implementation of various SILC protocol packet
-payloads and other routines. It also implements the SILC Packet Engine.
-
-
-The SILC Packet Engine
-
-The SILC Packet engine (silcpacket.[ch]) is the heart of sending and
-receiving SILC packets. The engine works in single thread but is thread
-safe and has the notion of per-thread contexts for optimized processing.
-The per-thread processing is actually per-scheduler, but in reality multiple
-schedulers are run only when they are used in threads.
-
-The packet engine has a lock (engine->lock) that protects various engine
-wide data. Currently this includes SILC Packet freelist, which could
-perhaps later be in the per-thread SilcPacketEngineContext context. The
-engine also keeps list of all streams (SilcPacketStream) that has been
-added to the engine.
-
-The SilcPacketStream contains all stream related data, including encryption
-and decryption keys, IDs, and outgoing buffer. The outgoing buffer is
-per-stream so that data can be sent in multiple pieces from the outbuffer
-if writing would block. Incoming buffer is not in stream context unless
-it is necessary. The incoming buffer is in the per-thread context which
-actually has a list of incoming buffers. If reading blocks for the given
-stream, that incoming buffer is given to the SilcPacketStream context from
-the list of buffers. When data is again available for that stream it is
-read into the buffer the stream already has. Other stream will read to
-the per-thread buffer, unless they would block also. The stream also
-has a lock (stream->lock) because application can modify various data in
-the stream.
-
-The packet callback has packet callbacks that is used to deliver the read
-packet to application. The callbacks also deliver error and end of stream
-status to application. It is also possible to attach additional packet
-callbacks to stream so that there may be multiple receivers for one packet.
-In the callback application may decide whether it wants to take the packet
-or whether to pass it for the next receiver. The callbacks can be added
-with priority.
-
-
-Locking in packet engine
-
-Currently the engine lock is used only when the packet free list is accessed,
-or new stream is added or removed. The packet free list, however, is
-accessed for all incoming packets. Application free's the packet context so
-the lock must later be acquired be putting the unused packet context back
-to the free list. It might be possible to later put the packet free list to
-per-thread context.
-
-Stream lock is taken everytime data is read from the underlaying stream or
-sent to the underlaying stream. In principal it would be possible to read
-without locking, because we use per-thread incoming buffers but in reality
-many platforms would not suppots reading and writing to the same underlaying
-stream (effectively socket) at the same time. And even if they would, some
-rare race conditions with closing the stream might occur. One way of dealing
-with this would be to make sure that any stream used with SilcPacketStream
-must itself be thread-safe. In that case the locking would move to the
-underlaying stream.
-
-When reading data from stream, the lock is held during reading and during
-data processing. The lock is released when the packet is dispatched to
-a packet callback.
-
-When sending packet the lock is acquired only when actually accessing the
-outgoing buffer and writing to the stream. This includes encryption. This
-means that if two threads send to same stream the encryption is not in
-parallel.
/*
- silcargument.c
+ silcargument.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2006 Pekka Riikonen
+ Copyright (C) 2001 - 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
GNU General Public License for more details.
*/
-/* Implementation of Argument Payload routines */
+/* Implementation of Argument Payload routines */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcargument.h"
-/*************************** Argument Payload *******************************/
+/******************************************************************************
+
+ Argument Payload
+
+******************************************************************************/
struct SilcArgumentPayloadStruct {
SilcUInt32 argc;
newp->argv_types = silc_calloc(argc, sizeof(SilcUInt32));
if (!newp->argv_types)
goto err;
-
+
/* Get arguments */
arg_num = 1;
for (i = 0; i < argc; i++) {
SILC_STR_UI_SHORT(&p_len),
SILC_STR_UI_CHAR(&arg_type),
SILC_STR_END);
- if (ret == -1 || p_len > silc_buffer_len(&buffer) - 3)
+ if (ret == -1 || p_len > buffer.len - 3)
goto err;
newp->argv_lens[i] = p_len;
/* Get argument data */
silc_buffer_pull(&buffer, 3);
ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI_XNSTRING_ALLOC(&newp->argv[i],
+ SILC_STR_UI_XNSTRING_ALLOC(&newp->argv[i],
p_len),
SILC_STR_END);
if (ret == -1)
pull_len += 3 + p_len;
}
- if (silc_buffer_len(&buffer) != 0) {
+ if (buffer.len != 0) {
SILC_LOG_DEBUG(("Malformed argument payload"));
goto err;
}
len = 3 + (SilcUInt16)arg_len;
buffer = silc_buffer_realloc(buffer,
- (buffer ? silc_buffer_truelen(buffer) +
- len : len));
+ (buffer ? buffer->truelen + len : len));
if (!buffer)
return NULL;
- silc_buffer_pull(buffer, silc_buffer_len(buffer));
+ silc_buffer_pull(buffer, buffer->len);
silc_buffer_pull_tail(buffer, len);
- silc_buffer_format(buffer,
+ silc_buffer_format(buffer,
SILC_STR_UI_SHORT(arg_len),
SILC_STR_UI_CHAR(arg_type),
SILC_STR_UI_XNSTRING(arg, (SilcUInt16)arg_len),
silc_buffer_format(buffer,
SILC_STR_UI_SHORT(payload->argv_lens[i]),
SILC_STR_UI_CHAR(payload->argv_types[i]),
- SILC_STR_UI_XNSTRING(payload->argv[i],
+ SILC_STR_UI_XNSTRING(payload->argv[i],
payload->argv_lens[i]),
SILC_STR_END);
silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
return payload->argv[i];
}
-
-/* Return argument already decoded */
-
-static SilcBool silc_argument_decode(unsigned char *data,
- SilcUInt32 data_len,
- SilcArgumentDecodeType dec_type,
- void *ret_arg,
- void **ret_arg_alloc)
-{
- switch (dec_type) {
-
- case SILC_ARGUMENT_ID:
- if (ret_arg)
- if (!silc_id_payload_parse_id(data, data_len, (SilcID *)ret_arg))
- return FALSE;
-
- if (ret_arg_alloc) {
- SilcID id;
- if (!silc_id_payload_parse_id(data, data_len, &id))
- return FALSE;
- *ret_arg_alloc = silc_memdup(&id, sizeof(id));
- }
- break;
-
- case SILC_ARGUMENT_PUBLIC_KEY:
- {
- SilcPublicKey public_key;
-
- if (!ret_arg_alloc)
- return FALSE;
-
- if (!silc_public_key_payload_decode(data, data_len, &public_key))
- return FALSE;
-
- *ret_arg_alloc = public_key;
- }
- break;
-
- case SILC_ARGUMENT_ATTRIBUTES:
- if (!ret_arg_alloc)
- return FALSE;
-
- *ret_arg_alloc = silc_attribute_payload_parse(data, data_len);
- break;
-
- case SILC_ARGUMENT_UINT32:
- if (data_len != 4)
- return FALSE;
-
- if (ret_arg) {
- SilcUInt32 *i = ret_arg;
- SILC_GET32_MSB(*i, data);
- }
-
- if (ret_arg_alloc) {
- SilcUInt32 i;
- SILC_GET32_MSB(i, data);
- *ret_arg_alloc = silc_memdup(&i, sizeof(i));
- }
- break;
-
- case SILC_ARGUMENT_BOOL:
- if (data_len != sizeof(SilcBool))
- return FALSE;
-
- if (ret_arg) {
- SilcBool *b = ret_arg;
- *b = (data[0] == 0x01 ? TRUE : FALSE);
- }
-
- if (ret_arg_alloc) {
- SilcBool b;
- b = (data[0] == 0x01 ? TRUE : FALSE);
- *ret_arg_alloc = silc_memdup(&b, sizeof(b));
- }
- break;
-
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Return argument already decoded */
-
-SilcBool silc_argument_get_decoded(SilcArgumentPayload payload,
- SilcUInt32 type,
- SilcArgumentDecodeType dec_type,
- void *ret_arg,
- void **ret_arg_alloc)
-{
- unsigned char *tmp;
- SilcUInt32 tmp_len;
-
- tmp = silc_argument_get_arg_type(payload, type, &tmp_len);
- if (!tmp)
- return FALSE;
-
- return silc_argument_decode(tmp, tmp_len, dec_type, ret_arg, ret_arg_alloc);
-}
-
-/************************* Argument List Payload ****************************/
-
-/* Parses argument payload list */
-
-SilcArgumentPayload
-silc_argument_list_parse(const unsigned char *payload,
- SilcUInt32 payload_len)
-{
- SilcArgumentPayload arg;
- SilcUInt16 argc;
-
- if (payload_len < 5)
- return NULL;
-
- SILC_GET16_MSB(argc, payload);
-
- arg = silc_argument_payload_parse(payload + 2, payload_len - 2, argc);
-
- return arg;
-}
-
-/* Parses argument payload list of specific argument types */
-
-SilcDList
-silc_argument_list_parse_decoded(const unsigned char *payload,
- SilcUInt32 payload_len,
- SilcArgumentDecodeType dec_type)
-{
- SilcArgumentPayload arg;
- SilcArgumentDecodedList dec;
- unsigned char *data;
- SilcUInt32 data_len, type;
- SilcDList list;
-
- arg = silc_argument_list_parse(payload, payload_len);
- if (!arg)
- return NULL;
-
- list = silc_dlist_init();
- if (!list) {
- silc_argument_payload_free(arg);
- return NULL;
- }
-
- data = silc_argument_get_first_arg(arg, &type, &data_len);
- while (data) {
- dec = silc_calloc(1, sizeof(*dec));
- if (!dec)
- continue;
- dec->arg_type = type;
- if (silc_argument_decode(data, data_len, dec_type, NULL, &dec->argument))
- silc_dlist_add(list, dec);
- else
- silc_free(dec);
- data = silc_argument_get_next_arg(arg, &type, &data_len);
- }
-
- silc_argument_payload_free(arg);
-
- silc_dlist_start(list);
-
- return list;
-}
-
-/* Free decoded argument payload list */
-
-void silc_argument_list_free(SilcDList list, SilcArgumentDecodeType dec_type)
-{
- SilcArgumentDecodedList dec;
-
- if (!list)
- return;
-
- silc_dlist_start(list);
- while ((dec = silc_dlist_get(list))) {
- switch (dec_type) {
-
- case SILC_ARGUMENT_ID:
- case SILC_ARGUMENT_UINT32:
- case SILC_ARGUMENT_BOOL:
- silc_free(dec->argument);
- break;
-
- case SILC_ARGUMENT_PUBLIC_KEY:
- silc_pkcs_public_key_free(dec->argument);
- break;
-
- case SILC_ARGUMENT_ATTRIBUTES:
- silc_attribute_payload_free(dec->argument);
- break;
-
- default:
- break;
- }
-
- silc_free(dec);
- }
-
- silc_dlist_uninit(list);
-}
/*
- silcargument.h
+ silcargument.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2006 Pekka Riikonen
+ Copyright (C) 2001 - 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
*
* DESCRIPTION
*
- * Implementations of the Argument Payload and Argument List Payload, that
- * is used to include arguments to other payload that needs arguments.
+ * Implementation of the Argument Payload, that is used to include
+ * argument to other payload that needs arguments.
*
***/
-#ifndef SILCARGUMENT_H
-#define SILCARGUMENT_H
+#ifndef SILCPAYLOAD_H
+#define SILCPAYLOAD_H
/****s* silccore/SilcArgumentAPI/SilcArgumentPayload
*
* NAME
- *
+ *
* typedef struct SilcArgumentPayloadStruct *SilcArgumentPayload;
*
* DESCRIPTION
*
* SYNOPSIS
*
- * SilcArgumentPayload
+ * SilcArgumentPayload
* silc_argument_payload_parse(const unsigned char *payload,
* SilcUInt32 payload_len,
* SilcUInt32 argc);
* Encodes arguments in to Argument Paylods returning them to SilcBuffer.
* The `argv' is the array of the arguments, the `argv_lens' array of
* the length of the `argv' arguments and the `argv_types' array of
- * the argument types of the `argv' arguments. The `argc' is the
+ * the argument types of the `argv' arguments. The `argc' is the
* number of arguments.
*
***/
*
* SYNOPSIS
*
- * SilcBuffer
+ * SilcBuffer
* silc_argument_payload_encode_payload(SilcArgumentPayload payload);
*
* DESCRIPTION
*
* DESCRIPTION
*
- * Returns the number of arguments in the Argument Payload.
+ * Returns the number of argument in the Argument Payload.
*
***/
SilcUInt32 silc_argument_get_arg_num(SilcArgumentPayload payload);
SilcUInt32 type,
SilcUInt32 *ret_len);
-/****d* silccore/SilcArgumentAPI/SilcArgumentDecodeType
- *
- * NAME
- *
- * typedef enum { ... } SilcArgumentDecodeType;
- *
- * DESCRIPTION
- *
- * Argument decode types used with silc_argument_get_decoded.
- *
- * SOURCE
- */
-typedef enum {
- SILC_ARGUMENT_ID, /* SilcID */
- SILC_ARGUMENT_PUBLIC_KEY, /* SilcPublicKey (always alloc) */
- SILC_ARGUMENT_ATTRIBUTES, /* SilcDList (always alloc) */
- SILC_ARGUMENT_UINT32, /* SilcUInt32 */
- SILC_ARGUMENT_BOOL, /* SilcBool */
-} SilcArgumentDecodeType;
-/***/
-
-/****f* silccore/SilcArgumentAPI/silc_argument_get_decoded
- *
- * SYNOPSIS
- *
- * SilcBool silc_argument_get_decoded(SilcArgumentPayload payload,
- * SilcUInt32 type,
- * SilcArgumentDecodeType dec_type,
- * void *ret_arg,
- * void *ret_arg_alloc);
- *
- * DESCRIPTION
- *
- * Returns decoded argument by type. This is a helper function to
- * decode common argument types directly. The `type' is the argument
- * type number in the payload, and the `dec_type' is the type the
- * argument is decoded to. If the `ret_arg' is non-NULL then the
- * decodec data is returned into that pointer. If the `ret_arg_alloc'
- * is non-NULL then this function will allocate the decoded data and
- * will return the pointer into `ret_arg_alloc'. Some types must always
- * be allocated; see SilcArgumentDecodeType.
- *
- * Return TRUE if the argument was present and waa successfully decoded.
- * FALSE if it is not present, or could not be decoded.
- *
- * EXAMPLE
- *
- * SilcID id;
- * SilcPublicKey public_key;
- *
- * if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
- * error;
- *
- * if (!silc_argument_get_decoded(args, 4, SILC_ARGUMENT_PUBLIC_KEY,
- * NULL, &public_key))
- * error;
- *
- ***/
-SilcBool silc_argument_get_decoded(SilcArgumentPayload payload,
- SilcUInt32 type,
- SilcArgumentDecodeType dec_type,
- void *ret_arg,
- void **ret_arg_alloc);
-
-/****f* silccore/SilcArgumentAPI/silc_argument_list_parse
- *
- * SYNOPSIS
- *
- * SilcArgumentPayload
- * silc_argument_list_parse(const unsigned char *payload,
- * SilcUInt32 payload_len);
- *
- * DESCRIPTION
- *
- * Parses argument list payload. Returns parsed SilcArgumentPayload which
- * contains all the arguments from the list. The caller must free the
- * returned context with silc_argument_payload_free.
- *
- ***/
-SilcArgumentPayload
-silc_argument_list_parse(const unsigned char *payload, SilcUInt32 payload_len);
-
-/****s* silccore/SilcArgumentAPI/SilcArgumentDecodedList
- *
- * NAME
- *
- * typedef struct { ... } *SilcArgumentDecodedList;
- *
- * DESCRIPTION
- *
- * This structure is in the list returned by the function
- * silc_argument_list_payload_parse_decoded. The caller is responsible
- * of freeing the contents of the structure and the structure itself.
- *
- ***/
-typedef struct {
- void *argument; /* Decoded argument, caller must know its type */
- SilcUInt32 arg_type; /* Argument type number from the payload */
-} *SilcArgumentDecodedList;
-
-/****f* silccore/SilcArgumentAPI/silc_argument_list_parse_decoded
- *
- * SYNOPSIS
- *
- * SilcDList
- * silc_argument_list_parse_decoded(const unsigned char *payload,
- * SilcUInt32 payload_len,
- * SilcArgumentDecodeType dec_type);
- *
- * DESCRIPTION
- *
- * Parses argument list payload of arguments of the type `dec_type'.
- * The returned list includes the already decoded arguments. The caller
- * is responsible of freeing the the contents of the list and the list
- * itself. Each entry in the list is SilcArgumentDecodedList. The
- * caller must free the returned list with silc_argument_list_free.
- *
- ***/
-SilcDList
-silc_argument_list_parse_decoded(const unsigned char *payload,
- SilcUInt32 payload_len,
- SilcArgumentDecodeType dec_type);
-
-/****f* silccore/SilcArgumentAPI/silc_argument_list_free
- *
- * SYNOPSIS
- *
- * void
- * silc_argument_list_free(SilcDList list, SilcArgumentDecodeType dec_type);
- *
- * DESCRIPTION
- *
- * Free's the decoded argument list and its contents.
- *
- ***/
-void silc_argument_list_free(SilcDList list, SilcArgumentDecodeType dec_type);
-
-#endif /* SILCARGUMENT_H */
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 Pekka Riikonen
+ Copyright (C) 2002 - 2004 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
/* Implementation of Attribute Payload routines */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcattrs.h"
/******************************************************************************
len = strlen(service->address);
len2 = strlen(service->signon);
tmpbuf = silc_buffer_alloc_size(13 + len + len2);
- if (!tmpbuf)
- return NULL;
silc_buffer_format(tmpbuf,
SILC_STR_UI_INT(service->port),
SILC_STR_UI_SHORT(len),
SILC_STR_UI_INT(service->idle),
SILC_STR_END);
object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
+ object_size = tmpbuf->len;
}
break;
case SILC_ATTRIBUTE_EXTENSION:
case SILC_ATTRIBUTE_USER_ICON:
{
- SilcMime mime = object;
+ SilcAttributeObjMime *mime = object;
if (object_size != sizeof(*mime))
return NULL;
- str = silc_mime_encode(mime, &object_size);
- if (!str)
- return NULL;
+ object = (void *)mime->mime;
+ object_size = mime->mime_len;
}
break;
SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
SILC_STR_END);
object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
+ object_size = tmpbuf->len;
}
break;
SILC_STR_UI16_STRING(len4 ? dev->language : ""),
SILC_STR_END);
object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
- }
- break;
-
- case SILC_ATTRIBUTE_PHONE_NUMBER:
- {
- SilcAttributeObjPN *pn = object;
- if (object_size != sizeof(*pn))
- return NULL;
- if (!pn->number || strlen(pn->number) < 5)
- return NULL;
- tmpbuf = silc_buffer_alloc(0);
- if (!tmpbuf)
- return NULL;
- if (silc_buffer_format(tmpbuf,
- SILC_STR_UI_INT(pn->format),
- SILC_STR_UI_SHORT(strlen(pn->number)),
- SILC_STR_UI16_STRING(pn->number),
- SILC_STR_END) < 0)
- return NULL;
- object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
+ object_size = tmpbuf->len;
}
break;
SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
SILC_STR_END);
object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
+ object_size = tmpbuf->len;
}
break;
silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
list = silc_dlist_init();
- while (silc_buffer_len(&buffer)) {
+ while (buffer.len) {
newp = silc_calloc(1, sizeof(*newp));
if (!newp)
goto err;
if (ret == -1)
goto err;
- if (newp->data_len > silc_buffer_len(&buffer) - 4) {
+ if (newp->data_len > buffer.len - 4) {
SILC_LOG_ERROR(("Incorrect attribute payload in list"));
goto err;
}
len = 4 + newp->data_len;
- if (silc_buffer_len(&buffer) < len)
+ if (buffer.len < len)
break;
silc_buffer_pull(&buffer, len);
len = 4 + (SilcUInt16)data_len;
buffer = silc_buffer_realloc(buffer,
- (buffer ? silc_buffer_truelen(buffer) +
- len : len));
+ (buffer ? buffer->truelen + len : len));
if (!buffer)
return NULL;
- silc_buffer_pull(buffer, silc_buffer_len(buffer));
+ silc_buffer_pull(buffer, buffer->len);
silc_buffer_pull_tail(buffer, len);
silc_buffer_format(buffer,
SILC_STR_UI_CHAR(attribute),
/* Construct digital signature verification data */
unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
- SilcBool server_verification,
+ bool server_verification,
SilcUInt32 *data_len)
{
SilcAttributePayload attr;
/* Return parsed attribute object */
-SilcBool silc_attribute_get_object(SilcAttributePayload payload,
- void *object, SilcUInt32 object_size)
+bool silc_attribute_get_object(SilcAttributePayload payload,
+ void *object, SilcUInt32 object_size)
{
SilcUInt16 len;
- SilcBool ret = FALSE;
+ bool ret = FALSE;
if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
return FALSE;
case SILC_ATTRIBUTE_EXTENSION:
case SILC_ATTRIBUTE_USER_ICON:
{
- SilcMime mime = object;
+ SilcAttributeObjMime *mime = object;
if (object_size != sizeof(*mime))
break;
- if (!silc_mime_decode(mime, payload->data, payload->data_len))
- break;
+ mime->mime = (const unsigned char *)payload->data;
+ mime->mime_len = payload->data_len;
ret = TRUE;
}
break;
}
break;
- case SILC_ATTRIBUTE_PHONE_NUMBER:
- {
- SilcAttributeObjPN *pn = object;
- SilcBufferStruct buffer;
- SilcUInt32 pn_format;
- int res;
- if (object_size != sizeof(*pn))
- break;
- silc_buffer_set(&buffer, (unsigned char *)payload->data,
- payload->data_len);
- res =
- silc_buffer_unformat(&buffer,
- SILC_STR_UI_INT(&pn_format),
- SILC_STR_UI16_STRING_ALLOC(&pn->number),
- SILC_STR_END);
- if (res == -1)
- break;
- pn->format = pn_format;
- ret = TRUE;
- }
- break;
-
case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
{
silc_buffer_unformat(&buffer,
SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
SILC_STR_END);
- if (res == -1 || len > silc_buffer_len(&buffer) - 2)
+ if (res == -1 || len > buffer.len - 2)
break;
pk->data = silc_memdup(payload->data + 2 + len,
payload->data_len - 2 - len);
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 Pekka Riikonen
+ Copyright (C) 2002 - 2003 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
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 /* 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_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_SERVER_DIGITAL_SIGNATURE 15 /* SilcAttributeObjPk */
-#define SILC_ATTRIBUTE_USER_ICON 16 /* SilcMime */
-#define SILC_ATTRIBUTE_PHONE_NUMBER 17 /* SilcAttributeObjPN */
+#define SILC_ATTRIBUTE_USER_ICON 16 /* SilcAttributeObjMime */
/***/
/* Maximum length of attribute request packet */
} SilcAttributeDevice;
/***/
-/****d* silccore/SilcAttributesAPI/SilcAttributePNFormat
- *
- * NAME
- *
- * typedef enum { ... } SilcAttributePNFormat;
- *
- * DESCRIPTION
- *
- * The defined phone number formats.
- *
- * SOURCE
- */
-typedef enum {
- SILC_ATTRIBUTE_NUMBER_ITU_E164 = 0, /* ITU E.164 */
- SILC_ATTRIBUTE_NUMBER_ITU_E123 = 1, /* ITU E.123 */
- SILC_ATTRIBUTE_NUMBER_ENUM = 2, /* ENUM, RFC 3761 */
-} SilcAttributePNFormat;
-/***/
-
/****f* silccore/SilcAttributesAPI/silc_attribute_payload_alloc
*
* SYNOPSIS
*
* unsigned char *
* silc_attribute_get_verify_data(SilcDList attrs,
- * SilcBool server_verification,
+ * bool server_verification,
* SilcUInt32 *data_len);
*
* DESCRIPTION
*
***/
unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
- SilcBool server_verification,
+ bool server_verification,
SilcUInt32 *data_len);
/* Object structures */
SilcUInt32 idle; /* Idle time in the service */
char signon[64]; /* Signon date and time (UTC) */
char address[256]; /* service address */
- SilcBool status; /* online status (TRUE present in service) */
+ bool 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
* caller must free the data inside the structure. The 'type' is one
* of following: "silc-rsa", "silc-dss, "ssh-rsa", "ssh-dss",
* "pgp-sign-rsa", "pgp-sign-dss", "x509v3-sign-rsa", "x509v3-sign-dss".
- * The 'type' is NULL when this structure includes a digital signature.
+ * See the draft-riikonen-precense-attrs draft for more detailed
+ * information. The 'type' is NULL when this structure includes a
+ * digital signature.
*
* In SILC, at least the "silc-rsa" must be supported. In this case
* the key is normal SILC Public key. To verify a signature with the
} SilcAttributeObjPk;
/***/
-/****s* silccore/SilcAttributesAPI/SilcAttributeObjPN
- *
- * NAME
- *
- * typedef struct { ... } SilcAttributeObjPN;
- *
- * DESCRIPTION
- *
- * SILC_ATTRIBUTE_PHONE_NUMBER type object. The caller must free the
- * phone number string inside the structure.
- *
- * SOURCE
- */
-typedef struct SilcAttributeObjPNStruct {
- SilcAttributePNFormat format; /* Phone number format */
- char *number; /* Phone number */
-} SilcAttributeObjPN;
-/***/
-
/****f* silccore/SilcAttributesAPI/silc_attribute_get_object
*
* SYNOPSIS
*
- * SilcBool silc_attribute_get_object(SilcAttributePayload payload,
- * void *object,
- * SilcUInt32 object_size);
+ * bool silc_attribute_get_object(SilcAttributePayload payload,
+ * void *object,
+ * SilcUInt32 object_size);
*
* DESCRIPTION
*
* 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();
* ...
*
***/
-SilcBool silc_attribute_get_object(SilcAttributePayload payload,
- void *object, SilcUInt32 object_size);
+bool silc_attribute_get_object(SilcAttributePayload payload,
+ void *object, SilcUInt32 object_size);
#endif /* SILCATTRS_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2003 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcauth.h"
/******************************************************************************
return NULL;
}
- if (newp->len != silc_buffer_len(&buffer) ||
- newp->random_len + newp->auth_len > silc_buffer_len(&buffer) - 8) {
+ if (newp->len != buffer.len ||
+ newp->random_len + newp->auth_len > buffer.len - 8) {
silc_auth_payload_free(newp);
return NULL;
}
SilcIdType type, SilcUInt32 *ret_len)
{
SilcBuffer buf;
- unsigned char *pk, id_data[32], *ret;
+ unsigned char *pk, *id_data, *ret;
SilcUInt32 pk_len, id_len;
pk = silc_pkcs_public_key_encode(public_key, &pk_len);
if (!pk)
return NULL;
- if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &id_len)) {
+ id_data = silc_id_id2str(id, type);
+ if (!id_data) {
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,
ret = silc_buffer_steal(buf, ret_len);
silc_buffer_free(buf);
+ silc_free(id_data);
silc_free(pk);
return ret;
unsigned char *tmp;
SilcUInt32 tmp_len;
SilcBuffer buf;
+ SilcPKCS pkcs;
SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
if (!tmp)
return NULL;
+ /* Allocate PKCS object */
+ if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
+ memset(tmp, 0, tmp_len);
+ silc_free(tmp);
+ return NULL;
+ }
+ silc_pkcs_public_key_set(pkcs, public_key);
+ silc_pkcs_private_key_set(pkcs, private_key);
+
/* Compute the hash and the signature. */
- if (!silc_pkcs_sign(private_key, tmp, tmp_len, auth_data,
- sizeof(auth_data) - 1, &auth_len, TRUE, hash)) {
+ if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
+ !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
+ &auth_len)) {
memset(tmp, 0, tmp_len);
silc_free(tmp);
+ silc_pkcs_free(pkcs);
return NULL;
}
memset(tmp, 0, tmp_len);
memset(auth_data, 0, sizeof(auth_data));
silc_free(tmp);
+ silc_pkcs_free(pkcs);
return buf;
}
/* Verifies the authentication data. Returns TRUE if authentication was
successful. */
-SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
- SilcPublicKey public_key,
- SilcHash hash,
- const void *id, SilcIdType type)
+bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+ SilcPublicKey public_key, SilcHash hash,
+ const void *id, SilcIdType type)
{
unsigned char *tmp;
SilcUInt32 tmp_len;
+ SilcPKCS pkcs;
SILC_LOG_DEBUG(("Verifying authentication data"));
return FALSE;
}
+ /* Allocate PKCS object */
+ if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
+ memset(tmp, 0, tmp_len);
+ silc_free(tmp);
+ return FALSE;
+ }
+ silc_pkcs_public_key_set(pkcs, public_key);
+
/* Verify the authentication data */
- if (!silc_pkcs_verify(public_key, payload->auth_data,
- payload->auth_len, tmp, tmp_len, hash)) {
+ if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
+ payload->auth_len, tmp, tmp_len)) {
memset(tmp, 0, tmp_len);
silc_free(tmp);
+ silc_pkcs_free(pkcs);
SILC_LOG_DEBUG(("Authentication failed"));
return FALSE;
}
memset(tmp, 0, tmp_len);
silc_free(tmp);
+ silc_pkcs_free(pkcs);
SILC_LOG_DEBUG(("Authentication successful"));
/* Same as above but the payload is not parsed yet. This will parse it. */
-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)
+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)
{
SilcAuthPayload auth_payload;
int ret;
authentication then the `auth_data' is the SilcPublicKey and the
`auth_data_len' is ignored. */
-SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
- const void *auth_data, SilcUInt32 auth_data_len,
- SilcHash hash, const void *id, SilcIdType type)
+bool 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"));
/* Same as above but parses the authentication payload before verify. */
-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)
+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)
{
SilcAuthPayload auth_payload;
- SilcBool ret;
+ bool ret;
auth_payload = silc_auth_payload_parse(payload, payload_len);
if (!auth_payload || (auth_payload->auth_len == 0))
struct SilcKeyAgreementPayloadStruct {
SilcUInt16 hostname_len;
unsigned char *hostname;
- SilcUInt16 protocol;
- SilcUInt16 port;
+ SilcUInt32 port;
};
/* Parses and returns an allocated Key Agreement payload. */
SILC_LOG_DEBUG(("Parsing Key Agreement Payload"));
+ silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
newp = silc_calloc(1, sizeof(*newp));
if (!newp)
return NULL;
/* Parse the payload */
- silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
ret = silc_buffer_unformat(&buffer,
SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname,
&newp->hostname_len),
- SILC_STR_UI_SHORT(&newp->protocol),
- SILC_STR_UI_SHORT(&newp->port),
+ SILC_STR_UI_INT(&newp->port),
SILC_STR_END);
- if (ret == -1 || newp->hostname_len > silc_buffer_len(&buffer) - 6) {
+ if (ret == -1 || newp->hostname_len > buffer.len - 6) {
silc_free(newp);
return NULL;
}
/* Encodes the Key Agreement protocol and returns the encoded buffer */
SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
- SilcUInt16 protocol,
- SilcUInt16 port)
+ SilcUInt32 port)
{
SilcBuffer buffer;
SilcUInt32 len = hostname ? strlen(hostname) : 0;
silc_buffer_format(buffer,
SILC_STR_UI_SHORT(len),
SILC_STR_UI_XNSTRING(hostname, len),
- SILC_STR_UI_SHORT(protocol),
- SILC_STR_UI_SHORT(port),
+ SILC_STR_UI_INT(port),
SILC_STR_END);
return buffer;
return payload->hostname;
}
-/* Returns the protocol in the payload */
-
-SilcUInt16 silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload)
-{
- return payload->protocol;
-}
-
/* Returns the port in the payload */
-SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
+SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload)
{
return payload->port;
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2003 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
#define SILC_AUTH_PASSWORD 1 /* Passphrase authentication */
#define SILC_AUTH_PUBLIC_KEY 2 /* Public key authentication */
-/****d* silccore/SilcAuthAPI/SilcAuthResult
- *
- * NAME
- *
- * typedef SilcUInt32 SilcAuthResult;
- *
- * DESCRIPTION
- *
- * Authentication protocol status. Used by all authentication protocols
- * in SILC.
- *
- * SOURCE
- */
-typedef SilcUInt32 SilcAuthResult;
-
-#define SILC_AUTH_OK 0 /* Authentication successful */
-#define SILC_AUTH_FAILED 1 /* Authentication failed */
+/* Authentication protocol status message (used by all authentication
+ protocols in the SILC). */
+#define SILC_AUTH_OK 0
+#define SILC_AUTH_FAILED 1
/***/
/****s* silccore/SilcAuthAPI/SilcAuthPayload
*
* SYNOPSIS
*
- * SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+ * bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
* SilcPublicKey public_key,
* SilcHash hash,
* const void *id, SilcIdType type);
* successful.
*
***/
-SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
- SilcPublicKey public_key,
- SilcHash hash,
- const void *id,
- SilcIdType type);
+bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+ SilcPublicKey public_key, SilcHash hash,
+ const void *id, SilcIdType type);
/****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_verify_data
*
* SYNOPSIS
*
- * SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+ * bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
* SilcUInt32 payload_len,
* SilcPublicKey public_key,
* SilcHash hash,
* was successful.
*
***/
-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);
+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);
/****f* silccore/SilcAuthAPI/silc_auth_verify
*
* SYNOPSIS
*
- * SilcBool silc_auth_verify(SilcAuthPayload payload,
+ * bool silc_auth_verify(SilcAuthPayload payload,
* SilcAuthMethod auth_method,
* const void *auth_data, SilcUInt32 auth_data_len,
* SilcHash hash, const void *id, SilcIdType type);
* `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
*
***/
-SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
- const void *auth_data, SilcUInt32 auth_data_len,
- SilcHash hash, const void *id, SilcIdType type);
+bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+ const void *auth_data, SilcUInt32 auth_data_len,
+ SilcHash hash, const void *id, SilcIdType type);
/****f* silccore/SilcAuthAPI/silc_auth_verify_data
*
* SYNOPSIS
*
- * SilcBool silc_auth_verify_data(const unsigned char *payload,
+ * bool silc_auth_verify_data(const unsigned char *payload,
* SilcUInt32 payload_len,
* SilcAuthMethod auth_method,
* const void *auth_data,
* `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
*
***/
-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);
+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);
/****s* silccore/SilcAuthAPI/SilcKeyAgreementPayload
*
* SYNOPSIS
*
* SilcBuffer silc_key_agreement_payload_encode(char *hostname,
- * SilcUInt16 protocol,
- * SilcUInt16 port);
+ * SilcUInt32 port);
*
* DESCRIPTION
*
- * Encodes the Key Agreement payload and returns the encoded buffer.
- * The `protocol' is 0 for TCP and 1 for UDP.
+ * Encodes the Key Agreement protocol and returns the encoded buffer
*
***/
SilcBuffer silc_key_agreement_payload_encode(const char *hostname,
- SilcUInt16 protocol,
- SilcUInt16 port);
+ SilcUInt32 port);
/****f* silccore/SilcAuthAPI/silc_key_agreement_payload_free
*
*
* DESCRIPTION
*
- * Frees the Key Agreement payload and all data in it.
+ * Frees the Key Agreement protocol and all data in it.
*
***/
void silc_key_agreement_payload_free(SilcKeyAgreementPayload payload);
***/
char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload);
-/****f* silccore/SilcAuthAPI/silc_key_agreement_get_protocol
- *
- * SYNOPSIS
- *
- * SilcUInt16
- * silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload);
- *
- * DESCRIPTION
- *
- * Returns the protocol in the payload. The protocol is either TCP (0)
- * or UDP (1).
- *
- ***/
-SilcUInt16 silc_key_agreement_get_protocol(SilcKeyAgreementPayload payload);
-
/****f* silccore/SilcAuthAPI/silc_key_agreement_get_port
*
* SYNOPSIS
*
- * SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload);
+ * SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload);
*
* DESCRIPTION
*
* the SILC Key Exchange protocol.
*
***/
-SilcUInt16 silc_key_agreement_get_port(SilcKeyAgreementPayload payload);
+SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload);
#endif
/*
- silcchannel.c
+ silcchannel.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005 Pekka Riikonen
+ Copyright (C) 1997 - 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
/* Channel Payload and Channel Key Payload implementations. */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcchannel.h"
/******************************************************************************
/* Parse the Channel Payload. Ignore the padding. */
ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
&newp->name_len),
- SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
&newp->id_len),
SILC_STR_UI_INT(&newp->mode),
SILC_STR_END);
if (ret == -1)
goto err;
- if ((newp->name_len < 1 || newp->name_len > silc_buffer_len(&buffer) - 8) ||
- (newp->id_len < 1 || newp->id_len > silc_buffer_len(&buffer) - 8) ||
- (newp->id_len + newp->name_len > silc_buffer_len(&buffer) - 8)) {
+ if ((newp->name_len < 1 || newp->name_len > buffer.len - 8) ||
+ (newp->id_len < 1 || newp->id_len > buffer.len - 8) ||
+ (newp->id_len + newp->name_len > buffer.len - 8)) {
SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
goto err;
}
silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
list = silc_dlist_init();
- while (silc_buffer_len(&buffer)) {
+ while (buffer.len) {
newp = silc_calloc(1, sizeof(*newp));
if (!newp)
goto err;
ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
&newp->name_len),
- SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
&newp->id_len),
SILC_STR_UI_INT(&newp->mode),
SILC_STR_END);
if (ret == -1)
goto err;
- if ((newp->name_len < 1 || newp->name_len > silc_buffer_len(&buffer) - 8) ||
- (newp->id_len < 1 || newp->id_len > silc_buffer_len(&buffer) - 8) ||
- (newp->id_len + newp->name_len > silc_buffer_len(&buffer) - 8)) {
+ if ((newp->name_len < 1 || newp->name_len > buffer.len - 8) ||
+ (newp->id_len < 1 || newp->id_len > buffer.len - 8) ||
+ (newp->id_len + newp->name_len > buffer.len - 8)) {
SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
goto err;
}
len = 2 + newp->name_len + 2 + newp->id_len + 4;
- if (silc_buffer_len(&buffer) < len)
+ if (buffer.len < len)
break;
silc_buffer_pull(&buffer, len);
silc_dlist_add(list, newp);
}
-
+
return list;
err:
SILC_LOG_DEBUG(("Encoding message payload"));
- buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 +
+ buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 +
channel_id_len + 4);
if (!buffer)
return NULL;
/* Encode the Channel Payload */
- silc_buffer_format(buffer,
+ silc_buffer_format(buffer,
SILC_STR_UI_SHORT(channel_name_len),
SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
SILC_STR_UI_SHORT(channel_id_len),
/* Return the channel ID as parsed ID. */
-SilcBool silc_channel_get_id_parse(SilcChannelPayload payload,
- SilcChannelID *ret_channel_id)
+SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
{
return silc_id_str2id(payload->channel_id, payload->id_len,
- SILC_ID_CHANNEL, ret_channel_id,
- sizeof(SilcChannelID));
+ SILC_ID_CHANNEL);
}
/* Return the mode. The mode is arbitrary. It can be the mode of the
/* Parses channel key payload returning new channel key payload structure */
-SilcChannelKeyPayload
+SilcChannelKeyPayload
silc_channel_key_payload_parse(const unsigned char *payload,
SilcUInt32 payload_len)
{
ret =
silc_buffer_unformat(&buffer,
SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
- SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
&newp->cipher_len),
- SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
&newp->key_len),
SILC_STR_END);
if (ret == -1)
goto err;
if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1 ||
- newp->id_len + newp->cipher_len + newp->key_len > silc_buffer_len(&buffer) - 6) {
+ newp->id_len + newp->cipher_len + newp->key_len > buffer.len - 6) {
SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
goto err;
}
return NULL;
}
-/* 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. */
SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
SILC_LOG_DEBUG(("Encoding channel key payload"));
- /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
+ /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
2 + cipher */
len = 2 + id_len + 2 + key_len + 2 + cipher_len;
buffer = silc_buffer_alloc_size(len);
return NULL;
/* Encode the Channel Payload */
- silc_buffer_format(buffer,
+ silc_buffer_format(buffer,
SILC_STR_UI_SHORT(id_len),
SILC_STR_UI_XNSTRING(id, id_len),
SILC_STR_UI_SHORT(cipher_len),
/* Return ID */
-unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
+unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
SilcUInt32 *id_len)
{
if (id_len)
/*
-
+
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
/****s* silccore/SilcChannelAPI/SilcChannelPayload
*
* NAME
- *
+ *
* typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
*
* DESCRIPTION
/****s* silccore/SilcChannelAPI/SilcChannelKeyPayload
*
* NAME
- *
+ *
* typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
*
* DESCRIPTION
*
* SYNOPSIS
*
- * SilcChannelPayload
+ * SilcChannelPayload
* silc_channel_payload_parse(const unsigned char *payload,
* SilcUInt32 payload_len);
*
*
* SYNOPSIS
*
- * SilcBool silc_channel_get_id_parse(SilcChannelPayload payload,
- * SilcChannelID *ret_channel_id);
+ * SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload);
*
* DESCRIPTION
*
* Return the Channel ID as parsed ID. This is equivalent to the
- * silc_channel_get_id execpt that the ID is already parsed.
+ * silc_channel_get_id execpt that the ID is already parsed. The caller
+ * must free the parsed Channel ID.
*
***/
-SilcBool silc_channel_get_id_parse(SilcChannelPayload payload,
- SilcChannelID *ret_channel_id);
+SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload);
/****f* silccore/SilcChannelAPI/silc_channel_get_mode
*
*
* 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);
*
* 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.
*
***/
*
* SYNOPSIS
*
- * unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
+ * unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
* SilcUInt32 *id_len);
*
* DESCRIPTION
* 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
/*
- silccommand.c
+ silccommand.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 Pekka Riikonen
+ Copyright (C) 1997 - 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silccommand.h"
/******************************************************************************
return NULL;
/* Parse the Command Payload */
- ret = silc_buffer_unformat(&buffer,
+ ret = silc_buffer_unformat(&buffer,
SILC_STR_UI_SHORT(&p_len),
SILC_STR_UI_CHAR(&newp->cmd),
SILC_STR_UI_CHAR(&args_num),
return NULL;
}
- if (p_len != silc_buffer_len(&buffer)) {
+ if (p_len != buffer.len) {
SILC_LOG_ERROR(("Incorrect command payload in packet"));
silc_free(newp);
return NULL;
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, buffer.len,
args_num);
if (!newp->args) {
silc_free(newp);
args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
if (!args)
return NULL;
- len = silc_buffer_len(args);
+ len = args->len;
}
len += SILC_COMMAND_PAYLOAD_LEN;
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, args->len),
SILC_STR_END);
silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
silc_buffer_free(args);
if (payload->args) {
args = silc_argument_payload_encode_payload(payload->args);
if (args)
- len = silc_buffer_len(args);
+ len = args->len;
argc = silc_argument_get_arg_num(payload->args);
}
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, args->len),
SILC_STR_END);
silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
silc_buffer_free(args);
}
/* Encodes Command payload with variable argument list. The arguments
- must be: SilcUInt32, unsigned char *, unsigned int, ... One
- {SilcUInt32, unsigned char * and unsigned int} forms one argument,
- thus `argc' in case when sending one {SilcUInt32, unsigned char *
+ must be: SilcUInt32, unsigned char *, unsigned int, ... One
+ {SilcUInt32, unsigned char * and unsigned int} forms one argument,
+ thus `argc' in case when sending one {SilcUInt32, unsigned char *
and SilcUInt32} equals one (1) and when sending two of those it
equals two (2), and so on. This has to be preserved or bad things
will happen. The variable arguments is: {type, data, data_len}. */
-SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
- SilcUInt16 ident,
+SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
+ SilcUInt16 ident,
SilcUInt32 argc, ...)
{
va_list ap;
/* Same as above but with va_list. */
-SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
- SilcUInt16 ident,
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
+ SilcUInt16 ident,
SilcUInt32 argc, va_list ap)
{
unsigned char **argv = NULL;
x_type = va_arg(ap, SilcUInt32);
x = va_arg(ap, unsigned char *);
x_len = va_arg(ap, SilcUInt32);
-
+
if (!x_type || !x || !x_len)
continue;
-
+
argv[k] = silc_memdup(x, x_len);
if (!argv[k])
goto out;
}
}
- buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
+ buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
argv_types, ident);
out:
extra argument to this function. The `argc' must not count `status'
as on argument. */
-SilcBuffer
-silc_command_reply_payload_encode_va(SilcCommand cmd,
+SilcBuffer
+silc_command_reply_payload_encode_va(SilcCommand cmd,
SilcStatus status,
SilcStatus error,
SilcUInt16 ident,
return buffer;
}
-SilcBuffer
-silc_command_reply_payload_encode_vap(SilcCommand cmd,
+SilcBuffer
+silc_command_reply_payload_encode_vap(SilcCommand cmd,
SilcStatus status,
SilcStatus error,
- SilcUInt16 ident, SilcUInt32 argc,
+ SilcUInt16 ident, SilcUInt32 argc,
va_list ap)
{
unsigned char **argv;
k++;
}
- buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
+ buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
argv_types, ident);
out:
/* Return command status */
-SilcBool silc_command_get_status(SilcCommandPayload payload,
- SilcStatus *status,
- SilcStatus *error)
+bool silc_command_get_status(SilcCommandPayload payload,
+ SilcStatus *status,
+ SilcStatus *error)
{
unsigned char *tmp;
SilcUInt32 tmp_len;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
*
* SYNOPSIS
*
- * SilcBool silc_command_get_status(SilcCommandPayload payload,
+ * bool silc_command_get_status(SilcCommandPayload payload,
* SilcStatus *status,
* SilcStatus *error);
*
* which indicates that there will be list of errors.
*
***/
-SilcBool silc_command_get_status(SilcCommandPayload payload,
- SilcStatus *status,
- SilcStatus *error);
+bool silc_command_get_status(SilcCommandPayload payload,
+ SilcStatus *status,
+ SilcStatus *error);
/****f* silccore/SilcCommandAPI/silc_command_set_ident
*
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcid.h"
/* ID lengths (in bytes) without the IP address part */
silc_buffer_pull(&buffer, 4);
- if (newp->len > silc_buffer_len(&buffer) ||
- newp->len > SILC_PACKET_MAX_ID_LEN)
+ if (newp->len > buffer.len || newp->len > SILC_PACKET_MAX_ID_LEN)
goto err;
ret = silc_buffer_unformat(&buffer,
- SILC_STR_DATA_ALLOC(&newp->id, newp->len),
+ SILC_STR_UI_XNSTRING_ALLOC(&newp->id, newp->len),
SILC_STR_END);
if (ret == -1)
goto err;
+ silc_buffer_push(&buffer, 4);
+
return newp;
err:
/* Return the ID directly from the raw payload data. */
-SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
- SilcID *ret_id)
+void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
+ SilcIdType *ret_type)
{
SilcBufferStruct buffer;
SilcIdType type;
SilcUInt16 idlen;
unsigned char *id_data;
int ret;
-
- if (!ret_id)
- return FALSE;
+ void *id;
silc_buffer_set(&buffer, (unsigned char *)data, len);
ret = silc_buffer_unformat(&buffer,
silc_buffer_pull(&buffer, 4);
- if (idlen > silc_buffer_len(&buffer) || idlen > SILC_PACKET_MAX_ID_LEN)
+ if (idlen > buffer.len || idlen > SILC_PACKET_MAX_ID_LEN)
goto err;
ret = silc_buffer_unformat(&buffer,
- SILC_STR_DATA(&id_data, idlen),
+ SILC_STR_UI_XNSTRING(&id_data, idlen),
SILC_STR_END);
if (ret == -1)
goto err;
- ret_id->type = type;
-
- if (type == SILC_ID_CLIENT) {
- if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.client_id,
- sizeof(SilcClientID)))
- goto err;
- } else if (type == SILC_ID_SERVER) {
- if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.server_id,
- sizeof(SilcServerID)))
- goto err;
- } else {
- if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.channel_id,
- sizeof(SilcChannelID)))
- goto err;
- }
+ id = silc_id_str2id(id_data, idlen, type);
+
+ if (ret_type)
+ *ret_type = type;
- return TRUE;
+ return id;
err:
SILC_LOG_DEBUG(("Error parsing ID payload"));
- return FALSE;
+ return NULL;
}
/* Encodes ID Payload */
SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
{
SilcBuffer buffer;
- unsigned char id_data[32];
+ unsigned char *id_data;
SilcUInt32 len;
- if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &len))
- return NULL;
+ id_data = silc_id_id2str(id, type);
+ len = silc_id_get_len(id, type);
buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
len, type);
+ silc_free(id_data);
return buffer;
}
silc_buffer_format(buffer,
SILC_STR_UI_SHORT(type),
SILC_STR_UI_SHORT(id_len),
- SILC_STR_DATA(id, id_len),
+ SILC_STR_UI_XNSTRING(id, id_len),
SILC_STR_END);
return buffer;
}
/* Get ID */
-SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
- SilcUInt32 ret_id_len)
+void *silc_id_payload_get_id(SilcIDPayload payload)
{
- if (!payload)
- return FALSE;
- return silc_id_str2id(payload->id, payload->len, payload->type,
- ret_id, ret_id_len);
+ return payload ? silc_id_str2id(payload->id, payload->len,
+ payload->type) : NULL;
}
/* Get raw ID data. Data is duplicated. */
/* Converts ID to string. */
-SilcBool silc_id_id2str(const void *id, SilcIdType type,
- unsigned char *ret_id, SilcUInt32 ret_id_size,
- SilcUInt32 *ret_id_len)
+unsigned char *silc_id_id2str(const void *id, SilcIdType type)
{
+ 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 FALSE;
+ return NULL;
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 TRUE;
+ return ret_id;
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,
+ memcpy(&ret_id[client_id->ip.data_len + 1], client_id->hash,
CLIENTID_HASH_LEN);
- return TRUE;
+ return ret_id;
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 TRUE;
+ return ret_id;
break;
}
- return FALSE;
+ return NULL;
}
/* Converts string to a ID */
-SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
- SilcIdType type, void *ret_id, SilcUInt32 ret_id_size)
+void *silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
+ SilcIdType type)
{
if (id_len > SILC_PACKET_MAX_ID_LEN)
- return FALSE;
+ return NULL;
switch(type) {
case SILC_ID_SERVER:
{
- SilcServerID *server_id = ret_id;
+ SilcServerID *server_id;
if (id_len != ID_SERVER_LEN_PART + 4 &&
id_len != ID_SERVER_LEN_PART + 16)
- return FALSE;
+ return NULL;
- if (ret_id_size < sizeof(SilcServerID))
- return FALSE;
-
- memset(ret_id, 0, ret_id_size);
+ server_id = silc_calloc(1, sizeof(*server_id));
+ if (!server_id)
+ return NULL;
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);
SILC_GET16_MSB(server_id->port, &id[server_id->ip.data_len]);
SILC_GET16_MSB(server_id->rnd, &id[server_id->ip.data_len + 2]);
- return TRUE;
+ return server_id;
}
break;
case SILC_ID_CLIENT:
{
- SilcClientID *client_id = ret_id;
+ SilcClientID *client_id;
if (id_len != ID_CLIENT_LEN_PART + 4 &&
id_len != ID_CLIENT_LEN_PART + 16)
- return FALSE;
-
- if (ret_id_size < sizeof(SilcClientID))
- return FALSE;
+ return NULL;
- memset(ret_id, 0, ret_id_size);
+ client_id = silc_calloc(1, sizeof(*client_id));
+ if (!client_id)
+ return NULL;
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);
client_id->rnd = id[client_id->ip.data_len];
- memcpy(client_id->hash, &id[client_id->ip.data_len + 1],
+ memcpy(client_id->hash, &id[client_id->ip.data_len + 1],
CLIENTID_HASH_LEN);
- return TRUE;
+ return client_id;
}
break;
case SILC_ID_CHANNEL:
{
- SilcChannelID *channel_id = ret_id;
+ SilcChannelID *channel_id;
if (id_len != ID_CHANNEL_LEN_PART + 4 &&
id_len != ID_CHANNEL_LEN_PART + 16)
- return FALSE;
+ return NULL;
- if (ret_id_size < sizeof(SilcChannelID))
- return FALSE;
-
- memset(ret_id, 0, ret_id_size);
+ channel_id = silc_calloc(1, sizeof(*channel_id));
+ if (!channel_id)
+ return NULL;
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);
SILC_GET16_MSB(channel_id->port, &id[channel_id->ip.data_len]);
SILC_GET16_MSB(channel_id->rnd, &id[channel_id->ip.data_len + 2]);
- return TRUE;
+ return channel_id;
}
break;
}
- return FALSE;
+ return NULL;
}
/* Returns length of the ID */
/*
-
+
silcid.h
-
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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
#ifndef SILCID_H
#define SILCID_H
-/* The ID Lenghts. These are IPv4 based and should be noted if used directly
- that these cannot be used with IPv6. */
-#define SILC_ID_SERVER_LEN (64 / 8)
-#define SILC_ID_CLIENT_LEN (128 / 8)
-#define SILC_ID_CHANNEL_LEN (64 / 8)
-
-#define CLIENTID_HASH_LEN (88 / 8) /* Client ID's 88 bit MD5 hash */
-
/****d* silccore/SilcIDAPI/SilcIdType
*
* NAME
- *
+ *
* typedef SilcUInt16 SilcIdType;
*
* DESCRIPTION
#define SILC_ID_CHANNEL 3
/***/
-/****s* silccore/SilcIDAPI/SilcIDIP
+/* The ID Lenghts. These are IPv4 based and should be noted if used directly
+ that these cannot be used with IPv6. */
+#define SILC_ID_SERVER_LEN (64 / 8)
+#define SILC_ID_CLIENT_LEN (128 / 8)
+#define SILC_ID_CHANNEL_LEN (64 / 8)
+
+#define CLIENTID_HASH_LEN (88 / 8) /* Client ID's 88 bit MD5 hash */
+
+/****s* silccore/SilcIDAPI/SilcIDPayload
*
* NAME
+ *
+ * typedef struct SilcIDPayloadStruct *SilcIDPayload;
+ *
+ * DESCRIPTION
+ *
+ * This context is the actual ID Payload and is allocated by
+ * silc_id_payload_parse and given as argument usually to all
+ * silc_id_payload_* functions. It is freed by the function
+ * silc_id_payload_free.
+ *
+ ***/
+typedef struct SilcIDPayloadStruct *SilcIDPayload;
+
+/* Prototypes */
+
+/****f* silccore/SilcIDAPI/silc_id_payload_parse
+ *
+ * SYNOPSIS
+ *
+ * SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
+ * SilcUInt32 payload_len);
+ *
+ * DESCRIPTION
+ *
+ * Parses buffer and return ID payload into payload structure. The
+ * `buffer' is raw payload buffer. The caller must free the returned
+ * payload.
+ *
+ ***/
+SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
+ SilcUInt32 payload_len);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_parse_id
+ *
+ * SYNOPSIS
+ *
+ * void *silc_id_payload_parse_id(const unsigned char *data,
+ * SilcUInt32 len,
+ * SilcIdType *type);
+ *
+ * DESCRIPTION
+ *
+ * Return ID directly from the raw ID Payload data buffer. The
+ * caller must free the returned ID.
+ *
+ ***/
+void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
+ SilcIdType *type);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_encode
+ *
+ * SYNOPSIS
+ *
+ * SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type);
+ *
+ * DESCRIPTION
+ *
+ * Encodes ID Payload. The `id' is the ID of the type `type' to put
+ * into the payload. Returns the encoded payload buffer.
+ *
+ ***/
+SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_encode_data
+ *
+ * SYNOPSIS
+ *
+ * SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
+ * uin32 id_len, SilcIdType type);
+ *
+ * DESCRIPTION
+ *
+ * Encodes ID Payload. The `id' is raw ID data of the length of `id_len'
+ * of type of `type'. Returns the encoded payload buffer.
+ *
+ ***/
+SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
+ SilcUInt32 id_len, SilcIdType type);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_id_payload_free(SilcIDPayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Frees the ID Payload and all data in it.
+ *
+ ***/
+void silc_id_payload_free(SilcIDPayload payload);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_get_type
+ *
+ * SYNOPSIS
+ *
+ * SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Returns the ID type from the ID Payload. The type tells the
+ * type of the ID in the payload.
+ *
+ ***/
+SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_get_id
+ *
+ * SYNOPSIS
*
+ * void *silc_id_payload_get_id(SilcIDPayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Returns the ID in the ID Payload. The caller must free the
+ * returned ID.
+ *
+ ***/
+void *silc_id_payload_get_id(SilcIDPayload payload);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_get_data
+ *
+ * SYNOPSIS
+ *
+ * unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Returns the raw ID data from the ID Payload. The data is duplicated
+ * and the caller must free it.
+ *
+ ***/
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
+
+/****f* silccore/SilcIDAPI/silc_id_payload_get_len
+ *
+ * SYNOPSIS
+ *
+ * SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Returns the length of the ID in the ID Payload.
+ *
+ ***/
+SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload);
+
+/****s* silccore/SilcIDAPI/SilcIDIP
+ *
+ * NAME
+ *
* typedef struct { ... } SilcIDIP;
*
* DESCRIPTION
/****s* silccore/SilcIDAPI/SilcServerID
*
* NAME
- *
+ *
* typedef struct { ... } SilcServerID;
*
* DESCRIPTION
*
* 64 or 160 bit SilcServerID structure:
- *
+ *
* n bit IP address
* 16 bit port
* 16 bit random number
/****s* silccore/SilcIDAPI/SilcClientID
*
* NAME
- *
+ *
* typedef struct { ... } SilcClientID;
*
* DESCRIPTION
/****s* silccore/SilcIDAPI/SilcChannelID
*
* NAME
- *
+ *
* typedef struct { ... } SilcChannelID;
*
* DESCRIPTION
} SilcChannelID;
/***/
-/****s* silccore/SilcIDAPI/SilcID
- *
- * NAME
- *
- * typedef struct { ... } SilcID;
- *
- * DESCRIPTION
- *
- * The generic ID structure that can represent SilcClientID, SilcServerID
- * and SilcChannelID. The silc_id_payload_parse_id returns the ID in the
- * SilcID structure. Other routines except either SilcClientID,
- * SilcServerID or SilcChannelID as a void pointer.
- *
- * SOURCE
- */
-typedef struct {
- union {
- SilcServerID server_id;
- SilcChannelID channel_id;
- SilcClientID client_id;
- } u;
- SilcIdType type;
-} SilcID;
-/***/
-
/* Macros */
-/****d* silccore/SilcIDAPI/SILC_ID_GET_ID
- *
- * NAME
- *
- * #define SILC_ID_GET_ID ...
- *
- * DESCRIPTION
- *
- * Returns the ID type specific pointer from the SilcID structure. As
- * the SilcID is able to house all types of IDs this macro can be used
- * to get the specific ID from the structure by its type.
- *
- * SOURCE
- */
-#define SILC_ID_GET_ID(id) \
- ((id).type == SILC_ID_CLIENT ? (void *)&(id).u.client_id : \
- (id).type == SILC_ID_SERVER ? (void *)&(id).u.server_id : \
- (void *)&(id).u.channel_id)
-/***/
-
/****d* silccore/SilcIDAPI/SILC_ID_COMPARE
*
* NAME
- *
+ *
* #define SILC_ID_COMPARE ...
*
* DESCRIPTION
/****d* silccore/SilcIDAPI/SILC_ID_CLIENT_COMPARE
*
* NAME
- *
+ *
* #define SILC_ID_CLIENT_COMPARE ...
*
* DESCRIPTION
/****d* silccore/SilcIDAPI/SILC_ID_SERVER_COMPARE
*
* NAME
- *
+ *
* #define SILC_ID_SERVER_COMPARE ...
*
* DESCRIPTION
/****d* silccore/SilcIDAPI/SILC_ID_CHANNEL_COMPARE
*
* NAME
- *
+ *
* #define SILC_ID_CHANNEL_COMPARE ...
*
* DESCRIPTION
/****d* silccore/SilcIDAPI/SILC_ID_COMPARE_TYPE
*
* NAME
- *
+ *
* #define SILC_ID_COMPARE_TYPE ...
*
* DESCRIPTION
/****d* silccore/SilcIDAPI/SILC_ID_COMPARE_HASH
*
* NAME
- *
+ *
* #define SILC_ID_COMPARE_HASH ...
*
* DESCRIPTION
(!memcmp((id1)->hash, (id2)->hash, CLIENTID_HASH_LEN))
/***/
-/****s* silccore/SilcIDAPI/SilcIDPayload
- *
- * NAME
- *
- * typedef struct SilcIDPayloadStruct *SilcIDPayload;
- *
- * DESCRIPTION
- *
- * This context is the actual ID Payload and is allocated by
- * silc_id_payload_parse and given as argument usually to all
- * silc_id_payload_* functions. It is freed by the function
- * silc_id_payload_free.
- *
- ***/
-typedef struct SilcIDPayloadStruct *SilcIDPayload;
-
/* Prototypes */
-/****f* silccore/SilcIDAPI/silc_id_payload_parse
- *
- * SYNOPSIS
- *
- * SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
- * SilcUInt32 payload_len);
- *
- * DESCRIPTION
- *
- * Parses buffer and return ID payload into payload structure. The
- * `buffer' is raw payload buffer. The caller must free the returned
- * payload.
- *
- ***/
-SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
- SilcUInt32 payload_len);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_parse_id
- *
- * SYNOPSIS
- *
- * SilcBool silc_id_payload_parse_id(const unsigned char *data,
- * SilcUInt32 len, SilcID *ret_id);
- *
- * DESCRIPTION
- *
- * Return ID directly from the raw ID Payload data buffer. This does
- * not allocate any memory.
- *
- ***/
-SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
- SilcID *ret_id);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_encode
- *
- * SYNOPSIS
- *
- * SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type);
- *
- * DESCRIPTION
- *
- * Encodes ID Payload. The `id' is the ID of the type `type' to put
- * into the payload. Returns the encoded payload buffer.
- *
- ***/
-SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_encode_data
- *
- * SYNOPSIS
- *
- * SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
- * uin32 id_len, SilcIdType type);
- *
- * DESCRIPTION
- *
- * Encodes ID Payload. The `id' is raw ID data of the length of `id_len'
- * of type of `type'. Returns the encoded payload buffer.
- *
- ***/
-SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
- SilcUInt32 id_len, SilcIdType type);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_free
- *
- * SYNOPSIS
- *
- * void silc_id_payload_free(SilcIDPayload payload);
- *
- * DESCRIPTION
- *
- * Frees the ID Payload and all data in it.
- *
- ***/
-void silc_id_payload_free(SilcIDPayload payload);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_get_type
- *
- * SYNOPSIS
- *
- * SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
- *
- * DESCRIPTION
- *
- * Returns the ID type from the ID Payload. The type tells the
- * type of the ID in the payload.
- *
- ***/
-SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_get_id
- *
- * SYNOPSIS
- *
- * SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
- * SilcUInt32 ret_id_len);
- *
- * DESCRIPTION
- *
- * Returns the ID in the ID Payload. This does not allocate any memory.
- *
- ***/
-SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
- SilcUInt32 ret_id_len);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_get_data
- *
- * SYNOPSIS
- *
- * unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
- *
- * DESCRIPTION
- *
- * Returns the raw ID data from the ID Payload. The data is duplicated
- * and the caller must free it.
- *
- ***/
-unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
-
-/****f* silccore/SilcIDAPI/silc_id_payload_get_len
- *
- * SYNOPSIS
- *
- * SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload);
- *
- * DESCRIPTION
- *
- * Returns the length of the ID in the ID Payload.
- *
- ***/
-SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload);
-
/****f* silccore/SilcIDAPI/silc_id_id2str
*
* SYNOPSIS
*
- * SilcBool silc_id_id2str(const void *id, SilcIdType type,
- * unsigned char *ret_id, SilcUInt32 ret_id_size,
- * SilcUInt32 *ret_id_len);
+ * unsigned char *silc_id_id2str(const void *id, SilcIdType type);
*
* 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. This does
- * not allocate any memory.
+ * convert the ID's to data for inclusion in the packets. Use the
+ * silc_id_get_len to get the length of the ID.
*
***/
-SilcBool silc_id_id2str(const void *id, SilcIdType type,
- unsigned char *ret_id, SilcUInt32 ret_id_size,
- SilcUInt32 *ret_id_len);
+unsigned char *silc_id_id2str(const void *id, SilcIdType type);
/****f* silccore/SilcIDAPI/silc_id_str2id
*
* SYNOPSIS
*
- * SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
- * SilcIdType type, void *ret_id,
- * SilcUInt32 ret_id_size);
+ * void *silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
+ * SilcIdType type);
*
* 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. This
- * does not allocate any memory.
+ * ID out of data that has been taken for example from packet.
*
***/
-SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
- SilcIdType type, void *ret_id, SilcUInt32 ret_id_size);
+void *silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
+ SilcIdType type);
/****f* silccore/SilcIDAPI/silc_id_get_len
*
--- /dev/null
+/*
+
+ silcidcache.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ 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
+ 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 "silcincludes.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);
+
+/*
+ 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.
+
+ SilcHashTable context_table
+
+ Hash table using the context as the key.
+
+ SilcIDCacheDestructor destructor
+
+ 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.
+
+ SilcIdType id_type
+
+ Indicates the type of the ID's this cache holds.
+
+*/
+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;
+};
+
+/*
+ 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. :)
+
+ 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. */
+
+SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
+ SilcIDCacheDestructor destructor,
+ void *destructor_context,
+ bool delete_id, bool delete_name)
+{
+ SilcIDCache cache;
+
+ SILC_LOG_DEBUG(("Allocating new cache"));
+
+ 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);
+ cache->name_table = silc_hash_table_alloc(count, silc_hash_utf8_string, NULL,
+ silc_hash_utf8_compare, NULL,
+ NULL, NULL, TRUE);
+ cache->context_table = silc_hash_table_alloc(count, silc_hash_ptr, NULL,
+ 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;
+
+ if (!cache->id_table || !cache->name_table || !cache->context_table) {
+ if (cache->id_table)
+ silc_hash_table_free(cache->id_table);
+ if (cache->name_table)
+ silc_hash_table_free(cache->name_table);
+ if (cache->context_table)
+ silc_hash_table_free(cache->context_table);
+ silc_free(cache);
+ return NULL;
+ }
+
+ return cache;
+}
+
+/* Frees ID cache object and cache entries */
+
+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);
+ }
+}
+
+/* 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. */
+
+bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
+ void *context, int expire, SilcIDCacheEntry *ret)
+{
+ SilcIDCacheEntry c;
+
+ SILC_LOG_DEBUG(("Adding cache entry"));
+
+ /* Allocate new cache entry */
+ c = silc_calloc(1, sizeof(*c));
+ if (!c)
+ return FALSE;
+ c->id = id;
+ c->name = name;
+ c->expire = expire;
+ c->context = context;
+
+ /* Add the new entry to the hash tables */
+
+ if (id)
+ silc_hash_table_add(cache->id_table, id, c);
+ if (name)
+ silc_hash_table_add(cache->name_table, name, c);
+ if (context)
+ silc_hash_table_add(cache->context_table, context, c);
+
+ if (ret)
+ *ret = c;
+
+ return TRUE;
+}
+
+/* Destructor for the ID Cache entry */
+
+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);
+ }
+}
+
+/* Delete cache entry from cache. */
+
+bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
+{
+ 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;
+}
+
+/* Deletes ID cache entry by ID. */
+
+bool silc_idcache_del_by_id(SilcIDCache cache, void *id)
+{
+ SilcIDCacheEntry c;
+
+ if (!silc_hash_table_find(cache->id_table, id, NULL, (void *)&c))
+ return FALSE;
+
+ return silc_idcache_del(cache, c);
+}
+
+/* Same as above but with specific hash and comparison functions. If the
+ functions are NULL then default values are used. */
+
+bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
+ SilcHashFunction hash,
+ void *hash_context,
+ SilcHashCompare compare,
+ void *compare_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))
+ 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;
+}
+
+/* Deletes ID cache entry by context. */
+
+bool silc_idcache_del_by_context(SilcIDCache cache, void *context)
+{
+ SilcIDCacheEntry c;
+ bool ret = FALSE;
+
+ SILC_LOG_DEBUG(("Deleting cache entry"));
+
+ 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;
+}
+
+/* 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;
+}
+
+static void silc_idcache_destructor_dummy(void *key, void *context,
+ void *user_context)
+{
+ /* Dummy - nothing */
+}
+
+/* Foreach callback fro silc_idcache_purge. */
+
+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);
+ }
+ }
+}
+
+/* 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. */
+
+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;
+
+ /* 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);
+ }
+
+ 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);
+}
+
+/* Returns all cache entrys from the ID cache to the `ret' ID Cache List. */
+
+bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret)
+{
+ SilcIDCacheList list;
+
+ if (!ret)
+ return TRUE;
+
+ list = silc_idcache_list_alloc();
+ if (!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);
+ return FALSE;
+ }
+
+ *ret = list;
+
+ return TRUE;
+}
+
+/* Find ID Cache entry by ID. May return multiple entries. */
+
+bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
+ SilcIDCacheList *ret)
+{
+ SilcIDCacheList list;
+
+ list = silc_idcache_list_alloc();
+ if (!list)
+ return FALSE;
+
+ if (!ret)
+ return TRUE;
+
+ silc_hash_table_find_foreach(cache->id_table, id,
+ silc_idcache_get_all_foreach, list);
+
+ if (silc_idcache_list_count(list) == 0) {
+ silc_idcache_list_free(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. */
+
+bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
+ SilcHashFunction hash,
+ void *hash_context,
+ SilcHashCompare compare,
+ void *compare_context,
+ 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);
+}
+
+/* Finds cache entry by context. */
+
+bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
+ SilcIDCacheEntry *ret)
+{
+ return silc_hash_table_find(cache->context_table, context, NULL,
+ (void *)ret);
+}
+
+/* Find ID Cache entry by name. Returns list of cache entries. */
+
+bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
+ SilcIDCacheList *ret)
+{
+ SilcIDCacheList list;
+
+ list = silc_idcache_list_alloc();
+ if (!list)
+ return FALSE;
+
+ if (!ret)
+ return TRUE;
+
+ silc_hash_table_find_foreach(cache->name_table, name,
+ silc_idcache_get_all_foreach, list);
+
+ if (silc_idcache_list_count(list) == 0) {
+ silc_idcache_list_free(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)
+{
+ 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);
+ }
+}
--- /dev/null
+/*
+
+ silcidcache.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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
+ 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* silccore/SILC ID Cache Interface
+ *
+ * DESCRIPTION
+ *
+ * SILC ID Cache is an cache for all kinds of ID's used in the SILC
+ * protocol. Application can save here the ID's it uses and the interface
+ * provides fast retrieval of the ID's from the cache.
+ *
+ ***/
+
+#ifndef SILCIDCACHE_H
+#define SILCIDCACHE_H
+
+/****s* silccore/SilcIDCacheAPI/SilcIDCacheEntry
+ *
+ * NAME
+ *
+ * typedef struct { ... } 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.
+ *
+ * SOURCE
+ */
+typedef struct {
+ void *id;
+ char *name;
+ SilcUInt32 expire;
+ void *context;
+} *SilcIDCacheEntry;
+/***/
+
+/****s* silccore/SilcIDCacheAPI/SilcIDCache
+ *
+ * NAME
+ *
+ * typedef struct SilcIDCacheStruct *SilcIDCache;
+ *
+ * DESCRIPTION
+ *
+ * This context is the actual ID Cache and is allocated by
+ * silc_idcache_alloc and given as argument usually to all
+ * silc_idcache_* functions. It is freed by the
+ * silc_idcache_free function.
+ *
+ ***/
+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);
+ *
+ * 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.
+ *
+ ***/
+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)
+
+/* Prototypes */
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_alloc
+ *
+ * SYNOPSIS
+ *
+ * SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
+ * SilcIDCacheDestructor destructor,
+ * void *destructor_context,
+ * bool delete_id, bool delete_name);
+ *
+ * DESCRIPTION
+ *
+ * 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.
+ *
+ * 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);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_idcache_free(SilcIDCache cache);
+ *
+ * DESCRIPTION
+ *
+ * Frees ID cache object and all cache entries.
+ *
+ ***/
+void silc_idcache_free(SilcIDCache cache);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_add
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
+ * void *context, int expire, SilcIDCacheEntry *ret);
+ *
+ * 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.
+ *
+ * The `name', `id' and `context' pointers will be saved 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.
+ *
+ ***/
+bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
+ void *context, int expire, SilcIDCacheEntry *ret);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_del
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
+ *
+ * DESCRIPTION
+ *
+ * Delete cache entry from cache. Returns TRUE if the entry was deleted.
+ * The destructor function is not called.
+ *
+ ***/
+bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
+
+/****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);
+ *
+ * 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.
+ *
+ ***/
+bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
+ SilcHashFunction hash,
+ void *hash_context,
+ SilcHashCompare compare,
+ void *compare_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);
+ *
+ * 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.
+ *
+ ***/
+bool silc_idcache_purge(SilcIDCache cache);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_by_context
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_purge_by_context(SilcIDCache cache, void *context);
+ *
+ * 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.
+ *
+ ***/
+bool silc_idcache_purge_by_context(SilcIDCache cache, void *context);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_get_all
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret);
+ *
+ * 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.
+ *
+ ***/
+bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_id
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
+ * SilcIDCacheList *ret);
+ *
+ * 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
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
+ * SilcIDCacheEntry *ret);
+ *
+ * DESCRIPTION
+ *
+ * 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(SilcIDCache cache, void *id,
+ SilcIDCacheEntry *ret);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_id_one_ext
+ *
+ * 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);
+ *
+ * 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.
+ *
+ ***/
+bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
+ SilcHashFunction hash,
+ void *hash_context,
+ SilcHashCompare compare,
+ void *compare_context,
+ SilcIDCacheEntry *ret);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_context
+ *
+ * SYNOPSIS
+ *
+ * bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
+ * SilcIDCacheEntry *ret);
+ *
+ * DESCRIPTION
+ *
+ * Find cache entry by user specified context. Returns TRUE if the
+ * entry was found.
+ *
+ ***/
+bool 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);
+ *
+ * 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.
+ *
+ ***/
+bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
+ SilcIDCacheList *ret);
+
+/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_name_one
+ *
+ * SYNOPSIS
+ *
+ * bool 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
+ * 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.
+ *
+ ***/
+void silc_idcache_list_free(SilcIDCacheList list);
+
+#endif
/*
- silcmessage.c
+ silcmessage.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 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
private messages. */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcmessage.h"
-/*************************** Types and definitions **************************/
+/******************************************************************************
+
+ Message Payload
+
+******************************************************************************/
/* Calculates padding length for message payload */
#define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
/* Header length plus maximum padding length */
#define SILC_MESSAGE_HLEN 6 + 16
-/* Maximum message length */
-#define SILC_MESSAGE_MAX_LEN SILC_PACKET_MAX_LEN - SILC_MESSAGE_HLEN - 16
-
-/* Payload encoding context */
-typedef struct {
- SilcMessageFlags flags;
- SilcPublicKey public_key;
- SilcPrivateKey private_key;
- SilcHash hash;
- SilcCipher cipher;
- SilcHmac hmac;
- unsigned char *iv;
- SilcUInt16 payload_len;
- SilcID *sid;
- SilcID *rid;
-} SilcMessageEncode;
-
-
-/************************* Static utility functions *************************/
-
/* Returns the data length that fits to the packet. If data length is too
big it will be truncated to fit to the payload. */
-
-static inline
-SilcUInt32 silc_message_payload_datalen(SilcUInt32 data_len,
- SilcUInt32 header_len,
- SilcUInt32 flags,
- SilcPublicKey public_key,
- SilcPrivateKey private_key)
-{
- SilcUInt32 pklen = (flags & SILC_MESSAGE_FLAG_SIGNED && public_key ?
- silc_pkcs_public_key_get_len(public_key) : 0);
- SilcUInt32 prlen = (flags & SILC_MESSAGE_FLAG_SIGNED ?
- silc_pkcs_private_key_get_len(private_key) / 8 : 0);
- SilcUInt32 dlen = data_len + SILC_MESSAGE_HLEN + header_len + pklen + prlen;
-
- if (silc_unlikely(dlen > SILC_MESSAGE_MAX_LEN))
- data_len -= (dlen - SILC_MESSAGE_MAX_LEN);
-
- return data_len;
-}
-
-/* Free signed payload */
-
-static void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
-{
- if (sig->sign_data) {
- memset(sig->sign_data, 0, sig->sign_len);
- silc_free(sig->sign_data);
- }
- silc_free(sig->pk_data);
-}
-
-/* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
-
-static SilcBool
-silc_message_signed_payload_parse(const unsigned char *data,
- SilcUInt32 data_len,
- SilcMessageSignedPayload sig)
-{
- SilcBufferStruct buffer;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
-
- SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len);
-
- silc_buffer_set(&buffer, (unsigned char *)data, data_len);
-
- /* Parse the payload */
- ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI_SHORT(&sig->pk_len),
- SILC_STR_UI_SHORT(&sig->pk_type),
- SILC_STR_END);
- if (ret == -1 || sig->pk_len > data_len - 4) {
- SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
- "Payload"));
- return FALSE;
- }
-
- silc_buffer_pull(&buffer, 4);
- ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
- sig->pk_len),
- SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
- &sig->sign_len),
- SILC_STR_END);
- if (ret == -1 || sig->sign_len > silc_buffer_len(&buffer) -
- sig->pk_len - 2) {
- silc_message_signed_payload_free(sig);
- SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
- return FALSE;
- }
- silc_buffer_push(&buffer, 4);
-
- /* Signature must be provided */
- if (sig->sign_len < 1) {
- SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
- "Payload"));
- silc_message_signed_payload_free(sig);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
-
-static SilcBuffer
-silc_message_signed_encode_data(const unsigned char *message_payload,
- SilcUInt32 message_payload_len,
- unsigned char *pk,
- SilcUInt32 pk_len, SilcUInt32 pk_type)
-{
- SilcBuffer sign;
-
- sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
- if (!sign)
- return NULL;
-
- silc_buffer_format(sign,
- SILC_STR_UI_XNSTRING(message_payload,
- message_payload_len),
- SILC_STR_UI_SHORT(pk_len),
- SILC_STR_UI_SHORT(pk_type),
- SILC_STR_END);
-
- if (pk && pk_len) {
- silc_buffer_pull(sign, message_payload_len + 4);
- silc_buffer_format(sign,
- SILC_STR_UI_XNSTRING(pk, pk_len),
- SILC_STR_END);
- silc_buffer_push(sign, message_payload_len + 4);
- }
-
- return sign;
-}
-
-/* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
- signature. */
-
-static SilcBuffer
-silc_message_signed_payload_encode(const unsigned char *message_payload,
- SilcUInt32 message_payload_len,
- SilcPublicKey public_key,
- SilcPrivateKey private_key,
- SilcHash hash)
-{
- SilcBuffer buffer, sign;
- unsigned char auth_data[2048 + 1];
- SilcUInt32 auth_len;
- unsigned char *pk = NULL;
- SilcUInt32 pk_len = 0;
- SilcUInt16 pk_type;
-
- if (!message_payload || !message_payload_len || !private_key || !hash)
- return NULL;
-
- if (public_key) {
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
- if (!pk)
- return NULL;
- }
- pk_type = silc_pkcs_get_type(private_key);
-
- /* Encode the data to be signed */
- sign = silc_message_signed_encode_data(message_payload,
- message_payload_len,
- pk, pk_len, pk_type);
- if (!sign) {
- silc_free(pk);
- return NULL;
- }
-
- /* Sign the buffer */
-
- /* Compute the hash and the signature. */
- if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
- auth_data, sizeof(auth_data) - 1, &auth_len,
- TRUE, hash)) {
- SILC_LOG_ERROR(("Could not compute signature"));
- silc_buffer_clear(sign);
- silc_buffer_free(sign);
- silc_free(pk);
- return NULL;
- }
-
- /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
-
- buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
- if (!buffer) {
- silc_buffer_clear(sign);
- silc_buffer_free(sign);
- memset(auth_data, 0, sizeof(auth_data));
- silc_free(pk);
- return NULL;
- }
-
- silc_buffer_format(buffer,
- SILC_STR_UI_SHORT(pk_len),
- SILC_STR_UI_SHORT(pk_type),
- SILC_STR_END);
-
- if (pk_len && pk) {
- silc_buffer_pull(buffer, 4);
- silc_buffer_format(buffer,
- SILC_STR_UI_XNSTRING(pk, pk_len),
- SILC_STR_END);
- silc_buffer_push(buffer, 4);
- }
-
- silc_buffer_pull(buffer, 4 + pk_len);
- silc_buffer_format(buffer,
- SILC_STR_UI_SHORT(auth_len),
- SILC_STR_UI_XNSTRING(auth_data, auth_len),
- SILC_STR_END);
- silc_buffer_push(buffer, 4 + pk_len);
-
- SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer));
-
- memset(auth_data, 0, sizeof(auth_data));
- silc_buffer_clear(sign);
- silc_buffer_free(sign);
- silc_free(pk);
-
- return buffer;
-}
-
-
-/***************************** Payload parsing ******************************/
-
-/* Decrypts the Message Payload. The `data' is the actual Message Payload. */
-
-SilcBool silc_message_payload_decrypt(unsigned char *data,
- size_t data_len,
- SilcBool private_message,
- SilcBool static_key,
- SilcCipher cipher,
- SilcHmac hmac,
- unsigned char *sender_id,
- SilcUInt32 sender_id_len,
- unsigned char *receiver_id,
- SilcUInt32 receiver_id_len,
- SilcBool check_mac)
+#define SILC_MESSAGE_DATALEN(data_len, header_len) \
+ ((data_len + SILC_MESSAGE_HLEN + header_len) > \
+ SILC_PACKET_MAX_LEN ? \
+ data_len - ((data_len + SILC_MESSAGE_HLEN + header_len) - \
+ SILC_PACKET_MAX_LEN) : data_len)
+
+/* Message Payload structure. Contents of this structure is parsed
+ from SILC packets. */
+struct SilcMessagePayloadStruct {
+ SilcMessageFlags flags;
+ SilcUInt16 data_len;
+ SilcUInt16 pad_len;
+ SilcUInt16 iv_len;
+ unsigned char *data;
+ unsigned char *pad;
+ unsigned char *iv;
+ unsigned char *mac;
+ SilcMessageSignedPayload sig;
+};
+
+/* Decrypts the Message Payload. The `data' is the actual Message Payload */
+
+bool silc_message_payload_decrypt(unsigned char *data,
+ size_t data_len,
+ bool private_message,
+ bool static_key,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ bool check_mac)
{
SilcUInt32 mac_len, iv_len = 0, block_len;
- SilcUInt16 len, totlen;
- unsigned char mac[32], *ivp;
-
+ SilcUInt16 len, totlen, dlen;
+ unsigned char mac[32], *ivp, *dec;
+
mac_len = silc_hmac_len(hmac);
- block_len = silc_cipher_get_block_len(cipher);
- /* IV is present for all channel messages, and private messages when
+ /* IV is present for all channel messages, and private messages when
static key (pre-shared key) is used. */
if (!private_message || (private_message && static_key))
- iv_len = block_len;
+ iv_len = silc_cipher_get_block_len(cipher);
- if (silc_unlikely(data_len < (mac_len + iv_len + block_len)))
+ if (data_len <= (mac_len + iv_len))
return FALSE;
- if (silc_likely(check_mac)) {
+ if (check_mac) {
/* Check the MAC of the message */
SILC_LOG_DEBUG(("Checking message MAC"));
silc_hmac_init(hmac);
silc_hmac_update(hmac, data, data_len - mac_len);
- silc_hmac_update(hmac, sender_id, sender_id_len);
- silc_hmac_update(hmac, receiver_id, receiver_id_len);
silc_hmac_final(hmac, mac, &mac_len);
- if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
-#if 0
+ if (memcmp(data + (data_len - mac_len), mac, mac_len)) {
SILC_LOG_DEBUG(("Message MAC does not match"));
return FALSE;
-#else
- /* Check for old style message MAC. Remove this check at some point. */
- silc_hmac_init(hmac);
- silc_hmac_update(hmac, data, data_len - mac_len);
- silc_hmac_final(hmac, mac, &mac_len);
- if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
- SILC_LOG_DEBUG(("Message MAC does not match"));
-#endif
- return FALSE;
- }
}
SILC_LOG_DEBUG(("MAC is Ok"));
}
- /* Decrypt first only one block to get the header and then rest of
- the data. This is done because there might be unencrypted data at
- the end and we don't know the encrypted length yet. */
+ /* Decrypt the entire buffer into allocated decryption buffer, since we
+ do not reliably know its encrypted length (it may include unencrypted
+ data at the end). */
/* Get pointer to the IV */
ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
silc_cipher_get_iv(cipher));
- /* Decrypt block */
- if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
- ivp))) {
- SILC_ASSERT(FALSE);
- return FALSE;
- }
+ /* Allocate buffer for decryption. Since there might be unencrypted
+ data at the end, it might not be multiple by block size, make it so. */
+ block_len = silc_cipher_get_block_len(cipher);
+ dlen = data_len - iv_len - mac_len;
+ if (dlen & (block_len - 1))
+ dlen += SILC_MESSAGE_PAD(dlen);
+ if (dlen > data_len - iv_len - mac_len)
+ dlen -= block_len;
+ dec = silc_malloc(dlen);
+
+ /* Decrypt */
+ silc_cipher_decrypt(cipher, data, dec, dlen, ivp);
+
+ /* Now verify the true length of the payload and copy the decrypted
+ part over the original data. First get data length, and then padding
+ length from the decrypted data. Then, copy over the original data. */
- /* Get the payload length and decrypt rest */
totlen = 2;
- SILC_GET16_MSB(len, data + totlen);
+ SILC_GET16_MSB(len, dec + totlen);
totlen += 2 + len;
- if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
+ if (totlen + iv_len + mac_len + 2 > data_len) {
+ memset(dec, 0, dlen);
+ silc_free(dec);
return FALSE;
- totlen += 2;
- if (totlen >= block_len)
- if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
- data + block_len,
- (totlen - block_len) +
- SILC_MESSAGE_PAD(totlen), ivp))) {
- SILC_ASSERT(FALSE);
- return FALSE;
- }
+ }
+ SILC_GET16_MSB(len, dec + totlen);
+ totlen += 2 + len;
+ if (totlen + iv_len + mac_len > data_len) {
+ memset(dec, 0, dlen);
+ silc_free(dec);
+ return FALSE;
+ }
+
+ memcpy(data, dec, totlen);
+ memset(dec, 0, dlen);
+ silc_free(dec);
return TRUE;
}
/* Parses Message Payload returning new payload structure. This also
decrypts it and checks the MAC. */
-SilcMessagePayload
+SilcMessagePayload
silc_message_payload_parse(unsigned char *payload,
SilcUInt32 payload_len,
- SilcBool private_message,
- SilcBool static_key,
+ bool private_message,
+ bool static_key,
SilcCipher cipher,
- SilcHmac hmac,
- unsigned char *sender_id,
- SilcUInt32 sender_id_len,
- unsigned char *receiver_id,
- SilcUInt32 receiver_id_len,
- SilcStack stack,
- SilcBool no_allocation,
- SilcMessagePayload message)
+ SilcHmac hmac)
{
SilcBufferStruct buffer;
- SilcMessagePayload newp = NULL;
+ SilcMessagePayload newp;
int ret;
SilcUInt32 mac_len = 0, iv_len = 0;
silc_buffer_set(&buffer, payload, payload_len);
/* Decrypt the payload */
- if (silc_likely(cipher)) {
- ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
+ if (cipher) {
+ ret = silc_message_payload_decrypt(buffer.data, buffer.len,
private_message, static_key,
- cipher, hmac, sender_id,
- sender_id_len, receiver_id,
- receiver_id_len, TRUE);
- if (silc_unlikely(ret == FALSE))
+ cipher, hmac, TRUE);
+ if (ret == FALSE)
return NULL;
}
- if (silc_likely(hmac))
+ if (hmac)
mac_len = silc_hmac_len(hmac);
- /* IV is present for all channel messages, and private messages when
+ /* IV is present for all channel messages, and private messages when
static key (pre-shared key) is used. */
if (cipher && (!private_message || (private_message && static_key)))
iv_len = silc_cipher_get_block_len(cipher);
- if (!message) {
- newp = message = silc_calloc(1, sizeof(*newp));
- if (silc_unlikely(!newp))
- return NULL;
- }
- memset(message, 0, sizeof(*message));
- message->allocated = (stack || no_allocation ? FALSE : TRUE);
+ newp = silc_calloc(1, sizeof(*newp));
+ if (!newp)
+ return NULL;
/* Parse the Message Payload. */
- if (!no_allocation)
- ret = silc_buffer_sunformat(stack, &buffer,
- SILC_STR_UI_SHORT(&message->flags),
- SILC_STR_UI16_NSTRING_ALLOC(&message->data,
- &message->data_len),
- SILC_STR_UI16_NSTRING_ALLOC(&message->pad,
- &message->pad_len),
- SILC_STR_END);
- else
- ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI_SHORT(&message->flags),
- SILC_STR_UI16_NSTRING(&message->data,
- &message->data_len),
- SILC_STR_UI16_NSTRING(&message->pad,
- &message->pad_len),
- SILC_STR_END);
- if (silc_unlikely(ret == -1))
+ ret = silc_buffer_unformat(&buffer,
+ SILC_STR_UI_SHORT(&newp->flags),
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
+ &newp->data_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
+ &newp->pad_len),
+ SILC_STR_END);
+ if (ret == -1)
goto err;
- if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
- 6 - mac_len - iv_len) ||
- (message->pad_len + message->data_len >
- silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
+ if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
+ (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
goto err;
}
/* Parse Signed Message Payload if provided */
- if (message->flags & SILC_MESSAGE_FLAG_SIGNED &&
- message->data_len + message->pad_len + 6 + mac_len +
- iv_len < silc_buffer_len(&buffer)) {
- if (!silc_message_signed_payload_parse(buffer.data + 6 +
- message->data_len +
- message->pad_len,
- silc_buffer_len(&buffer) -
- iv_len - mac_len - 6 -
- message->data_len -
- message->pad_len,
- &message->sig))
- goto err;
+ if (newp->flags & SILC_MESSAGE_FLAG_SIGNED &&
+ newp->data_len + newp->pad_len + 6 + mac_len + iv_len < buffer.len) {
+ newp->sig =
+ silc_message_signed_payload_parse(buffer.data + 6 + newp->data_len +
+ newp->pad_len,
+ buffer.len - iv_len - mac_len);
}
- /* Parse MAC from the payload */
+ /* Parse IV and MAC from the payload */
+ if (iv_len) {
+ newp->iv = buffer.data + (buffer.len - iv_len - mac_len);
+ newp->iv_len = iv_len;
+ }
if (mac_len)
- message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len);
+ newp->mac = buffer.data + (buffer.len - mac_len);
return newp;
err:
- if (newp)
- silc_message_payload_free(newp);
+ silc_message_payload_free(newp);
return NULL;
}
-
-/***************************** Payload encoding *****************************/
-
/* This function is used to encrypt the Messsage Payload which is
the `data' and `data_len'. This is used internally by the Message
- Payload encoding routines but application may call this too if needed.
+ 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. */
-SilcBool silc_message_payload_encrypt(unsigned char *data,
- SilcUInt32 data_len,
- SilcUInt32 true_len,
- unsigned char *iv,
- SilcID *sender_id,
- SilcID *receiver_id,
- SilcCipher cipher,
- SilcHmac hmac)
+bool silc_message_payload_encrypt(unsigned char *data,
+ SilcUInt32 data_len,
+ SilcUInt32 true_len,
+ unsigned char *iv,
+ SilcUInt32 iv_len,
+ SilcCipher cipher,
+ SilcHmac hmac)
{
-#if 0
- unsigned char sid[32], rid[32];
- SilcUInt32 sid_len = 0, rid_len = 0;
-#endif /* 0 */
-
- /* Encrypt payload of the packet */
- if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
- return FALSE;
+ unsigned char mac[32];
+ SilcUInt32 mac_len;
+ SilcBufferStruct buf;
-#if 0 /* For now this is disabled. Enable at 1.1.x or 1.2 at the latest. */
- /* Encode IDs */
- silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
- &sid_len);
- if (receiver_id->type == SILC_ID_CLIENT)
- silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid,
- sizeof(rid), &rid_len);
- else if (receiver_id->type == SILC_ID_CHANNEL)
- silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
- sizeof(rid), &rid_len);
-#endif /* 0 */
+ /* Encrypt payload of the packet. If the IV is added to packet do
+ not encrypt that. */
+ silc_cipher_encrypt(cipher, data, data, data_len, iv_len ? iv : NULL);
/* Compute the MAC of the encrypted message data */
silc_hmac_init(hmac);
silc_hmac_update(hmac, data, true_len);
-#if 0
- silc_hmac_update(hmac, sid, sid_len);
- silc_hmac_update(hmac, rid, rid_len);
-#endif /* 0 */
- silc_hmac_final(hmac, data + true_len, NULL);
-
- return TRUE;
-}
-
-/* Encrypt message payload */
-
-static int silc_message_payload_encode_encrypt(SilcBuffer buffer,
- void *value, void *context)
-{
- SilcMessageEncode *e = context;
- SilcUInt32 mac_len;
-
- if (!e->cipher || !e->hmac)
- return 0;
+ silc_hmac_final(hmac, mac, &mac_len);
- mac_len = silc_hmac_len(e->hmac);
- if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
- return -1;
+ /* Put rest of the data to the payload */
+ silc_buffer_set(&buf, data, true_len + mac_len);
+ silc_buffer_pull(&buf, true_len);
+ silc_buffer_put(&buf, mac, mac_len);
- if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
- e->payload_len,
- silc_buffer_headlen(buffer),
- e->iv, e->sid, e->rid,
- e->cipher, e->hmac)))
- return -1;
-
- return mac_len;
-}
-
-/* Compute message signature */
-
-static int silc_message_payload_encode_sig(SilcBuffer buffer,
- void *value, void *context)
-{
- SilcMessageEncode *e = context;
- SilcBuffer sig;
- int len;
-
- if (!(e->flags & SILC_MESSAGE_FLAG_SIGNED))
- return 0;
-
- sig = silc_message_signed_payload_encode(buffer->head,
- silc_buffer_headlen(buffer),
- e->public_key, e->private_key,
- e->hash);
- if (silc_unlikely(!sig))
- return -1;
-
- len = silc_buffer_format(buffer,
- SILC_STR_DATA(silc_buffer_data(sig),
- silc_buffer_len(sig)),
- SILC_STR_END);
- if (silc_unlikely(len < 0)) {
- silc_buffer_free(sig);
- return -1;
- }
-
- silc_buffer_free(sig);
- return len;
+ return TRUE;
}
/* Encodes Message Payload into a buffer and returns it. */
SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
const unsigned char *data,
SilcUInt32 data_len,
- SilcBool generate_iv,
- SilcBool private_message,
+ bool generate_iv,
+ bool private_message,
SilcCipher cipher,
SilcHmac hmac,
SilcRng rng,
SilcPublicKey public_key,
SilcPrivateKey private_key,
- SilcHash hash,
- SilcID *sender_id,
- SilcID *receiver_id,
- SilcBuffer buffer)
+ SilcHash hash)
{
- SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
- unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
- SilcBuffer buf = NULL;
- SilcMessageEncode e;
int i;
+ SilcBuffer buffer;
+ SilcUInt32 len, pad_len = 0, mac_len = 0, iv_len = 0;
+ unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
+ SilcBuffer sig = NULL;
SILC_LOG_DEBUG(("Encoding Message Payload"));
- if (silc_unlikely(!data_len))
- return NULL;
- if (silc_unlikely(!private_message && (!cipher || !hmac)))
+ if (!data_len)
return NULL;
- if (!buffer) {
- buf = buffer = silc_buffer_alloc(0);
- if (silc_unlikely(!buf))
- return NULL;
- }
- silc_buffer_reset(buffer);
-
/* For channel messages IV is always generated */
if (!private_message && !generate_iv)
generate_iv = TRUE;
if (hmac)
mac_len = silc_hmac_len(hmac);
- data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
- public_key, private_key);
+ data_len = SILC_MESSAGE_DATALEN(data_len, mac_len + iv_len);
/* Calculate length of padding. IV is not included into the calculation
since it is not encrypted. */
- pad_len = SILC_MESSAGE_PAD(6 + data_len);
+ len = 6 + data_len;
+ pad_len = SILC_MESSAGE_PAD(len);
+
+ /* Allocate payload buffer */
+ len += pad_len + iv_len + mac_len;
+ buffer = silc_buffer_alloc(len);
+ if (!buffer)
+ return NULL;
/* Generate padding */
if (cipher) {
}
}
- e.flags = flags;
- e.public_key = public_key;
- e.private_key = private_key;
- e.hash = hash;
- e.cipher = cipher;
- e.hmac = hmac;
- e.sid = sender_id;
- e.rid = receiver_id;
- e.iv = iv_len ? iv : NULL;
- e.payload_len = 6 + data_len + pad_len;
-
/* Encode the Message Payload */
- if (silc_buffer_format(buffer,
- SILC_STR_UI_SHORT(flags),
- SILC_STR_UI_SHORT(data_len),
- SILC_STR_DATA(data, data_len),
- SILC_STR_UI_SHORT(pad_len),
- SILC_STR_DATA(pad, pad_len),
- SILC_STR_FUNC(silc_message_payload_encode_sig,
- NULL, &e),
- SILC_STR_DATA(iv, iv_len),
- SILC_STR_FUNC(silc_message_payload_encode_encrypt,
- NULL, &e),
- SILC_STR_END) < 0) {
- silc_buffer_free(buf);
- return NULL;
+ silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(flags),
+ SILC_STR_UI_SHORT(data_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI_SHORT(pad_len),
+ SILC_STR_UI_XNSTRING(pad, pad_len),
+ SILC_STR_END);
+
+ memset(pad, 0, sizeof(pad));
+
+ /* Sign the message if wanted */
+ if (flags & SILC_MESSAGE_FLAG_SIGNED && private_key && hash) {
+ sig = silc_message_signed_payload_encode(buffer->data, buffer->len,
+ public_key, private_key, hash);
+ if (sig) {
+ buffer = silc_buffer_realloc(buffer, buffer->truelen + sig->len);
+ if (buffer) {
+ silc_buffer_pull(buffer, 6 + data_len + pad_len);
+ silc_buffer_pull_tail(buffer, sig->len);
+ silc_buffer_put(buffer, sig->data, sig->len);
+ silc_buffer_push(buffer, 6 + data_len + pad_len);
+ }
+ }
}
+ /* Put IV */
+ silc_buffer_pull(buffer, 6 + data_len + pad_len + (sig ? sig->len : 0));
+ silc_buffer_pull_tail(buffer, iv_len);
+ silc_buffer_format(buffer,
+ SILC_STR_UI_XNSTRING(iv, iv_len),
+ SILC_STR_END);
+ silc_buffer_push(buffer, 6 + data_len + pad_len + (sig ? sig->len : 0));
+
+ SILC_LOG_HEXDUMP(("foo"), buffer->data, buffer->len);
+
+ /* Now encrypt the Message Payload and compute MAC */
+ if (cipher) {
+ if (!silc_message_payload_encrypt(buffer->data,
+ buffer->len - iv_len -
+ (sig ? sig->len : 0),
+ buffer->len, iv, iv_len,
+ cipher, hmac)) {
+ silc_buffer_free(buffer);
+ silc_buffer_free(sig);
+ return NULL;
+ }
+ }
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
+
+ silc_buffer_free(sig);
return buffer;
}
{
if (payload->data) {
memset(payload->data, 0, payload->data_len);
- if (payload->allocated)
- silc_free(payload->data);
+ silc_free(payload->data);
}
- if (payload->allocated) {
- silc_free(payload->pad);
- silc_free(payload);
- }
- silc_message_signed_payload_free(&payload->sig);
+ if (payload->sig)
+ silc_message_signed_payload_free(payload->sig);
+ silc_free(payload->pad);
+ silc_free(payload);
}
/* Return flags */
return payload->mac;
}
+/* Return IV. The caller knows the length of the IV */
+
+unsigned char *silc_message_get_iv(SilcMessagePayload payload)
+{
+ return payload->iv;
+}
+
+/* Return signature of the message */
+
+SilcMessageSignedPayload
+silc_message_get_signature(SilcMessagePayload payload)
+{
+ return payload->sig;
+}
+
+/******************************************************************************
+
+ SILC_MESSAGE_FLAG_SIGNED Payload
+
+******************************************************************************/
+
+/* The SILC_MESSAGE_FLAG_SIGNED Payload */
+struct SilcMessageSignedPayloadStruct {
+ SilcUInt16 pk_len;
+ SilcUInt16 pk_type;
+ SilcUInt16 sign_len;
+ unsigned char *pk_data;
+ unsigned char *sign_data;
+};
+
+/* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
+
+static SilcBuffer
+silc_message_signed_encode_data(const unsigned char *message_payload,
+ SilcUInt32 message_payload_len,
+ unsigned char *pk,
+ SilcUInt32 pk_len, SilcUInt32 pk_type)
+{
+ SilcBuffer sign;
+
+ sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
+ if (!sign)
+ return NULL;
+
+ silc_buffer_format(sign,
+ SILC_STR_UI_XNSTRING(message_payload,
+ message_payload_len),
+ SILC_STR_UI_SHORT(pk_len),
+ SILC_STR_UI_SHORT(pk_type),
+ SILC_STR_END);
+
+ if (pk && pk_len) {
+ silc_buffer_pull(sign, message_payload_len + 4);
+ silc_buffer_format(sign,
+ SILC_STR_UI_XNSTRING(pk, pk_len),
+ SILC_STR_END);
+ silc_buffer_push(sign, message_payload_len + 4);
+ }
+
+ return sign;
+}
+
+/* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
+
+SilcMessageSignedPayload
+silc_message_signed_payload_parse(const unsigned char *data,
+ SilcUInt32 data_len)
+{
+ SilcMessageSignedPayload sig;
+ SilcBufferStruct buffer;
+ int ret;
+
+ SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
+
+ SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len);
+
+ silc_buffer_set(&buffer, (unsigned char *)data, data_len);
+ sig = silc_calloc(1, sizeof(*sig));
+ if (!sig)
+ return NULL;
+
+ /* Parse the payload */
+ ret = silc_buffer_unformat(&buffer,
+ SILC_STR_UI_SHORT(&sig->pk_len),
+ SILC_STR_UI_SHORT(&sig->pk_type),
+ SILC_STR_END);
+ if (ret == -1 || sig->pk_len > data_len - 4) {
+ silc_message_signed_payload_free(sig);
+ SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
+ "Payload"));
+ return NULL;
+ }
+
+ silc_buffer_pull(&buffer, 4);
+ ret = silc_buffer_unformat(&buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
+ sig->pk_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
+ &sig->sign_len),
+ SILC_STR_END);
+ if (ret == -1 || sig->sign_len > buffer.len - sig->pk_len - 2) {
+ silc_message_signed_payload_free(sig);
+ SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
+ return NULL;
+ }
+ silc_buffer_push(&buffer, 4);
+
+ /* Signature must be provided */
+ if (sig->sign_len < 1) {
+ SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
+ "Payload"));
+ silc_message_signed_payload_free(sig);
+ return NULL;
+ }
+
+ return sig;
+}
+
+/* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
+ signature. */
+
+SilcBuffer
+silc_message_signed_payload_encode(const unsigned char *message_payload,
+ SilcUInt32 message_payload_len,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcHash hash)
+{
+ SilcBuffer buffer, sign;
+ SilcPKCS pkcs;
+ unsigned char auth_data[2048 + 1];
+ SilcUInt32 auth_len;
+ unsigned char *pk = NULL;
+ SilcUInt32 pk_len = 0;
+ SilcUInt16 pk_type;
+
+ if (!message_payload || !message_payload_len || !private_key || !hash)
+ return NULL;
+
+ if (public_key)
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+
+ /* Now we support only SILC style public key */
+ pk_type = SILC_SKE_PK_TYPE_SILC;
+
+ /* Encode the data to be signed */
+ sign = silc_message_signed_encode_data(message_payload,
+ message_payload_len,
+ pk, pk_len, pk_type);
+ if (!sign) {
+ silc_free(pk);
+ return NULL;
+ }
+
+ /* Sign the buffer */
+
+ /* Allocate PKCS object */
+ if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
+ SILC_LOG_ERROR(("Could not allocated PKCS"));
+ silc_buffer_clear(sign);
+ silc_buffer_free(sign);
+ silc_free(pk);
+ return NULL;
+ }
+ silc_pkcs_private_key_set(pkcs, private_key);
+
+ /* Compute the hash and the signature. */
+ if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
+ !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, sign->len, auth_data,
+ &auth_len)) {
+ SILC_LOG_ERROR(("Could not compute signature"));
+ silc_buffer_clear(sign);
+ silc_buffer_free(sign);
+ silc_pkcs_free(pkcs);
+ silc_free(pk);
+ return NULL;
+ }
+
+ /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
+
+ buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
+ if (!buffer) {
+ silc_buffer_clear(sign);
+ silc_buffer_free(sign);
+ silc_pkcs_free(pkcs);
+ memset(auth_data, 0, sizeof(auth_data));
+ silc_free(pk);
+ return NULL;
+ }
+
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(pk_len),
+ SILC_STR_UI_SHORT(pk_type),
+ SILC_STR_END);
+
+ if (pk_len && pk) {
+ silc_buffer_pull(buffer, 4);
+ silc_buffer_format(buffer,
+ SILC_STR_UI_XNSTRING(pk, pk_len),
+ SILC_STR_END);
+ silc_buffer_push(buffer, 4);
+ }
+
+ silc_buffer_pull(buffer, 4 + pk_len);
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(auth_len),
+ SILC_STR_UI_XNSTRING(auth_data, auth_len),
+ SILC_STR_END);
+ silc_buffer_push(buffer, 4 + pk_len);
+
+ SILC_LOG_HEXDUMP(("sig payload"), buffer->data, buffer->len);
+
+ memset(auth_data, 0, sizeof(auth_data));
+ silc_pkcs_free(pkcs);
+ silc_buffer_clear(sign);
+ silc_buffer_free(sign);
+ silc_free(pk);
+
+ return buffer;
+}
+
+/* Free the payload */
+
+void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
+{
+ memset(sig->sign_data, 0, sig->sign_len);
+ silc_free(sig->sign_data);
+ silc_free(sig->pk_data);
+ silc_free(sig);
+}
+
/* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
-SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
- SilcPublicKey remote_public_key,
- SilcHash hash)
+int silc_message_signed_verify(SilcMessageSignedPayload sig,
+ SilcMessagePayload message,
+ SilcPublicKey remote_public_key,
+ SilcHash hash)
{
int ret = SILC_AUTH_FAILED;
- SilcBuffer sign, tmp;
- SilcMessageSignedPayload sig = &message->sig;
-
- if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
- !sig->sign_len || !remote_public_key || !hash)
+ SilcBuffer sign;
+ SilcPKCS pkcs;
+ SilcBuffer tmp;
+
+ if (!sig || !remote_public_key || !hash)
return ret;
/* Generate the signature verification data, the Message Payload */
SILC_STR_UI_SHORT(message->pad_len),
SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
SILC_STR_END);
- sign = silc_message_signed_encode_data(tmp->data, silc_buffer_len(tmp),
+ sign = silc_message_signed_encode_data(tmp->data, tmp->len,
sig->pk_data, sig->pk_len,
sig->pk_type);
silc_buffer_clear(tmp);
silc_buffer_free(tmp);
-
+
if (!sign)
return ret;
+
+ /* Allocate PKCS object */
+ if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) {
+ silc_buffer_clear(sign);
+ silc_buffer_free(sign);
+ return ret;
+ }
+ silc_pkcs_public_key_set(pkcs, remote_public_key);
/* Verify the authentication data */
- if (!silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
- silc_buffer_data(sign), silc_buffer_len(sign), hash)) {
+ if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data,
+ sig->sign_len,
+ sign->data, sign->len)) {
+
silc_buffer_clear(sign);
silc_buffer_free(sign);
+ silc_pkcs_free(pkcs);
SILC_LOG_DEBUG(("Signature verification failed"));
return ret;
}
silc_buffer_clear(sign);
silc_buffer_free(sign);
+ silc_pkcs_free(pkcs);
SILC_LOG_DEBUG(("Signature verification successful"));
/* Return the public key from the payload */
SilcPublicKey
-silc_message_signed_get_public_key(SilcMessagePayload payload,
- const unsigned char **pk_data,
+silc_message_signed_get_public_key(SilcMessageSignedPayload sig,
+ unsigned char **pk_data,
SilcUInt32 *pk_data_len)
{
SilcPublicKey pk;
- SilcMessageSignedPayload sig = &payload->sig;
-
- if (!sig->pk_data)
- return NULL;
- if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
- sig->pk_len, &pk))
+ if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data,
+ sig->pk_len, &pk))
return NULL;
if (pk_data)
/*
- silcmessage.h
+ silcmessage.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 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
* DESCRIPTION
*
* This interface includes the implementation of the Message Payload that
- * is used to send private messages and channel messages. The interface
- * is also able to automatically provide digital signature in the messages
- * if it is requested. Message digital signatures may also be verified with
- * this interface.
+ * is used to send private messages and channel messages.
+ *
+ * This interface defines also the SILC_MESSAGE_FLAG_SIGNED Payload,
+ * which defines how channel messages and private messages can be digitally
+ * signed. This interface provides the payload parsing, encoding,
+ * signature computing and signature verification routines.
*
***/
/****s* silccore/SilcMessageAPI/SilcMessagePayload
*
* NAME
- *
- * typedef struct SilcMessagePayloadObject
- * *SilcMessagePayload, SilcMessagePayloadStruct;
+ *
+ * typedef struct SilcMessagePayloadStruct *SilcMessagePayload;
*
*
* DESCRIPTION
* silc_message_payload_free function.
*
***/
-typedef struct SilcMessagePayloadObject
- *SilcMessagePayload, SilcMessagePayloadStruct;
+typedef struct SilcMessagePayloadStruct *SilcMessagePayload;
-/****d* silccore/SilcMessageAPI/SilcMessageFlags
+/****s* silccore/SilcMessageAPI/SilcMessageSignedPayload
*
* NAME
+ *
+ * typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
*
+ *
+ * DESCRIPTION
+ *
+ * This context represents the SILC_MESSAGE_FLAG_SIGNED Payload which
+ * is used with channel messages and private messages to indicate that
+ * the message is digitally signed. This payload may include the
+ * message sender's public key and it includes the digital signature.
+ * This payload MUST NOT be used in any other context except with
+ * channel and private message sending and reception.
+ *
+ ***/
+typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
+
+/****d* silccore/SilcMessageAPI/SilcMessageFlags
+ *
+ * NAME
+ *
* typedef SilcUInt16 SilcMessageFlags;
*
* DESCRIPTION
*
- * The message flags type definition and the message flags. The
+ * The message flags type definition and the message flags. The
* message flags are used to indicate some status of the message.
*
* SOURCE
#define SILC_MESSAGE_FLAG_DATA 0x0080 /* MIME object */
#define SILC_MESSAGE_FLAG_UTF8 0x0100 /* UTF-8 string */
#define SILC_MESSAGE_FLAG_ACK 0x0200 /* ACK messages */
-#define SILC_MESSAGE_FLAG_STOP 0x0400 /* Stop indication */
-#define SILC_MESSAGE_FLAG_RESERVED 0x0800 /* to 0x1000 */
+#define SILC_MESSAGE_FLAG_RESERVED 0x0400 /* to 0x1000 */
#define SILC_MESSAGE_FLAG_PRIVATE 0x2000 /* to 0x8000 */
/***/
*
* SYNOPSIS
*
- * SilcBool silc_message_payload_decrypt(unsigned char *data,
- * size_t data_len,
- * SilcBool private_message,
- * SilcBool static_key,
- * SilcCipher cipher,
- * SilcHmac hmac,
- * unsigned char *sender_id,
- * SilcUInt32 sender_id_len,
- * unsigned char *receiver_id,
- * SilcUInt32 receiver_id_len,
- * SilcBool check_mac);
+ * bool silc_message_payload_decrypt(unsigned char *data,
+ * size_t data_len,
+ * bool private_message,
+ * bool static_key,
+ * SilcCipher cipher,
+ * SilcHmac hmac,
+ * bool check_mac);
*
* DESCRIPTION
*
* (Key Agreement was done for the key) then it MUST be FALSE. For
* channel messages the `static_key' is ignored.
*
- * The `sender_id' and `receiver_id' are the IDs from the packet header
- * of the packet where this message payload was received.
- *
* This is usually used by the Message Payload interface itself but can
* be called by the appliation if separate decryption process is required.
- * For example server might need to call this directly in some
+ * For example server might need to call this directly in some
* circumstances. The `cipher' is used to decrypt the payload. If
* `check_mac' is FALSE then MAC is not verified.
*
***/
-SilcBool silc_message_payload_decrypt(unsigned char *data,
- size_t data_len,
- SilcBool private_message,
- SilcBool static_key,
- SilcCipher cipher,
- SilcHmac hmac,
- unsigned char *sender_id,
- SilcUInt32 sender_id_len,
- unsigned char *receiver_id,
- SilcUInt32 receiver_id_len,
- SilcBool check_mac);
+bool silc_message_payload_decrypt(unsigned char *data,
+ size_t data_len,
+ bool private_message,
+ bool static_key,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ bool check_mac);
/****f* silccore/SilcMessageAPI/silc_message_payload_parse
*
* SYNOPSIS
*
- * SilcMessagePayload
+ * SilcMessagePayload
* silc_message_payload_parse(unsigned char *payload,
* SilcUInt32 payload_len,
- * SilcBool private_message,
- * SilcBool static_key,
+ * bool private_message,
+ * bool static_key,
* SilcCipher cipher,
- * SilcHmac hmac,
- * unsigned char *sender_id,
- * SilcUInt32 sender_id_len,
- * unsigned char *receiver_id,
- * SilcUInt32 receiver_id_len,
- * SilcStack stack,
- * SilcBool no_allocation,
- * SilcMessagePayload message);
+ * SilcHmac hmac);
*
* DESCRIPTION
*
* then this assumes that the packet was decrypted with session keys
* (no private message key) and this merely decodes the payload.
*
- * The `sender_id' and `receiver_id' are the IDs from the packet header
- * of the packet where this message payload was received.
- *
- * If the `message' is non-NULL then that pre-allocated context is
- * used in parsing. Same context is returned. Otherwise new context
- * is allocated and returned. If the `stack' is non-NULL then memory
- * is allocated from that stack. If `no_allocation' is TRUE then the
- * `message' must be provided and data is merely parsed and referenced
- * from `payload' and will become invalid when `payload' invalidates.
- * If `no_allocation' is TRUE the routine does not do any allocations.
- *
***/
-SilcMessagePayload
+SilcMessagePayload
silc_message_payload_parse(unsigned char *payload,
SilcUInt32 payload_len,
- SilcBool private_message,
- SilcBool static_key,
+ bool private_message,
+ bool static_key,
SilcCipher cipher,
- SilcHmac hmac,
- unsigned char *sender_id,
- SilcUInt32 sender_id_len,
- unsigned char *receiver_id,
- SilcUInt32 receiver_id_len,
- SilcStack stack,
- SilcBool no_allocation,
- SilcMessagePayload message);
+ SilcHmac hmac);
/****f* silccore/SilcMessageAPI/silc_message_payload_encrypt
*
* SYNOPSIS
*
- * SilcBool silc_message_payload_encrypt(unsigned char *data,
- * SilcUInt32 data_len,
- * SilcUInt32 true_len,
- * unsigned char *iv,
- * SilcID *sender_id,
- * SilcID *receiver_id,
- * SilcCipher cipher,
- * SilcHmac hmac);
+ * bool silc_message_payload_encrypt(unsigned char *data,
+ * SilcUInt32 data_len,
+ * SilcUInt32 true_len,
+ * unsigned char *iv,
+ * SilcUInt32 iv_len,
+ * SilcCipher cipher,
+ * SilcHmac hmac);
*
* DESCRIPTION
*
* the `data' and `data_len'. The `data_len' is the data length which
* is used to create MAC out of. The `data' MUST have additional space
* after `true_len' bytes for the MAC which is appended to the data.
- * The `sender_id' is the ID message sender and `receiver_id' is ID of
- * message receiver.
*
* This is usually used by the Message Payload interface itself but can
* be called by the appliation if separate encryption process is required.
- * For example server might need to call this directly in some
+ * For example server might need to call this directly in some
* circumstances. The `cipher' is used to encrypt the payload and `hmac'
* to compute the MAC for the payload.
*
***/
-SilcBool silc_message_payload_encrypt(unsigned char *data,
- SilcUInt32 data_len,
- SilcUInt32 true_len,
- unsigned char *iv,
- SilcID *sender_id,
- SilcID *receiver_id,
- SilcCipher cipher,
- SilcHmac hmac);
+bool silc_message_payload_encrypt(unsigned char *data,
+ SilcUInt32 data_len,
+ SilcUInt32 true_len,
+ unsigned char *iv,
+ SilcUInt32 iv_len,
+ SilcCipher cipher,
+ SilcHmac hmac);
/****f* silccore/SilcMessageAPI/silc_message_payload_encode
*
* SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
* const unsigned char *data,
* SilcUInt32 data_len,
- * SilcBool generate_iv,
- * SilcBool private_message,
+ * bool generate_iv,
+ * bool private_message,
* SilcCipher cipher,
* SilcHmac hmac,
* SilcRng rng,
* SilcPublicKey public_key,
* SilcPrivateKey private_key,
- * SilcHash hash,
- * SilcID *sender_id,
- * SilcID *receiver_id,
- * SilcBuffer buffer);
+ * SilcHash hash);
*
* DESCRIPTION
*
* be included in the message. The `private_message' and `hash' MUST
* be provided. The `hash' SHOULD be SHA1.
*
- * The `sender_id' is the ID message sender and `receiver_id' is ID of
- * message receiver.
- *
- * If the `buffer' is non-NULL then the payload will be encoded into
- * that buffer. The same buffer is returned. Otherwise new buffer is
- * allocated and returned. The `buffer' will be automatically enlarged
- * if the payload does not fit to it.
- *
***/
SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
const unsigned char *data,
SilcUInt32 data_len,
- SilcBool generate_iv,
- SilcBool private_message,
+ bool generate_iv,
+ bool private_message,
SilcCipher cipher,
SilcHmac hmac,
SilcRng rng,
SilcPublicKey public_key,
SilcPrivateKey private_key,
- SilcHash hash,
- SilcID *sender_id,
- SilcID *receiver_id,
- SilcBuffer buffer);
+ SilcHash hash);
/****f* silccore/SilcMessageAPI/silc_message_payload_free
*
*
* DESCRIPTION
*
- * Return the MAC of the payload. The caller must already know the
+ * Return the MAC of the payload. The caller must already know the
* length of the MAC. The caller must not free the MAC.
*
***/
unsigned char *silc_message_get_mac(SilcMessagePayload payload);
+/****f* silccore/SilcMessageAPI/silc_message_get_iv
+ *
+ * SYNOPSIS
+ *
+ * unsigned char *
+ * silc_message_get_iv(SilcMessagePayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Return the IV of the payload. The caller must already know the
+ * length of the IV. The caller must not free the IV.
+ *
+ ***/
+unsigned char *silc_message_get_iv(SilcMessagePayload payload);
+
+/****f* silccore/SilcMessageAPI/silc_message_get_signature
+ *
+ * SYNOPSIS
+ *
+ * SilcMessageSignedPayload
+ * silc_message_get_signature(SilcMessagePayload payload);
+ *
+ * DESCRIPTION
+ *
+ * Returns the pointer to the signature of the message if the
+ * SILC_MESSAGE_FLAG_SIGNED was set. If the flag is set and this
+ * function returns NULL then error had occurred and the signature
+ * could not be retrieved from the message.
+ *
+ * The caller SHOULD verify the signature by calling the
+ * silc_message_signed_verify function. Caller must not free the
+ * returned payload pointer.
+ *
+ ***/
+SilcMessageSignedPayload
+silc_message_get_signature(SilcMessagePayload payload);
+
+/****f* silccore/SilcMessageAPI/silc_message_signed_payload_parse
+ *
+ * SYNOPSIS
+ *
+ * SilcMessageSignedPayload
+ * silc_message_signed_payload_parse(const unsigned char *data,
+ * SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ * Parses the SilcMessageSignedPayload Payload from the `data' of
+ * length of `data_len' bytes. The `data' must be payload without
+ * the actual message payload. Returns the parsed payload or NULL
+ * on error. Caller must free the returned payload. Application
+ * usually does not need to call this since the function
+ * silc_message_payload_parse calls this automatically for signed
+ * messages.
+ *
+ ***/
+SilcMessageSignedPayload
+silc_message_signed_payload_parse(const unsigned char *data,
+ SilcUInt32 data_len);
+
+/****f* silccore/SilcMessageAPI/silc_message_signed_payload_encode
+ *
+ * SYNOPSIS
+ *
+ * SilcBuffer
+ * silc_message_signed_payload_encode(const unsigned char *message_payload,
+ * SilcUInt32 message_payload_len,
+ * SilcPublicKey public_key,
+ * SilcPrivateKey private_key,
+ * SilcHash hash);
+ *
+ * DESCRIPTION
+ *
+ * Encodes the SilcMessageSignedPayload Payload and computes the
+ * digital signature. The `message_payload' is the message data that
+ * is used in the signature computation. The encoding of the buffer
+ * is specified in the SILC protocol. If `public_key' is provided
+ * then the public key included in the payload. The `private_key'
+ * is used to produce the signature. This function returns the encoded
+ * payload with the signature or NULL on error. Caller must free the
+ * returned buffer. The `hash' SHOULD be SHA-1 hash function.
+ *
+ * Application usually does not need to call this since the function
+ * silc_message_payload_encode calls this automatically if the caller
+ * wants to sign the message.
+ *
+ ***/
+SilcBuffer
+silc_message_signed_payload_encode(const unsigned char *message_payload,
+ SilcUInt32 message_payload_len,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcHash hash);
+
+/****f* silccore/SilcMessageAPI/silc_message_signed_payload_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_message_signed_payload_free(SilcMessageSignedPayload sig);
+ *
+ * DESCRIPTION
+ *
+ * Frees the SilcMessageSignedPayload Payload.
+ *
+ ***/
+void silc_message_signed_payload_free(SilcMessageSignedPayload sig);
+
/****f* silccore/SilcMessageAPI/silc_message_signed_verify
*
* SYNOPSIS
*
- * SilcAuthResult
- * silc_message_signed_verify(SilcMessagePayload message,
- * SilcPublicKey remote_public_key,
- * SilcHash hash);
+ * int silc_message_signed_verify(SilcMessageSignedPayload sig,
+ * SilcMessagePayload message,
+ * SilcPublicKey remote_public_key,
+ * SilcHash hash);
*
* DESCRIPTION
*
- * This routine can be used to verify the digital signature from the
- * message indicated by `message'. The signature is present only if
- * the SILC_MESSAGE_FLAG_SIGNED is set in the message flags. This
- * returns SILC_AUTH_OK if the signature verification was successful.
+ * This routine can be used to verify the signature found in
+ * SilcMessageSignedPayload Payload. This returns SILC_AUTH_OK if the
+ * signature verification was successful.
*
***/
-SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
- SilcPublicKey remote_public_key,
- SilcHash hash);
+int silc_message_signed_verify(SilcMessageSignedPayload sig,
+ SilcMessagePayload message,
+ SilcPublicKey remote_public_key,
+ SilcHash hash);
/****f* silccore/SilcMessageAPI/silc_message_signed_get_public_key
*
* SYNOPSIS
*
* SilcPublicKey
- * silc_message_signed_get_public_key(SilcMessagePayload payload,
- * const unsigned char **pk_data,
+ * silc_message_signed_get_public_key(SilcMessageSignedPayload sig,
+ * unsigned char **pk_data,
* SilcUInt32 *pk_data_len);
*
* DESCRIPTION
*
- * Returns the decoded SilcPublicKey from the message payload or NULL
- * if it does not include public key. The caller must free the returned
- * public key pointer. This also returns the raw public key (before
- * decoding) into `pk_data' and `pk_data_len' if they are provided. The
- * caller must not free these pointers.
+ * Returns the decoded SilcPublicKey from the SilcMessageSignedPayload
+ * Payload or NULL if it does not include public key. The caller must
+ * free the returned public key pointer. This also returns the raw
+ * public key (before decoding) into `pk_data' and `pk_data_len' if
+ * they are provided. The caller must not free these pointers.
*
***/
SilcPublicKey
-silc_message_signed_get_public_key(SilcMessagePayload payload,
- const unsigned char **pk_data,
+silc_message_signed_get_public_key(SilcMessageSignedPayload sig,
+ unsigned char **pk_data,
SilcUInt32 *pk_data_len);
-#include "silcmessage_i.h"
-
#endif /* SILCMESSAGE_H */
+++ /dev/null
-/*
-
- silcmessage_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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 SILCMESSAGE_I_H
-#define SILCMESSAGE_I_H
-
-#ifndef SILCMESSAGE_I_H
-#error "Do not include this header directly"
-#endif
-
-/* The SILC_MESSAGE_FLAG_SIGNED Payload */
-typedef struct SilcMessageSignedPayloadStruct {
- unsigned char *pk_data;
- unsigned char *sign_data;
- SilcUInt16 pk_len;
- SilcUInt16 pk_type;
- SilcUInt16 sign_len;
-} *SilcMessageSignedPayload;
-
-/* Message Payload structure. */
-struct SilcMessagePayloadObject {
- unsigned char *data;
- unsigned char *pad;
- unsigned char *mac;
- struct SilcMessageSignedPayloadStruct sig;
- SilcMessageFlags flags;
- SilcUInt16 data_len;
- SilcUInt16 pad_len;
- SilcUInt16 iv_len;
- unsigned int allocated : 1;
-};
-
-#endif /* SILCMESSAGE_I_H */
/*
-
+
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
/*
- silcnotify.c
+ silcnotify.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2005 Pekka Riikonen
+ 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcnotify.h"
/******************************************************************************
if (ret == -1)
goto err;
- if (len > silc_buffer_len(&buffer))
+ if (len > buffer.len)
goto err;
if (newp->argc) {
silc_buffer_pull(&buffer, 5);
- newp->args = silc_argument_payload_parse(buffer.data,
- silc_buffer_len(&buffer),
+ newp->args = silc_argument_payload_parse(buffer.data, buffer.len,
newp->argc);
silc_buffer_push(&buffer, 5);
}
argument payloads will be associated to the notify payload. Variable
arguments must be {usigned char *, SilcUInt32 (len)}. */
-SilcBuffer silc_notify_payload_encode(SilcNotifyType type, SilcUInt32 argc,
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, SilcUInt32 argc,
va_list ap)
{
SilcBuffer buffer;
silc_free(argv);
return NULL;
}
-
+
for (i = 0, k = 0; i < argc; i++) {
x = va_arg(ap, unsigned char *);
x_len = va_arg(ap, SilcUInt32);
if (!x || !x_len)
continue;
-
+
argv[k] = silc_memdup(x, x_len);
if (!argv[k])
return NULL;
}
args = silc_argument_payload_encode(k, argv, argv_lens, argv_types);
- len = silc_buffer_len(args);
+ len = args->len;
for (i = 0; i < k; i++)
silc_free(argv[i]);
SILC_STR_END);
if (k) {
+ silc_buffer_pull(buffer, 5);
silc_buffer_format(buffer,
- SILC_STR_OFFSET(5),
- SILC_STR_DATA(args->data, silc_buffer_len(args)),
+ SILC_STR_UI_XNSTRING(args->data, args->len),
SILC_STR_END);
+ silc_buffer_push(buffer, 5);
silc_buffer_free(args);
}
/* Same as above but takes argument from the `args' Argument Payload. */
-SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type,
+SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type,
SilcUInt32 argc,
SilcBuffer args)
{
SilcBuffer buffer;
SilcUInt32 len;
- len = 5 + (args ? silc_buffer_len(args) : 0);
+ len = 5 + (args ? args->len : 0);
buffer = silc_buffer_alloc_size(len);
if (!buffer)
return NULL;
SILC_STR_UI_CHAR(argc),
SILC_STR_END);
- if (args)
+ if (args) {
+ silc_buffer_pull(buffer, 5);
silc_buffer_format(buffer,
- SILC_STR_OFFSET(5),
- SILC_STR_DATA(args->data, silc_buffer_len(args)),
+ SILC_STR_UI_XNSTRING(args->data, args->len),
SILC_STR_END);
+ silc_buffer_push(buffer, 5);
+ }
return buffer;
}
/*
-
+
silcnotify.h
-
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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
/****s* silccore/SilcNotifyAPI/SilcNotifyPayload
*
* NAME
- *
+ *
* typedef struct SilcNotifyPayloadStruct *SilcNotifyPayload;
*
* DESCRIPTION
/****d* silccore/SilcNotifyAPI/SilcNotifyType
*
* NAME
- *
+ *
* typedef SilcUInt16 SilcNotifyType;
*
* DESCRIPTION
* arguments must be {unsigned char *, SilcUInt32 (len)}.
*
***/
-SilcBuffer silc_notify_payload_encode(SilcNotifyType type, SilcUInt32 argc,
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, SilcUInt32 argc,
va_list ap);
/****f* silccore/SilcNotifyAPI/silc_notify_payload_encode_args
* encoded Argument Payload buffer.
*
***/
-SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type,
+SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type,
SilcUInt32 argc,
SilcBuffer args);
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
-
-/************************** Types and definitions ***************************/
-
-/* Per scheduler (which usually means per thread) data. We put per scheduler
- data here for accessing without locking. SILC Schedule dictates that
- tasks are dispatched in one thread, hence the per scheduler context. */
-typedef struct {
- SilcSchedule schedule; /* The scheduler */
- SilcPacketEngine engine; /* Packet engine */
- SilcDList inbufs; /* Data inbut buffer list */
- SilcUInt32 stream_count; /* Number of streams using this */
-} *SilcPacketEngineContext;
-
-/* Packet engine */
-struct SilcPacketEngineStruct {
- SilcMutex lock; /* Engine lock */
- SilcRng rng; /* RNG for engine */
- SilcHashTable contexts; /* Per scheduler contexts */
- SilcPacketCallbacks *callbacks; /* Packet callbacks */
- void *callback_context; /* Context for callbacks */
- SilcList streams; /* All streams in engine */
- SilcList packet_pool; /* Free list for received packets */
- SilcHashTable udp_remote; /* UDP remote streams, or NULL */
- unsigned int local_is_router : 1;
-};
-
-/* Packet processor context */
-typedef struct SilcPacketProcessStruct {
- SilcPacketType *types; /* Packets to process */
- SilcPacketCallbacks *callbacks; /* Callbacks or NULL */
- void *callback_context;
- SilcInt32 priority; /* Priority */
-} *SilcPacketProcess;
-
-/* UDP remote stream tuple */
-typedef struct {
- char *remote_ip; /* Remote IP address */
- SilcUInt16 remote_port; /* Remote port */
-} *SilcPacketRemoteUDP;
-
-/* Packet stream */
-struct SilcPacketStreamStruct {
- struct SilcPacketStreamStruct *next;
- SilcPacketEngineContext sc; /* Per scheduler context */
- SilcStream stream; /* Underlaying stream */
- SilcMutex lock; /* Packet stream lock */
- SilcDList process; /* Packet processors, or NULL */
- SilcPacketRemoteUDP remote_udp; /* UDP remote stream tuple, or NULL */
- void *stream_context; /* Stream context */
- SilcBufferStruct outbuf; /* Out buffer */
- SilcBuffer inbuf; /* Inbuf from inbuf list or NULL */
- SilcCipher send_key[2]; /* Sending key */
- SilcHmac send_hmac[2]; /* Sending HMAC */
- SilcCipher receive_key[2]; /* Receiving key */
- SilcHmac receive_hmac[2]; /* Receiving HMAC */
- unsigned char *src_id; /* Source ID */
- unsigned char *dst_id; /* Destination ID */
- SilcUInt32 send_psn; /* Sending sequence */
- SilcUInt32 receive_psn; /* Receiving sequence */
- SilcAtomic8 refcnt; /* Reference counter */
- SilcUInt8 sid; /* Security ID, set if IV included */
- unsigned int src_id_len : 6;
- unsigned int src_id_type : 2;
- unsigned int dst_id_len : 6;
- unsigned int dst_id_type : 2;
- unsigned int is_router : 1; /* Set if router stream */
- unsigned int destroyed : 1; /* Set if destroyed */
- unsigned int iv_included : 1; /* Set if IV included */
- unsigned int udp : 1; /* UDP remote stream */
-};
-
-/* Initial size of stream buffers */
-#define SILC_PACKET_DEFAULT_SIZE 1024
-
-/* Header length without source and destination ID's. */
-#define SILC_PACKET_HEADER_LEN 10
-
-/* Minimum length of SILC Packet Header. */
-#define SILC_PACKET_MIN_HEADER_LEN 16
-#define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
-
-/* Maximum padding length */
-#define SILC_PACKET_MAX_PADLEN 128
-
-/* Default padding length */
-#define SILC_PACKET_DEFAULT_PADLEN 16
-
-/* Minimum packet length */
-#define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
-
-/* Returns true length of the packet. */
-#define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
-do { \
- SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
- (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
-} while(0)
-
-/* Calculates the data length with given header length. This macro
- can be used to check whether the data_len with header_len exceeds
- SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
- so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
- plus header_len fits SILC_PACKET_MAX_LEN the returned data length
- is the data_len given as argument. */
-#define SILC_PACKET_DATALEN(data_len, header_len) \
- ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
- data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
-
-/* Calculates the length of the padding in the packet. */
-#define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
-do { \
- __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
- ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
- if (__padlen < 8) \
- __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
-} while(0)
-
-/* Returns the length of the padding up to the maximum length, which
- is 128 bytes.*/
-#define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
-do { \
- __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
- ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
-} while(0)
-
-/* EOS callback */
-#define SILC_PACKET_CALLBACK_EOS(s) \
-do { \
- (s)->sc->engine->callbacks->eos((s)->sc->engine, s, \
- (s)->sc->engine->callback_context, \
- (s)->stream_context); \
-} while(0)
-
-/* Error callback */
-#define SILC_PACKET_CALLBACK_ERROR(s, err) \
-do { \
- (s)->sc->engine->callbacks->error((s)->sc->engine, s, err, \
- (s)->sc->engine->callback_context, \
- (s)->stream_context); \
-} while(0)
-
-static SilcBool silc_packet_dispatch(SilcPacket packet);
-static void silc_packet_read_process(SilcPacketStream stream);
-static inline 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);
-
-/************************ Static utility functions **************************/
-
-/* Injects packet to new stream created with silc_packet_stream_add_remote. */
-
-SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
-{
- SilcPacket packet = context;
- SilcPacketStream stream = packet->stream;
-
- SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
-
- silc_mutex_lock(stream->lock);
- if (!stream->destroyed)
- silc_packet_dispatch(packet);
- silc_mutex_unlock(stream->lock);
- silc_packet_stream_unref(stream);
-}
-
-/* Write data to the stream. Must be called with ps->lock locked. Unlocks
- the lock inside this function, unless no_unlock is TRUE. Unlocks always
- in case it returns FALSE. */
-
-static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
- SilcBool no_unlock)
-{
- SilcStream stream;
- SilcBool connected;
- int i;
-
- if (ps->udp)
- stream = ((SilcPacketStream)ps->stream)->stream;
- else
- stream = ps->stream;
-
- if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
- if (!connected) {
- /* Connectionless UDP stream */
- while (silc_buffer_len(&ps->outbuf) > 0) {
- i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
- ps->remote_udp->remote_port,
- ps->outbuf.data, silc_buffer_len(&ps->outbuf));
- if (silc_unlikely(i == -2)) {
- /* Error */
- silc_buffer_reset(&ps->outbuf);
- SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
- return FALSE;
- }
-
- if (silc_unlikely(i == -1)) {
- /* Cannot write now, write later. */
- if (!no_unlock)
- silc_mutex_unlock(ps->lock);
- return TRUE;
- }
-
- /* Wrote data */
- silc_buffer_pull(&ps->outbuf, i);
- }
-
- silc_buffer_reset(&ps->outbuf);
- if (!no_unlock)
- silc_mutex_unlock(ps->lock);
-
- return TRUE;
- }
- }
-
- /* Write the data to the stream */
- while (silc_buffer_len(&ps->outbuf) > 0) {
- i = silc_stream_write(stream, ps->outbuf.data,
- silc_buffer_len(&ps->outbuf));
- if (silc_unlikely(i == 0)) {
- /* EOS */
- silc_buffer_reset(&ps->outbuf);
- silc_mutex_unlock(ps->lock);
- SILC_PACKET_CALLBACK_EOS(ps);
- return FALSE;
- }
-
- if (silc_unlikely(i == -2)) {
- /* Error */
- silc_buffer_reset(&ps->outbuf);
- silc_mutex_unlock(ps->lock);
- SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
- return FALSE;
- }
-
- if (silc_unlikely(i == -1)) {
- /* Cannot write now, write later. */
- if (!no_unlock)
- silc_mutex_unlock(ps->lock);
- return TRUE;
- }
-
- /* Wrote data */
- silc_buffer_pull(&ps->outbuf, i);
- }
-
- silc_buffer_reset(&ps->outbuf);
- if (!no_unlock)
- silc_mutex_unlock(ps->lock);
-
- return TRUE;
-}
-
-/* Reads data from stream. Must be called with ps->lock locked. If this
- returns FALSE the lock has been unlocked. If this returns packet stream
- to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
- It is returned if the stream is UDP and remote UDP stream exists for
- the sender of the packet. */
-
-static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
- SilcPacketStream *ret_ps)
-{
- SilcStream stream = ps->stream;
- SilcBuffer inbuf;
- SilcBool connected;
- int ret;
-
- /* Get inbuf. If there is already some data for this stream in the buffer
- we already have it. Otherwise get the current one from list, it will
- include the data. */
- inbuf = ps->inbuf;
- if (!inbuf) {
- silc_dlist_start(ps->sc->inbufs);
- inbuf = silc_dlist_get(ps->sc->inbufs);
- if (!inbuf) {
- /* Allocate new data input buffer */
- inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
- if (!inbuf) {
- silc_mutex_unlock(ps->lock);
- return FALSE;
- }
- silc_buffer_reset(inbuf);
- silc_dlist_add(ps->sc->inbufs, inbuf);
- }
- }
-
- /* Make sure there is enough room to read */
- if (SILC_PACKET_DEFAULT_SIZE * 2 > silc_buffer_taillen(inbuf))
- silc_buffer_realloc(inbuf, silc_buffer_truelen(inbuf) +
- (SILC_PACKET_DEFAULT_SIZE * 2));
-
- if (silc_socket_stream_is_udp(stream, &connected)) {
- if (!connected) {
- /* Connectionless UDP stream, read one UDP packet */
- char remote_ip[64], tuple[64];
- int remote_port;
- SilcPacketStream remote;
-
- ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
- &remote_port, inbuf->tail,
- silc_buffer_taillen(inbuf));
-
- if (silc_unlikely(ret < 0)) {
- silc_mutex_unlock(ps->lock);
- if (ret == -1) {
- /* Cannot read now, do it later. */
- silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
- return FALSE;
- }
-
- /* Error */
- silc_buffer_reset(inbuf);
- SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
- return FALSE;
- }
-
- /* See if remote packet stream exist for this sender */
- silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
- silc_mutex_lock(ps->sc->engine->lock);
- if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
- (void *)&remote)) {
- silc_mutex_unlock(ps->sc->engine->lock);
- SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
- remote_port, remote));
- silc_mutex_unlock(ps->lock);
- silc_mutex_lock(remote->lock);
- *ret_ps = remote;
- return TRUE;
- }
- silc_mutex_unlock(ps->sc->engine->lock);
-
- /* Unknown sender */
- if (!ps->remote_udp) {
- ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
- if (silc_unlikely(!ps->remote_udp)) {
- silc_mutex_unlock(ps->lock);
- SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
- return FALSE;
- }
- }
-
- /* Save sender IP and port */
- silc_free(ps->remote_udp->remote_ip);
- ps->remote_udp->remote_ip = strdup(remote_ip);
- ps->remote_udp->remote_port = remote_port;
-
- silc_buffer_pull_tail(inbuf, ret);
- return TRUE;
- }
- }
-
- /* Read data from the stream */
- ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
- if (silc_unlikely(ret <= 0)) {
- silc_mutex_unlock(ps->lock);
- if (ret == 0) {
- /* EOS */
- silc_buffer_reset(inbuf);
- SILC_PACKET_CALLBACK_EOS(ps);
- return FALSE;
- }
-
- if (ret == -1) {
- /* Cannot read now, do it later. */
- silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
- return FALSE;
- }
-
- /* Error */
- silc_buffer_reset(inbuf);
- SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
- return FALSE;
- }
-
- silc_buffer_pull_tail(inbuf, ret);
- return TRUE;
-}
-
-/* Our stream IO notifier callback. */
-
-static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SilcPacketStream remote = NULL, ps = context;
-
- silc_mutex_lock(ps->lock);
-
- if (silc_unlikely(ps->destroyed)) {
- silc_mutex_unlock(ps->lock);
- return;
- }
-
- switch (status) {
- case SILC_STREAM_CAN_READ:
- /* Reading is locked also with stream->lock because we may be reading
- at the same time other thread is writing to same underlaying stream. */
- SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
-
- /* Read data from stream */
- if (!silc_packet_stream_read(ps, &remote))
- return;
-
- /* Now process the data */
- silc_packet_stream_ref(ps);
- if (!remote) {
- silc_packet_read_process(ps);
- silc_mutex_unlock(ps->lock);
- } else {
- silc_packet_read_process(remote);
- silc_mutex_unlock(remote->lock);
- }
- silc_packet_stream_unref(ps);
- break;
-
- case SILC_STREAM_CAN_WRITE:
- SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
- ps->stream, ps));
-
- if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
- silc_mutex_unlock(ps->lock);
- return;
- }
-
- /* Write pending data to stream */
- silc_packet_stream_write(ps, FALSE);
- 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 (silc_unlikely(!packet))
- return NULL;
-
- SILC_LOG_DEBUG(("Allocating new packet %p", packet));
-
- tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
- if (silc_unlikely(!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;
-}
-
-/* UDP remote stream hash table destructor */
-
-static void silc_packet_engine_hash_destr(void *key, void *context,
- void *user_context)
-{
- silc_free(key);
-}
-
-/* Per scheduler context hash table destructor */
-
-static void silc_packet_engine_context_destr(void *key, void *context,
- void *user_context)
-{
- SilcPacketEngineContext sc = context;
- SilcBuffer buffer;
-
- silc_dlist_start(sc->inbufs);
- while ((buffer = silc_dlist_get(sc->inbufs))) {
- silc_buffer_clear(buffer);
- silc_buffer_free(buffer);
- silc_dlist_del(sc->inbufs, buffer);
- }
-
- silc_dlist_uninit(sc->inbufs);
- silc_free(sc);
-}
-
-
-/******************************** Packet API ********************************/
-
-/* Allocate new packet engine */
-
-SilcPacketEngine
-silc_packet_engine_start(SilcRng rng, SilcBool router,
- SilcPacketCallbacks *callbacks,
- void *callback_context)
-{
- SilcPacketEngine engine;
- SilcPacket packet;
- int i;
- void *tmp;
-
- SILC_LOG_DEBUG(("Starting new packet engine"));
-
- if (!callbacks)
- return NULL;
- if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
- return NULL;
-
- engine = silc_calloc(1, sizeof(*engine));
- if (!engine)
- return NULL;
-
- engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
- silc_packet_engine_context_destr,
- engine, TRUE);
- if (!engine->contexts) {
- silc_free(engine);
- return NULL;
- }
-
- engine->rng = rng;
- engine->local_is_router = router;
- engine->callbacks = callbacks;
- engine->callback_context = callback_context;
- silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
- silc_mutex_alloc(&engine->lock);
-
- /* Allocate packet free list */
- silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
- for (i = 0; i < 5; i++) {
- packet = silc_calloc(1, sizeof(*packet));
- if (!packet) {
- silc_packet_engine_stop(engine);
- return NULL;
- }
-
- tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
- if (!tmp) {
- silc_packet_engine_stop(engine);
- return NULL;
- }
- silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
- silc_buffer_reset(&packet->buffer);
-
- silc_list_add(engine->packet_pool, packet);
- }
- silc_list_start(engine->packet_pool);
+#include "silcincludes.h"
- return engine;
-}
-
-/* Stop packet engine */
-
-void silc_packet_engine_stop(SilcPacketEngine engine)
-{
- SilcPacket packet;
-
- SILC_LOG_DEBUG(("Stopping packet engine"));
-
- if (!engine)
- return;
-
- /* Free packet free list */
- silc_list_start(engine->packet_pool);
- while ((packet = silc_list_get(engine->packet_pool))) {
- silc_buffer_purge(&packet->buffer);
- silc_free(packet);
- }
-
- silc_hash_table_free(engine->contexts);
- silc_mutex_free(engine->lock);
- silc_free(engine);
-}
-
-/* Create new packet stream */
-
-SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
- SilcSchedule schedule,
- SilcStream stream)
-{
- SilcPacketStream ps;
- SilcBuffer inbuf;
- void *tmp;
-
- SILC_LOG_DEBUG(("Creating new packet stream"));
-
- if (!engine || !stream)
- return NULL;
-
- ps = silc_calloc(1, sizeof(*ps));
- if (!ps)
- return NULL;
-
- ps->stream = stream;
- silc_atomic_init8(&ps->refcnt, 1);
- silc_mutex_alloc(&ps->lock);
-
- /* Allocate out buffer */
- tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
- if (!tmp) {
- silc_packet_stream_destroy(ps);
- 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();
- if (!ps->process) {
- silc_packet_stream_destroy(ps);
- return NULL;
- }
-
- silc_mutex_lock(engine->lock);
-
- /* Add per scheduler context */
- if (!silc_hash_table_find(engine->contexts, schedule, NULL,
- (void *)&ps->sc)) {
- ps->sc = silc_calloc(1, sizeof(*ps->sc));
- if (!ps->sc) {
- silc_packet_stream_destroy(ps);
- silc_mutex_unlock(engine->lock);
- return NULL;
- }
- ps->sc->engine = engine;
- ps->sc->schedule = schedule;
-
- /* Allocate data input buffer */
- inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
- if (!inbuf) {
- silc_free(ps->sc);
- ps->sc = NULL;
- silc_packet_stream_destroy(ps);
- silc_mutex_unlock(engine->lock);
- return NULL;
- }
- silc_buffer_reset(inbuf);
-
- ps->sc->inbufs = silc_dlist_init();
- if (!ps->sc->inbufs) {
- silc_buffer_free(inbuf);
- silc_free(ps->sc);
- ps->sc = NULL;
- silc_packet_stream_destroy(ps);
- silc_mutex_unlock(engine->lock);
- return NULL;
- }
- silc_dlist_add(ps->sc->inbufs, inbuf);
-
- /* Add to per scheduler context hash table */
- if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
- silc_buffer_free(inbuf);
- silc_dlist_del(ps->sc->inbufs, inbuf);
- silc_free(ps->sc);
- ps->sc = NULL;
- silc_packet_stream_destroy(ps);
- silc_mutex_unlock(engine->lock);
- return NULL;
- }
- }
- ps->sc->stream_count++;
-
- /* Add the packet stream to engine */
- silc_list_add(engine->streams, ps);
-
- /* If this is UDP stream, allocate UDP remote stream hash table */
- if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
- engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
- silc_hash_string_compare, NULL,
- silc_packet_engine_hash_destr,
- NULL, TRUE);
-
- silc_mutex_unlock(engine->lock);
-
- /* Set IO notifier callback. This schedules this stream for I/O. */
- if (!silc_stream_set_notifier(ps->stream, schedule,
- silc_packet_stream_io, ps)) {
- SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
- silc_packet_stream_destroy(ps);
- return NULL;
- }
-
- return ps;
-}
-
-/* Add new remote packet stream for UDP packet streams */
-
-SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
- const char *remote_ip,
- SilcUInt16 remote_port,
- SilcPacket packet)
-{
- SilcPacketEngine engine = stream->sc->engine;
- SilcPacketStream ps;
- char *tuple;
- void *tmp;
-
- SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
- remote_ip, remote_port, stream));
-
- if (!stream || !remote_ip || !remote_port)
- return NULL;
-
- if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
- SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
- return NULL;
- }
-
- ps = silc_calloc(1, sizeof(*ps));
- if (!ps)
- return NULL;
- ps->sc = stream->sc;
-
- silc_atomic_init8(&ps->refcnt, 1);
- silc_mutex_alloc(&ps->lock);
-
- /* Set the UDP packet stream as underlaying stream */
- silc_packet_stream_ref(stream);
- ps->stream = (SilcStream)stream;
- ps->udp = TRUE;
-
- /* Allocate out buffer */
- tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
- if (!tmp) {
- silc_packet_stream_destroy(ps);
- 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();
- if (!ps->process) {
- silc_packet_stream_destroy(ps);
- return NULL;
- }
-
- /* Add to engine with this IP and port pair */
- tuple = silc_format("%d%s", remote_port, remote_ip);
- silc_mutex_lock(engine->lock);
- if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
- silc_mutex_unlock(engine->lock);
- silc_packet_stream_destroy(ps);
- return NULL;
- }
- silc_mutex_unlock(engine->lock);
-
- /* Save remote IP and port pair */
- ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
- if (!ps->remote_udp) {
- silc_packet_stream_destroy(ps);
- return NULL;
- }
- ps->remote_udp->remote_port = remote_port;
- ps->remote_udp->remote_ip = strdup(remote_ip);
- if (!ps->remote_udp->remote_ip) {
- silc_packet_stream_destroy(ps);
- return NULL;
- }
-
- if (packet) {
- /* Inject packet to the new stream */
- packet->stream = ps;
- silc_packet_stream_ref(ps);
- silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
- silc_packet_stream_inject_packet, packet,
- 0, 0);
- }
-
- return ps;
-}
-
-/* Destroy packet stream */
-
-void silc_packet_stream_destroy(SilcPacketStream stream)
-{
- SilcPacketEngine engine;
-
- if (!stream)
- return;
-
- if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
- stream->destroyed = TRUE;
-
- /* Close the underlaying stream */
- if (!stream->udp && stream->stream)
- silc_stream_close(stream->stream);
- return;
- }
-
- SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
+/******************************************************************************
- if (!stream->udp) {
- /* Delete from engine */
- engine = stream->sc->engine;
- silc_mutex_lock(engine->lock);
- silc_list_del(engine->streams, stream);
+ Packet Sending Routines
- /* Remove per scheduler context, if it is not used anymore */
- if (stream->sc) {
- stream->sc->stream_count--;
- if (!stream->sc->stream_count)
- silc_hash_table_del(engine->contexts, stream->sc->schedule);
- }
- silc_mutex_unlock(engine->lock);
-
- /* Destroy the underlaying stream */
- if (stream->stream)
- silc_stream_destroy(stream->stream);
- } else {
- /* Delete from UDP remote hash table */
- char tuple[64];
- engine = stream->sc->engine;
- silc_snprintf(tuple, sizeof(tuple), "%d%s",
- stream->remote_udp->remote_port,
- stream->remote_udp->remote_ip);
- silc_mutex_lock(engine->lock);
- silc_hash_table_del(engine->udp_remote, tuple);
- silc_mutex_unlock(engine->lock);
-
- silc_free(stream->remote_udp->remote_ip);
- silc_free(stream->remote_udp);
-
- /* Unreference the underlaying packet stream */
- silc_packet_stream_unref((SilcPacketStream)stream->stream);
- }
-
- /* Clear and free buffers */
- silc_buffer_clear(&stream->outbuf);
- silc_buffer_purge(&stream->outbuf);
-
- if (stream->process) {
- SilcPacketProcess p;
- silc_dlist_start(stream->process);
- while ((p = silc_dlist_get(stream->process))) {
- silc_free(p->types);
- silc_free(p);
- silc_dlist_del(stream->process, p);
- }
- silc_dlist_uninit(stream->process);
- }
-
- /* Destroy ciphers and HMACs */
- if (stream->send_key[0])
- silc_cipher_free(stream->send_key[0]);
- if (stream->receive_key[0])
- silc_cipher_free(stream->receive_key[0]);
- if (stream->send_hmac[0])
- silc_hmac_free(stream->send_hmac[0]);
- if (stream->receive_hmac[0])
- silc_hmac_free(stream->receive_hmac[0]);
- if (stream->send_key[1])
- silc_cipher_free(stream->send_key[1]);
- if (stream->receive_key[1])
- silc_cipher_free(stream->receive_key[1]);
- if (stream->send_hmac[1])
- silc_hmac_free(stream->send_hmac[1]);
- if (stream->receive_hmac[1])
- silc_hmac_free(stream->receive_hmac[1]);
-
- /* Free IDs */
- silc_free(stream->src_id);
- silc_free(stream->dst_id);
-
- silc_atomic_uninit8(&stream->refcnt);
- silc_mutex_free(stream->lock);
- silc_free(stream);
-}
-
-/* Marks as router stream */
-
-void silc_packet_stream_set_router(SilcPacketStream stream)
-{
- stream->is_router = TRUE;
-}
+******************************************************************************/
-/* Mark to include IV in ciphertext */
+/* Actually sends the packet. This flushes the connections outgoing data
+ buffer. If data is sent directly to the network this returns the bytes
+ written, if error occured this returns -1 and if the data could not
+ be written directly to the network at this time this returns -2, in
+ which case the data should be queued by the caller and sent at some
+ later time. If `force_send' is TRUE this attempts to write the data
+ directly to the network, if FALSE, this returns -2. */
-void silc_packet_stream_set_iv_included(SilcPacketStream stream)
+int silc_packet_send(SilcSocketConnection sock, bool force_send)
{
- stream->iv_included = TRUE;
-}
+ SILC_LOG_DEBUG(("Sending packet to %s:%d [%s]", sock->hostname,
+ sock->port,
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router")));
-/* Links `callbacks' to `stream' for specified packet types */
+ /* Send now if forced to do so */
+ if (force_send == TRUE) {
+ int ret;
-static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
- SilcPacketCallbacks *callbacks,
- void *callback_context,
- int priority, va_list ap)
-{
- SilcPacketProcess p, e;
- SilcInt32 packet_type;
- int i;
+ SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
- SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
+ /* Write to network */
+ ret = silc_socket_write(sock);
- 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) {
- silc_mutex_unlock(stream->lock);
- 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);
-
- /* Get packet types to process */
- 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) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
-
- p->types[i - 1] = (SilcPacketType)packet_type;
- i++;
- }
- if (p->types)
- p->types[i - 1] = 0;
-
- silc_mutex_unlock(stream->lock);
-
- silc_packet_stream_ref(stream);
-
- return TRUE;
-}
-
-/* Links `callbacks' to `stream' for specified packet types */
-
-SilcBool silc_packet_stream_link(SilcPacketStream stream,
- SilcPacketCallbacks *callbacks,
- void *callback_context,
- int priority, ...)
-{
- va_list ap;
- SilcBool ret;
-
- va_start(ap, priority);
- ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
- priority, ap);
- va_end(ap);
-
- return ret;
-}
-
-/* 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->types);
- 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);
-}
-
-/* Returns TRUE if stream is UDP stream */
-
-SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
-{
- return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
-}
-
-/* Return packet sender IP and port for UDP packet stream */
-
-SilcBool silc_packet_get_sender(SilcPacket packet,
- const char **sender_ip,
- SilcUInt16 *sender_port)
-{
- if (!packet->stream->remote_udp)
- return FALSE;
-
- *sender_ip = packet->stream->remote_udp->remote_ip;
- *sender_port = packet->stream->remote_udp->remote_port;
-
- return TRUE;
-}
-
-/* Reference packet stream */
-
-void silc_packet_stream_ref(SilcPacketStream stream)
-{
- silc_atomic_add_int8(&stream->refcnt, 1);
- SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
- silc_atomic_get_int8(&stream->refcnt) - 1,
- silc_atomic_get_int8(&stream->refcnt)));
-}
-
-/* Unreference packet stream */
-
-void silc_packet_stream_unref(SilcPacketStream stream)
-{
- SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
- silc_atomic_get_int8(&stream->refcnt),
- silc_atomic_get_int8(&stream->refcnt) - 1));
- if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
- return;
- silc_atomic_add_int8(&stream->refcnt, 1);
- silc_packet_stream_destroy(stream);
-}
-
-/* Return engine */
-
-SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
-{
- return stream->sc->engine;
-}
-
-/* Set application context for packet stream */
-
-void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
-{
- silc_mutex_lock(stream->lock);
- stream->stream_context = stream_context;
- silc_mutex_unlock(stream->lock);
-}
-
-/* Return application context from packet stream */
-
-void *silc_packet_get_context(SilcPacketStream stream)
-{
- void *context;
- silc_mutex_lock(stream->lock);
- context = stream->stream_context;
- silc_mutex_unlock(stream->lock);
- return context;
-}
-
-/* Change underlaying stream */
-
-void silc_packet_stream_set_stream(SilcPacketStream ps,
- SilcStream stream)
-{
- if (ps->stream)
- silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
- ps->stream = stream;
- silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
- ps);
-}
-
-/* Return underlaying stream */
-
-SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
-{
- return stream->stream;
-}
-
-/* Set keys. */
-
-SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
- SilcCipher receive_key, SilcHmac send_hmac,
- SilcHmac receive_hmac, SilcBool rekey)
-{
- SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
-
- /* If doing rekey, send REKEY_DONE packet */
- if (rekey) {
- /* This will take stream lock. */
- if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
- stream->src_id_type, stream->src_id,
- stream->src_id_len, stream->dst_id_type,
- stream->dst_id, stream->dst_id_len,
- NULL, 0, stream->send_key[0],
- stream->send_hmac[0]))
- return FALSE;
-
- /* Write the packet to the stream */
- if (!silc_packet_stream_write(stream, TRUE))
- return FALSE;
- } else {
- silc_mutex_lock(stream->lock);
- }
-
- /* In case IV Included is set, save the old keys */
- if (stream->iv_included) {
- if (stream->send_key[1] && send_key) {
- silc_cipher_free(stream->send_key[1]);
- stream->send_key[1] = stream->send_key[0];
- }
- if (stream->receive_key[1] && receive_key) {
- silc_cipher_free(stream->receive_key[1]);
- stream->receive_key[1] = stream->receive_key[0];
- }
- if (stream->send_hmac[1] && send_hmac) {
- silc_hmac_free(stream->send_hmac[1]);
- stream->send_hmac[1] = stream->send_hmac[0];
- }
- if (stream->receive_hmac[1] && receive_hmac) {
- silc_hmac_free(stream->receive_hmac[1]);
- stream->receive_hmac[1] = stream->receive_hmac[0];
- }
- } else {
- if (stream->send_key[0] && send_key)
- silc_cipher_free(stream->send_key[0]);
- if (stream->receive_key[0] && receive_key)
- silc_cipher_free(stream->receive_key[0]);
- if (stream->send_hmac[0] && send_hmac)
- silc_hmac_free(stream->send_hmac[0]);
- if (stream->receive_hmac[0] && receive_hmac)
- silc_hmac_free(stream->receive_hmac[0]);
- }
-
- /* Set keys */
- if (send_key)
- stream->send_key[0] = send_key;
- if (receive_key)
- stream->receive_key[0] = receive_key;
- if (send_hmac)
- stream->send_hmac[0] = send_hmac;
- if (receive_hmac)
- stream->receive_hmac[0] = receive_hmac;
-
- silc_mutex_unlock(stream->lock);
- return TRUE;
-}
-
-/* Return current ciphers from packet stream */
-
-SilcBool silc_packet_get_keys(SilcPacketStream stream,
- SilcCipher *send_key,
- SilcCipher *receive_key,
- SilcHmac *send_hmac,
- SilcHmac *receive_hmac)
-{
- if (!stream->send_key[0] && !stream->receive_key[0] &&
- !stream->send_hmac[0] && !stream->receive_hmac[0])
- return FALSE;
-
- silc_mutex_lock(stream->lock);
-
- if (send_key)
- *send_key = stream->send_key[0];
- if (receive_key)
- *receive_key = stream->receive_key[0];
- if (send_hmac)
- *send_hmac = stream->send_hmac[0];
- if (receive_hmac)
- *receive_hmac = stream->receive_hmac[0];
-
- silc_mutex_unlock(stream->lock);
-
- return TRUE;
-}
-
-/* Set SILC IDs to packet stream */
-
-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;
-
- SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
-
- silc_mutex_lock(stream->lock);
-
- if (src_id) {
- silc_free(stream->src_id);
- if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
- stream->src_id = silc_memdup(tmp, len);
- if (!stream->src_id) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
- stream->src_id_type = src_id_type;
- stream->src_id_len = len;
- }
-
- if (dst_id) {
- silc_free(stream->dst_id);
- if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
- stream->dst_id = silc_memdup(tmp, len);
- if (!stream->dst_id) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
- stream->dst_id_type = dst_id_type;
- stream->dst_id_len = len;
- }
-
- silc_mutex_unlock(stream->lock);
-
- return TRUE;
-}
-
-/* Adds Security ID (SID) */
-
-SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
-{
- if (!stream->iv_included)
- return FALSE;
-
- SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
-
- stream->sid = sid;
- return TRUE;
-}
-
-/* Free packet */
-
-void silc_packet_free(SilcPacket packet)
-{
- SilcPacketStream stream = packet->stream;
-
- SILC_LOG_DEBUG(("Freeing packet %p", packet));
-
- /* Check for double free */
- SILC_ASSERT(packet->stream != NULL);
-
- packet->stream = NULL;
- packet->src_id = packet->dst_id = NULL;
- silc_buffer_reset(&packet->buffer);
-
- silc_mutex_lock(stream->sc->engine->lock);
-
- /* Put the packet back to freelist */
- silc_list_add(stream->sc->engine->packet_pool, packet);
- if (silc_list_count(stream->sc->engine->packet_pool) == 1)
- silc_list_start(stream->sc->engine->packet_pool);
-
- silc_mutex_unlock(stream->sc->engine->lock);
-}
-
-/****************************** Packet Sending ******************************/
-
-/* Prepare outgoing data buffer for packet sending. Returns the
- pointer to that buffer into the `packet'. */
-
-static inline 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;
-
- /* Allocate more space if needed */
- if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
- if (!silc_buffer_realloc(&stream->outbuf,
- silc_buffer_truelen(&stream->outbuf) + totlen))
- return FALSE;
- }
-
- /* 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);
- silc_buffer_set(packet, oldptr, totlen);
- silc_buffer_push_tail(packet, mac_len);
-
- return TRUE;
-}
-
-/* Increments counter when encrypting in counter mode. */
-
-static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
- SilcCipher cipher,
- unsigned char *ret_iv)
-{
- unsigned char *iv = silc_cipher_get_iv(cipher);
- SilcUInt32 pc1, pc2;
-
- /* Increment 64-bit packet counter */
- SILC_GET32_MSB(pc1, iv + 4);
- SILC_GET32_MSB(pc2, iv + 8);
- if (++pc2 == 0)
- ++pc1;
- SILC_PUT32_MSB(pc1, iv + 4);
- SILC_PUT32_MSB(pc2, iv + 8);
-
- /* Reset block counter */
- memset(iv + 12, 0, 4);
-
- /* If IV Included flag, return the 64-bit IV for inclusion in packet */
- if (stream->iv_included) {
- /* Get new nonce */
- ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
- ret_iv[1] = ret_iv[0] + iv[4];
- ret_iv[2] = ret_iv[0] ^ ret_iv[1];
- ret_iv[3] = ret_iv[0] + ret_iv[2];
- SILC_PUT32_MSB(pc2, ret_iv + 4);
- SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
-
- /* Set new nonce to counter block */
- memcpy(iv + 4, ret_iv, 4);
- }
-
- SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
-}
-
-/* Internal routine to assemble outgoing packet. Assembles and encryptes
- the packet. The silc_packet_stream_write needs to be called to send it
- after this returns TRUE. */
-
-static inline 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], iv[33], psn[4];
- int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
- int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
- SilcBool ctr;
- 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,
- flags, src_id_type, dst_id_type, data_len));
-
- /* Get the true length of the packet. This is saved as payload length
- into the packet header. This does not include the length of the
- padding. */
- data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
- src_id_len + dst_id_len));
- enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
- src_id_len + dst_id_len);
-
- /* If using CTR mode, increment the counter */
- ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
- if (ctr) {
- silc_packet_send_ctr_increment(stream, cipher, iv + 1);
-
- /* If IV is included, the SID, IV and sequence number is added to packet */
- if (stream->iv_included && cipher) {
- psnlen = sizeof(psn);
- ivlen = 8 + 1;
- iv[0] = stream->sid;
- }
- } else {
- /* If IV is included, the SID, IV and sequence number is added to packet */
- if (stream->iv_included && cipher) {
- psnlen = sizeof(psn);
- ivlen = block_len + 1;
- iv[0] = stream->sid;
- memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
- }
- }
-
- /* We automatically figure out the packet structure from the packet
- type and flags, and calculate correct length. Private messages with
- private keys and channel messages are special packets as their
- payload is encrypted already. */
- if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
- flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
- type == SILC_PACKET_CHANNEL_MESSAGE) {
-
- /* Padding is calculated from header + IDs */
- if (!ctr)
- SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
- psnlen), block_len, padlen);
-
- /* Length to encrypt, header + IDs + padding. */
- enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
- padlen + psnlen);
- } else {
-
- /* Padding is calculated from true length of the packet */
- if (flags & SILC_PACKET_FLAG_LONG_PAD)
- SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
- else if (!ctr)
- SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
-
- enclen += padlen + psnlen;
- }
-
- /* 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->sc->engine->rng);
-
- silc_mutex_lock(stream->lock);
-
- /* Get packet pointer from the outgoing buffer */
- if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
- + psnlen, hmac, &packet))) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
-
- SILC_PUT32_MSB(stream->send_psn, psn);
-
- /* Create the packet. This creates the SILC header, adds padding, and
- the actual packet data. */
- i = silc_buffer_format(&packet,
- SILC_STR_DATA(iv, ivlen),
- SILC_STR_DATA(psn, psnlen),
- SILC_STR_UI_SHORT(truelen),
- SILC_STR_UI_CHAR(flags),
- SILC_STR_UI_CHAR(type),
- SILC_STR_UI_CHAR(padlen),
- SILC_STR_UI_CHAR(0),
- SILC_STR_UI_CHAR(src_id_len),
- SILC_STR_UI_CHAR(dst_id_len),
- SILC_STR_UI_CHAR(src_id_type),
- SILC_STR_DATA(src_id, src_id_len),
- SILC_STR_UI_CHAR(dst_id_type),
- SILC_STR_DATA(dst_id, dst_id_len),
- SILC_STR_DATA(tmppad, padlen),
- SILC_STR_DATA(data, data_len),
- SILC_STR_END);
- if (silc_unlikely(i < 0)) {
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
-
- SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
- silc_buffer_data(&packet), silc_buffer_len(&packet));
-
- /* Encrypt the packet */
- if (silc_likely(cipher)) {
- SILC_LOG_DEBUG(("Encrypting packet"));
- silc_cipher_set_iv(cipher, NULL);
- if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
- packet.data + ivlen, enclen,
- NULL))) {
- SILC_LOG_ERROR(("Packet encryption failed"));
- silc_mutex_unlock(stream->lock);
- return FALSE;
- }
- }
-
- /* Compute HMAC */
- if (silc_likely(hmac)) {
- SilcUInt32 mac_len;
-
- /* MAC is computed from the entire encrypted packet data, and put
- to the end of the packet. */
- silc_hmac_init(hmac);
- silc_hmac_update(hmac, psn, sizeof(psn));
- silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
- silc_hmac_final(hmac, packet.tail, &mac_len);
- silc_buffer_pull_tail(&packet, mac_len);
- stream->send_psn++;
- }
-
- return TRUE;
-}
-
-/* Sends a packet */
-
-SilcBool silc_packet_send(SilcPacketStream stream,
- SilcPacketType type, SilcPacketFlags flags,
- const unsigned char *data, SilcUInt32 data_len)
-{
- SilcBool ret;
-
- ret = silc_packet_send_raw(stream, type, flags,
- stream->src_id_type,
- stream->src_id,
- stream->src_id_len,
- stream->dst_id_type,
- stream->dst_id,
- stream->dst_id_len,
- data, data_len,
- stream->send_key[0],
- stream->send_hmac[0]);
-
- /* Write the packet to the stream */
- return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
-}
-
-/* Sends a packet, extended routine */
-
-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)
-{
- unsigned char src_id_data[32], dst_id_data[32];
- SilcUInt32 src_id_len, dst_id_len;
- SilcBool ret;
-
- if (src_id)
- 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;
-
- ret = silc_packet_send_raw(stream, type, flags,
- src_id ? src_id_type : stream->src_id_type,
- src_id ? src_id_data : stream->src_id,
- src_id ? src_id_len : stream->src_id_len,
- dst_id ? dst_id_type : stream->dst_id_type,
- dst_id ? dst_id_data : stream->dst_id,
- dst_id ? dst_id_len : stream->dst_id_len,
- data, data_len,
- cipher ? cipher : stream->send_key[0],
- hmac ? hmac : stream->send_hmac[0]);
-
- /* Write the packet to the stream */
- return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
-}
-
-/* Sends packet after formatting the arguments to buffer */
-
-SilcBool silc_packet_send_va(SilcPacketStream stream,
- SilcPacketType type, SilcPacketFlags flags, ...)
-{
- SilcBufferStruct buf;
- SilcBool ret;
- va_list va;
-
- va_start(va, flags);
-
- memset(&buf, 0, sizeof(buf));
- if (silc_buffer_format_vp(&buf, va) < 0) {
- va_end(va);
- return FALSE;
- }
-
- ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
- silc_buffer_len(&buf));
-
- silc_buffer_purge(&buf);
- va_end(va);
-
- return ret;
-}
-
-/* Sends packet after formatting the arguments to buffer, extended routine */
-
-SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
- SilcPacketType type, SilcPacketFlags flags,
- SilcIdType src_id_type, void *src_id,
- SilcIdType dst_id_type, void *dst_id,
- SilcCipher cipher, SilcHmac hmac, ...)
-{
- SilcBufferStruct buf;
- SilcBool ret;
- va_list va;
-
- va_start(va, hmac);
-
- memset(&buf, 0, sizeof(buf));
- if (silc_buffer_format_vp(&buf, va) < 0) {
- va_end(va);
- return FALSE;
- }
-
- ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
- dst_id_type, dst_id, silc_buffer_data(&buf),
- silc_buffer_len(&buf), cipher, hmac);
-
- silc_buffer_purge(&buf);
- va_end(va);
-
- return TRUE;
-}
-
-/***************************** Packet Receiving *****************************/
-
-/* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
-
-static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
- const unsigned char *data,
- SilcUInt32 data_len,
- const unsigned char *packet_mac,
- const unsigned char *packet_seq,
- SilcUInt32 sequence)
-{
- /* Check MAC */
- if (silc_likely(hmac)) {
- unsigned char mac[32], psn[4];
- SilcUInt32 mac_len;
-
- SILC_LOG_DEBUG(("Verifying MAC"));
-
- /* Compute HMAC of packet */
- silc_hmac_init(hmac);
-
- if (!packet_seq) {
- SILC_PUT32_MSB(sequence, psn);
- silc_hmac_update(hmac, psn, 4);
- } else
- silc_hmac_update(hmac, packet_seq, 4);
-
- silc_hmac_update(hmac, data, data_len);
- silc_hmac_final(hmac, mac, &mac_len);
-
- /* Compare the MAC's */
- if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
- SILC_LOG_DEBUG(("MAC failed"));
- return FALSE;
- }
-
- SILC_LOG_DEBUG(("MAC is Ok"));
- }
-
- return TRUE;
-}
-
-/* Increments/sets counter when decrypting in counter mode. */
-
-static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
- unsigned char *iv,
- unsigned char *packet_iv)
-{
- SilcUInt32 pc1, pc2;
+ if (ret == -1) {
+ SILC_LOG_ERROR(("Error sending packet to %s:%d [%s], dropped: %s",
+ sock->hostname ? sock->hostname : "", sock->port,
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router"), strerror(errno)));
+ }
+ if (ret != -2)
+ return ret;
- /* If IV Included flag, set the IV from packet to block counter. */
- if (stream->iv_included) {
- memcpy(iv + 4, packet_iv, 8);
- } else {
- /* Increment 64-bit packet counter. */
- SILC_GET32_MSB(pc1, iv + 4);
- SILC_GET32_MSB(pc2, iv + 8);
- if (++pc2 == 0)
- ++pc1;
- SILC_PUT32_MSB(pc1, iv + 4);
- SILC_PUT32_MSB(pc2, iv + 8);
+ SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
}
- /* Reset block counter */
- memset(iv + 12, 0, 4);
+ SILC_LOG_DEBUG(("Packet in queue"));
- SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
+ return -2;
}
-/* Decrypts SILC packet. Handles both normal and special packet decryption.
- Return 0 when packet is normal and 1 when it it special, -1 on error. */
+/* Encrypts a packet. This also creates HMAC of the packet before
+ encryption and adds the HMAC at the end of the buffer. This assumes
+ that there is enough free space at the end of the buffer to add the
+ computed HMAC. This is the normal way of encrypting packets, if some
+ other process of HMAC computing and encryption is needed this function
+ cannot be used. */
-static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
- SilcUInt32 sequence, SilcBuffer buffer,
- SilcBool normal)
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
+ SilcBuffer buffer, SilcUInt32 len)
{
- if (normal == TRUE) {
- if (silc_likely(cipher)) {
- /* Decrypt rest of the packet */
- SILC_LOG_DEBUG(("Decrypting the packet"));
- if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
- buffer->data,
- silc_buffer_len(buffer), NULL)))
- return -1;
- }
- return 0;
-
- } else {
- /* Decrypt rest of the header plus padding */
- if (silc_likely(cipher)) {
- SilcUInt16 len;
- SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
- SILC_LOG_DEBUG(("Decrypting the header"));
+ /* Encrypt the data area of the packet. */
+ if (cipher) {
+ SILC_LOG_DEBUG(("Encrypting packet (%d), cipher %s, len %d",
+ sequence, silc_cipher_get_name(cipher), len));
+ silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, NULL);
+ }
- /* Padding length + src id len + dst id len + header length - 16
- bytes already decrypted, gives the rest of the encrypted packet */
- silc_buffer_push(buffer, block_len);
- len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
- (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
- block_len);
- silc_buffer_pull(buffer, block_len);
+ /* Compute HMAC. This assumes that MAC is computed from the entire
+ data area thus this uses the length found in buffer, not the length
+ sent as argument. */
+ if (hmac) {
+ unsigned char mac[32], psn[4];
+ SilcUInt32 mac_len;
- if (silc_unlikely(len > silc_buffer_len(buffer))) {
- SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
- "packet dropped"));
- return -1;
- }
- if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
- buffer->data, len, NULL)))
- return -1;
- }
+ silc_hmac_init(hmac);
+ SILC_PUT32_MSB(sequence, psn);
+ silc_hmac_update(hmac, psn, 4);
+ silc_hmac_update(hmac, buffer->data, buffer->len);
+ silc_hmac_final(hmac, mac, &mac_len);
- return 1;
+ /* Put MAC and pull the it into the visible data area in the buffer */
+ silc_buffer_put_tail(buffer, mac, mac_len);
+ silc_buffer_pull_tail(buffer, mac_len);
}
}
-/* Parses the packet. This is called when a whole packet is ready to be
- parsed. The buffer sent must be already decrypted before calling this
- function. */
+/* Assembles a new packet to be ready for send out. */
-static inline SilcBool silc_packet_parse(SilcPacket packet)
+bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
+ SilcCipher cipher, SilcHmac hmac,
+ SilcSocketConnection sock,
+ const unsigned char *data, SilcUInt32 data_len,
+ const SilcBuffer assembled_packet)
{
- SilcBuffer buffer = &packet->buffer;
- SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
- SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
- int ret;
+ unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
+ unsigned int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
+ int i, ret;
- SILC_LOG_DEBUG(("Parsing incoming packet"));
+ SILC_LOG_DEBUG(("Assembling outgoing packet"));
- /* Parse the buffer. This parses the SILC header of the packet. */
- ret = silc_buffer_unformat(buffer,
- SILC_STR_ADVANCE,
- SILC_STR_OFFSET(6),
- SILC_STR_UI_CHAR(&src_id_len),
- SILC_STR_UI_CHAR(&dst_id_len),
- SILC_STR_UI_CHAR(&src_id_type),
- SILC_STR_END);
- if (silc_unlikely(ret == -1)) {
- if (!packet->stream->udp &&
- !silc_socket_stream_is_udp(packet->stream->stream, NULL))
- SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
- return FALSE;
- }
+ /* Calculate the packet's length and padding length if upper layer
+ didn't already do it. */
- if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
- dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
- if (!packet->stream->udp &&
- !silc_socket_stream_is_udp(packet->stream->stream, NULL))
- SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
- packet->src_id_len, packet->dst_id_len));
- return FALSE;
+ /* Get the true length of the packet. This is saved as payload length
+ into the packet header. This does not include the length of the
+ padding. */
+ if (!packet->truelen) {
+ data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
+ packet->src_id_len + packet->dst_id_len);
+ packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packet->src_id_len + packet->dst_id_len;
+ }
+
+ /* Calculate the length of the padding. The padding is calculated from
+ the data that will be encrypted. */
+ if (!packet->padlen) {
+ if (packet->long_pad)
+ SILC_PACKET_PADLEN_MAX(packet->truelen, block_len, packet->padlen);
+ else
+ SILC_PACKET_PADLEN(packet->truelen, block_len, packet->padlen);
}
- ret = silc_buffer_unformat(buffer,
- SILC_STR_ADVANCE,
- SILC_STR_DATA(&packet->src_id, src_id_len),
- SILC_STR_UI_CHAR(&dst_id_type),
- SILC_STR_DATA(&packet->dst_id, dst_id_len),
- SILC_STR_OFFSET(padlen),
- SILC_STR_END);
- if (silc_unlikely(ret == -1)) {
- if (!packet->stream->udp &&
- !silc_socket_stream_is_udp(packet->stream->stream, NULL))
- SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
- return FALSE;
- }
+ /* Now prepare the outgoing data buffer for packet sending and start
+ assembling the packet. */
- if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
- dst_id_type > SILC_ID_CHANNEL)) {
- if (!packet->stream->udp &&
- !silc_socket_stream_is_udp(packet->stream->stream, NULL))
- SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
- src_id_type, dst_id_type));
+ /* Return pointer to the assembled packet */
+ if (!silc_packet_send_prepare(sock, packet->truelen - data_len,
+ packet->padlen, data_len, hmac,
+ assembled_packet))
return FALSE;
- }
- packet->src_id_len = src_id_len;
- packet->dst_id_len = dst_id_len;
- packet->src_id_type = src_id_type;
- packet->dst_id_type = dst_id_type;
+ /* Get random padding */
+ if (rng)
+ for (i = 0; i < packet->padlen; i++) tmppad[i] =
+ silc_rng_get_byte_fast(rng);
+ else
+ for (i = 0; i < packet->padlen; i++) tmppad[i] =
+ silc_rng_global_get_byte_fast();
- SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
- silc_buffer_len(buffer)), buffer->head,
- silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
+ /* Create the packet. This creates the SILC header, adds padding, and
+ the actual packet data. */
+ ret =
+ silc_buffer_format(assembled_packet,
+ SILC_STR_UI_SHORT(packet->truelen),
+ SILC_STR_UI_CHAR(packet->flags),
+ SILC_STR_UI_CHAR(packet->type),
+ SILC_STR_UI_CHAR(packet->padlen),
+ SILC_STR_UI_CHAR(0),
+ SILC_STR_UI_CHAR(packet->src_id_len),
+ SILC_STR_UI_CHAR(packet->dst_id_len),
+ SILC_STR_UI_CHAR(packet->src_id_type),
+ SILC_STR_UI_XNSTRING(packet->src_id,
+ packet->src_id_len),
+ SILC_STR_UI_CHAR(packet->dst_id_type),
+ SILC_STR_UI_XNSTRING(packet->dst_id,
+ packet->dst_id_len),
+ SILC_STR_UI_XNSTRING(tmppad, packet->padlen),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_END);
+ if (ret < 0)
+ return FALSE;
- SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
- silc_get_packet_name(packet->type)));
+ SILC_LOG_HEXDUMP(("Assembled packet, len %d", assembled_packet->len),
+ assembled_packet->data, assembled_packet->len);
return TRUE;
}
-/* Dispatch packet to application. Called with stream->lock locked.
- Returns FALSE if the stream was destroyed while dispatching a packet. */
+/* Prepare outgoing data buffer for packet sending. This moves the data
+ area so that new packet may be added into it. If needed this allocates
+ more space to the buffer. This handles directly the connection's
+ outgoing buffer in SilcSocketConnection object, and returns the
+ pointer to that buffer into the `packet'. */
-static SilcBool silc_packet_dispatch(SilcPacket packet)
+bool silc_packet_send_prepare(SilcSocketConnection sock,
+ SilcUInt32 header_len,
+ SilcUInt32 pad_len,
+ SilcUInt32 data_len,
+ SilcHmac hmac,
+ const SilcBuffer packet)
{
- SilcPacketStream stream = packet->stream;
- SilcPacketProcess p;
- SilcBool default_sent = FALSE;
- SilcPacketType *pt;
-
- /* Dispatch packet to all packet processors that want it */
-
- if (silc_likely(!stream->process)) {
- /* Send to default processor as no others exist */
- SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
- silc_mutex_unlock(stream->lock);
- if (silc_unlikely(!stream->sc->engine->callbacks->
- packet_receive(stream->sc->engine, stream, packet,
- stream->sc->engine->callback_context,
- stream->stream_context)))
- silc_packet_free(packet);
- silc_mutex_lock(stream->lock);
- return stream->destroyed == FALSE;
- }
+ SilcUInt32 totlen;
+ unsigned char *oldptr;
+ unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
- 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;
- silc_mutex_unlock(stream->lock);
- if (stream->sc->engine->callbacks->
- packet_receive(stream->sc->engine, stream, packet,
- stream->sc->engine->callback_context,
- stream->stream_context)) {
- silc_mutex_lock(stream->lock);
- return stream->destroyed == FALSE;
- }
- silc_mutex_lock(stream->lock);
- }
+ if (!packet)
+ return FALSE;
- /* Send to processor */
- if (!p->types) {
- /* Send all packet types */
- SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
- silc_mutex_unlock(stream->lock);
- if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
- p->callback_context,
- stream->stream_context)) {
- silc_mutex_lock(stream->lock);
- return stream->destroyed == FALSE;
- }
- silc_mutex_lock(stream->lock);
- } else {
- /* Send specific types */
- for (pt = p->types; *pt; pt++) {
- if (*pt != packet->type)
- continue;
- SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
- silc_mutex_unlock(stream->lock);
- if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
- p->callback_context,
- stream->stream_context)) {
- silc_mutex_lock(stream->lock);
- return stream->destroyed == FALSE;
- }
- silc_mutex_lock(stream->lock);
- break;
- }
+ totlen = header_len + pad_len + data_len;
+
+ /* Prepare the outgoing buffer for packet sending. */
+ if (!sock->outbuf) {
+ /* Allocate new buffer. This is done only once per connection. */
+ SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
+
+ sock->outbuf = silc_buffer_alloc(totlen > SILC_PACKET_DEFAULT_SIZE ?
+ totlen : SILC_PACKET_DEFAULT_SIZE);
+ if (!sock->outbuf)
+ return FALSE;
+ } else {
+ if (!SILC_IS_OUTBUF_PENDING(sock)) {
+ /* Buffer is free for use */
+ silc_buffer_clear(sock->outbuf);
}
}
- if (!default_sent) {
- /* Send to default processor as it has not been sent yet */
- SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
- silc_mutex_unlock(stream->lock);
- if (stream->sc->engine->callbacks->
- packet_receive(stream->sc->engine, stream, packet,
- stream->sc->engine->callback_context,
- stream->stream_context)) {
- silc_mutex_lock(stream->lock);
- return stream->destroyed == FALSE;
- }
- silc_mutex_lock(stream->lock);
+ /* Allocate more space if needed */
+ if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + mac_len)) {
+ SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+ sock->outbuf = silc_buffer_realloc(sock->outbuf,
+ sock->outbuf->truelen + (totlen * 2));
+ if (!sock->outbuf)
+ return FALSE;
}
- /* If we got here, no one wanted the packet, so drop it */
- silc_packet_free(packet);
- return stream->destroyed == FALSE;
+ /* 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'. */
+ oldptr = silc_buffer_pull_tail(sock->outbuf, totlen + mac_len);
+ silc_buffer_set(packet, oldptr, totlen + mac_len);
+ silc_buffer_push_tail(packet, mac_len);
+
+ return TRUE;
+}
+
+/******************************************************************************
+
+ Packet Reception Routines
+
+******************************************************************************/
+
+static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+ SilcUInt32 sequence, SilcBuffer buffer,
+ bool normal);
+static bool silc_packet_check_mac(SilcHmac hmac,
+ const unsigned char *data,
+ SilcUInt32 data_len,
+ const unsigned char *packet_mac,
+ SilcUInt32 sequence);
+
+/* Receives packet from network and reads the data into connection's
+ incoming data buffer. If the data was read directly this returns the
+ read bytes, if error occured this returns -1, if the data could not
+ be read directly at this time this returns -2 in which case the data
+ should be read again at some later time, or If EOF occured this returns
+ 0. */
+
+int silc_packet_receive(SilcSocketConnection sock)
+{
+ int ret;
+
+ SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
+ sock->port,
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router")));
+
+ /* Read some data from connection */
+ ret = silc_socket_read(sock);
+
+ return ret;
}
-/* Process incoming data and parse packets. Called with stream->lock
- locked. */
+/* Processes and decrypts the incmoing data, and calls parser callback
+ for each received packet that will handle the actual packet parsing.
+ If more than one packet was received this calls the parser multiple
+ times. The parser callback will get context SilcPacketParserContext
+ that includes the packet and the `parser_context' sent to this
+ function.
-static void silc_packet_read_process(SilcPacketStream stream)
+ The `local_is_router' indicates whether the caller is router server
+ in which case the receiving process of a certain packet types may
+ be special. Normal server and client must set it to FALSE. The
+ SilcPacketParserContext will indicate also whether the received
+ packet was normal or special packet. */
+
+bool silc_packet_receive_process(SilcSocketConnection sock,
+ bool local_is_router,
+ SilcCipher cipher, SilcHmac hmac,
+ SilcUInt32 sequence,
+ SilcPacketParserCallback parser,
+ void *parser_context)
{
- SilcBuffer inbuf;
- SilcCipher cipher;
- SilcHmac hmac;
- SilcPacket packet;
- SilcUInt8 sid;
+ SilcPacketParserContext *parse_ctx;
SilcUInt16 packetlen;
- SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
- unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
- unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
- SilcBool normal;
+ SilcUInt32 paddedlen, mac_len = 0, block_len;
int ret;
+ bool cont = TRUE;
+ unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
- /* Get inbuf. If there is already some data for this stream in the buffer
- we already have it. Otherwise get the current one from list, it will
- include the data. */
- inbuf = stream->inbuf;
- if (!inbuf) {
- silc_dlist_start(stream->sc->inbufs);
- inbuf = silc_dlist_get(stream->sc->inbufs);
- }
+ /* Do not process for disconnected connection */
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
+ return TRUE;
+
+ if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
+ return TRUE;
+
+ if (hmac)
+ mac_len = silc_hmac_len(hmac);
/* Parse the packets from the data */
- while (silc_buffer_len(inbuf) > 0) {
- ivlen = psnlen = 0;
- cipher = stream->receive_key[0];
- hmac = stream->receive_hmac[0];
- normal = FALSE;
-
- if (silc_unlikely(silc_buffer_len(inbuf) <
- (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
- SILC_PACKET_MIN_HEADER_LEN))) {
+ silc_socket_dup(sock);
+ while (sock->inbuf->len > 0 && cont) {
+
+ if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) {
SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
- silc_dlist_del(stream->sc->inbufs, inbuf);
- stream->inbuf = inbuf;
- return;
+ silc_socket_free(sock);
+ return TRUE;
}
- if (silc_likely(hmac))
- mac_len = silc_hmac_len(hmac);
- else
- mac_len = 0;
-
/* Decrypt first block of the packet to get the length field out */
- if (silc_likely(cipher)) {
+ if (cipher) {
block_len = silc_cipher_get_block_len(cipher);
-
- if (stream->iv_included) {
- /* SID, IV and sequence number is included in the ciphertext */
- sid = (SilcUInt8)inbuf->data[0];
-
- if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
- /* Set the CTR mode IV from packet to counter block */
- memcpy(iv, silc_cipher_get_iv(cipher), block_len);
- silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
- ivlen = 8 + 1;
- } else {
- /* Get IV from packet */
- memcpy(iv, inbuf->data + 1, block_len);
- ivlen = block_len + 1;
- }
- psnlen = 4;
-
- /* Check SID, and get correct decryption key */
- if (sid != stream->sid) {
- /* If SID is recent get the previous key and use it */
- if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
- stream->receive_key[1] && !stream->receive_hmac[1]) {
- cipher = stream->receive_key[1];
- hmac = stream->receive_hmac[1];
- } else {
- /* The SID is unknown, drop rest of the data in buffer */
- SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
- sid, stream->sid));
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
- silc_mutex_lock(stream->lock);
- goto out;
- }
- }
- } else {
- memcpy(iv, silc_cipher_get_iv(cipher), block_len);
-
- /* If using CTR mode, increment the counter */
- if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
- silc_packet_receive_ctr_increment(stream, iv, NULL);
- }
-
- if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
- silc_cipher_set_iv(cipher, NULL);
- silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
-
+ memcpy(iv, silc_cipher_get_iv(cipher), block_len);
+ silc_cipher_decrypt(cipher, sock->inbuf->data, tmp, block_len, iv);
header = tmp;
- if (stream->iv_included) {
- /* Take sequence number from packet */
- packet_seq = header;
- header += 4;
- }
} else {
- /* Unencrypted packet */
block_len = SILC_PACKET_MIN_HEADER_LEN;
- header = inbuf->data;
+ header = sock->inbuf->data;
}
- /* Get packet length and full packet length with padding */
+ /* Get packet lenght and full packet length with padding */
SILC_PACKET_LENGTH(header, packetlen, paddedlen);
/* Sanity checks */
- if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
- if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
- SILC_LOG_ERROR(("Received too short packet"));
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
- silc_mutex_lock(stream->lock);
- memset(tmp, 0, sizeof(tmp));
- goto out;
+ if (packetlen < SILC_PACKET_MIN_LEN) {
+ SILC_LOG_ERROR(("Received too short packet"));
+ memset(header, 0, sizeof(header));
+ silc_buffer_clear(sock->inbuf);
+ silc_socket_free(sock);
+ return FALSE;
}
- if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
+ if (sock->inbuf->len < paddedlen + mac_len) {
SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
- "(%d bytes)",
- paddedlen + mac_len - silc_buffer_len(inbuf)));
+ "(%d bytes)", paddedlen + mac_len - sock->inbuf->len));
+ SILC_SET_INBUF_PENDING(sock);
memset(tmp, 0, sizeof(tmp));
- silc_dlist_del(stream->sc->inbufs, inbuf);
- stream->inbuf = inbuf;
- return;
+ silc_socket_free(sock);
+ return TRUE;
}
/* Check MAC of the packet */
- if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
- paddedlen + ivlen,
- inbuf->data + ivlen +
- paddedlen, packet_seq,
- stream->receive_psn))) {
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
- silc_mutex_lock(stream->lock);
+ if (!silc_packet_check_mac(hmac, sock->inbuf->data, paddedlen,
+ sock->inbuf->data + paddedlen, sequence)) {
+ SILC_LOG_WARNING(("Packet MAC check failed %s:%d "
+ "[%s type %d len %dB blen %dB seq %d] [%s] proto %d",
+ sock->hostname, sock->port,
+ silc_get_packet_name(header[3]),
+ header[3], paddedlen, sock->inbuf->len, sequence,
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router"),
+ sock->protocol ? sock->protocol->protocol->type : -1));
memset(tmp, 0, sizeof(tmp));
- goto out;
+ silc_buffer_clear(sock->inbuf);
+ silc_socket_free(sock);
+ return FALSE;
}
- /* Get packet */
- packet = silc_packet_alloc(stream->sc->engine);
- if (silc_unlikely(!packet)) {
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
- silc_mutex_lock(stream->lock);
- memset(tmp, 0, sizeof(tmp));
- goto out;
- }
- packet->stream = stream;
-
- /* Allocate more space to packet buffer, if needed */
- if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
- if (!silc_buffer_realloc(&packet->buffer,
- silc_buffer_truelen(&packet->buffer) +
- (paddedlen -
- silc_buffer_truelen(&packet->buffer)))) {
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
- silc_mutex_lock(stream->lock);
- silc_packet_free(packet);
- memset(tmp, 0, sizeof(tmp));
- goto out;
- }
+ SILC_UNSET_INBUF_PENDING(sock);
+ parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
+ if (!parse_ctx) {
+ silc_socket_free(sock);
+ return FALSE;
}
-
- /* Parse packet header */
- packet->flags = (SilcPacketFlags)header[2];
- packet->type = (SilcPacketType)header[3];
-
- if (stream->sc->engine->local_is_router) {
- if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
- (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
- normal = FALSE;
- else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
- (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
- stream->is_router == TRUE))
- normal = TRUE;
+ parse_ctx->packet = silc_packet_context_alloc();
+ parse_ctx->packet->buffer = silc_buffer_alloc_size(paddedlen);
+ parse_ctx->packet->type = (SilcPacketType)header[3];
+ parse_ctx->packet->padlen = (SilcUInt8)header[4];
+ parse_ctx->packet->sequence = sequence++;
+ parse_ctx->sock = sock;
+ parse_ctx->context = parser_context;
+
+ /* Check whether this is normal or special packet */
+ if (local_is_router) {
+ if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+ (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+ parse_ctx->normal = FALSE;
+ else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE ||
+ (header[3] == SILC_PACKET_CHANNEL_MESSAGE &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER))
+ parse_ctx->normal = TRUE;
} else {
- if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
- (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
- normal = FALSE;
- else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
- normal = TRUE;
+ if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+ (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+ parse_ctx->normal = FALSE;
+ else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE)
+ parse_ctx->normal = TRUE;
}
SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
- stream->receive_psn, paddedlen + ivlen + mac_len),
- inbuf->data, paddedlen + ivlen + mac_len);
+ sequence - 1, paddedlen + mac_len),
+ sock->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 - psnlen);
- silc_buffer_pull(&packet->buffer, block_len - psnlen);
- silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
- psnlen + (block_len - psnlen)),
- paddedlen - ivlen - psnlen - (block_len - psnlen));
- if (silc_likely(cipher)) {
+ silc_buffer_put(parse_ctx->packet->buffer, header, block_len);
+ silc_buffer_pull(parse_ctx->packet->buffer, block_len);
+ silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data + block_len,
+ paddedlen - block_len);
+ if (cipher) {
silc_cipher_set_iv(cipher, iv);
- ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
- &packet->buffer, normal);
- if (silc_unlikely(ret < 0)) {
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
- silc_mutex_lock(stream->lock);
- silc_packet_free(packet);
+ ret = silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence,
+ parse_ctx->packet->buffer,
+ parse_ctx->normal);
+ if (ret < 0) {
+ SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]",
+ sock->hostname, sock->port,
+ silc_get_packet_name(parse_ctx->packet->type),
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router")));
memset(tmp, 0, sizeof(tmp));
- goto out;
+ silc_packet_context_free(parse_ctx->packet);
+ silc_free(parse_ctx);
+ silc_socket_free(sock);
+ return FALSE;
}
-
- stream->receive_psn++;
}
- silc_buffer_push(&packet->buffer, block_len);
+ silc_buffer_push(parse_ctx->packet->buffer, block_len);
- /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
- silc_buffer_pull(inbuf, paddedlen + mac_len);
+ SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d",
+ parse_ctx->packet->buffer->len),
+ parse_ctx->packet->buffer->data,
+ parse_ctx->packet->buffer->len);
- /* Parse the packet */
- if (silc_unlikely(!silc_packet_parse(packet))) {
- silc_mutex_unlock(stream->lock);
- SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
- silc_mutex_lock(stream->lock);
- silc_packet_free(packet);
- memset(tmp, 0, sizeof(tmp));
- goto out;
+ /* Pull the packet from inbuf thus we'll get the next one
+ in the inbuf. */
+ silc_buffer_pull(sock->inbuf, paddedlen + mac_len);
+
+ /* Call the parser */
+ cont = (*parser)(parse_ctx, parser_context);
+
+ /* See if socket disconnected while parsing the packet */
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+ SILC_LOG_DEBUG(("Abandoning packet processing, socket disconnected"));
+ cont = FALSE;
}
- /* Dispatch the packet to application */
- if (!silc_packet_dispatch(packet))
- break;
+ memset(tmp, 0, sizeof(tmp));
}
- out:
- /* Add inbuf back to free list, if we owned it. */
- if (stream->inbuf) {
- silc_dlist_add(stream->sc->inbufs, inbuf);
- stream->inbuf = NULL;
+ /* Don't clear buffer if pending data is in the buffer */
+ if (cont == FALSE && sock->inbuf->len > 0) {
+ silc_socket_free(sock);
+ return TRUE;
}
- silc_buffer_reset(inbuf);
-}
+ /* Don't clear buffer if QoS data exists in the buffer */
+ if (sock->qos && sock->qos->data_len > 0) {
+ silc_socket_free(sock);
+ return TRUE;
+ }
-/****************************** Packet Waiting ******************************/
+ SILC_LOG_DEBUG(("Clearing inbound buffer"));
+ silc_buffer_clear(sock->inbuf);
+ silc_socket_free(sock);
+ return TRUE;
+}
-/* Packet wait receive callback */
-static SilcBool
-silc_packet_wait_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context);
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
-/* Packet waiting callbacks */
-static SilcPacketCallbacks silc_packet_wait_cbs =
-{
- silc_packet_wait_packet_receive, NULL, NULL
-};
-
-/* Packet waiting context */
-typedef struct {
- SilcMutex wait_lock;
- SilcCond wait_cond;
- SilcList packet_queue;
- unsigned int stopped : 1;
-} *SilcPacketWait;
-
-/* Packet wait receive callback */
-
-static SilcBool
-silc_packet_wait_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context)
+static bool silc_packet_check_mac(SilcHmac hmac,
+ const unsigned char *data,
+ SilcUInt32 data_len,
+ const unsigned char *packet_mac,
+ SilcUInt32 sequence)
{
- SilcPacketWait pw = callback_context;
+ /* Check MAC */
+ if (hmac) {
+ unsigned char mac[32], psn[4];
+ SilcUInt32 mac_len;
- /* Signal the waiting thread for a new packet */
- silc_mutex_lock(pw->wait_lock);
+ SILC_LOG_DEBUG(("Verifying MAC"));
- if (silc_unlikely(pw->stopped)) {
- silc_mutex_unlock(pw->wait_lock);
- return FALSE;
- }
+ /* Compute HMAC of packet */
+ silc_hmac_init(hmac);
+ SILC_PUT32_MSB(sequence, psn);
+ silc_hmac_update(hmac, psn, 4);
+ silc_hmac_update(hmac, data, data_len);
+ silc_hmac_final(hmac, mac, &mac_len);
- silc_list_add(pw->packet_queue, packet);
- silc_cond_broadcast(pw->wait_cond);
+ /* Compare the MAC's */
+ if (memcmp(packet_mac, mac, mac_len)) {
+ SILC_LOG_ERROR(("MAC failed"));
+ return FALSE;
+ }
- silc_mutex_unlock(pw->wait_lock);
+ SILC_LOG_DEBUG(("MAC is Ok"));
+ }
return TRUE;
}
-/* Initialize packet waiting */
+/* Decrypts SILC packet. Handles both normal and special packet decryption.
+ Return 0 when packet is normal and 1 when it it special, -1 on error. */
-void *silc_packet_wait_init(SilcPacketStream stream, ...)
+static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+ SilcUInt32 sequence, SilcBuffer buffer,
+ bool normal)
{
- SilcPacketWait pw;
- SilcBool ret;
- va_list ap;
-
- pw = silc_calloc(1, sizeof(*pw));
- if (!pw)
- return NULL;
-
- /* Allocate mutex and conditional variable */
- if (!silc_mutex_alloc(&pw->wait_lock)) {
- silc_free(pw);
- return NULL;
- }
- if (!silc_cond_alloc(&pw->wait_cond)) {
- silc_mutex_free(pw->wait_lock);
- silc_free(pw);
- return NULL;
- }
+ /* If the packet type is not any special type lets decrypt rest
+ of the packet here. */
+ if (normal == TRUE) {
+ if (cipher) {
+ /* Decrypt rest of the packet */
+ SILC_LOG_DEBUG(("Decrypting the packet"));
+ if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
+ buffer->len, NULL)) {
+ SILC_LOG_ERROR(("silc_cipher_decrypt failed"));
+ return -1;
+ }
+ }
+ return 0;
- /* Link to the packet stream for the requested packet types */
- va_start(ap, stream);
- ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
- 10000000, ap);
- va_end(ap);
- if (!ret) {
- silc_cond_free(pw->wait_cond);
- silc_mutex_free(pw->wait_lock);
- silc_free(pw);
- return NULL;
- }
+ } else {
+ /* Decrypt rest of the header plus padding */
+ if (cipher) {
+ SilcUInt16 len;
+ SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
- /* Initialize packet queue */
- silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
+ SILC_LOG_DEBUG(("Decrypting the header"));
- return (void *)pw;
-}
+ /* padding length + src id len + dst id len + header length - 16
+ bytes already decrypted, gives the rest of the encrypted packet */
+ silc_buffer_push(buffer, block_len);
+ len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
+ (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
+ block_len);
+ silc_buffer_pull(buffer, block_len);
-/* Uninitialize packet waiting */
+ if (len > buffer->len) {
+ SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
+ "packet dropped"));
+ return -1;
+ }
+ if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
+ len, NULL)) {
+ SILC_LOG_ERROR(("silc_cipher_decrypt failed"));
+ return -1;
+ }
+ }
-void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
-{
- SilcPacketWait pw = waiter;
- SilcPacket packet;
-
- /* Signal any threads to stop waiting */
- silc_mutex_lock(pw->wait_lock);
- pw->stopped = TRUE;
- silc_cond_broadcast(pw->wait_cond);
- silc_mutex_unlock(pw->wait_lock);
-
- /* Re-acquire lock and free resources */
- silc_mutex_lock(pw->wait_lock);
- silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
-
- /* Free any remaining packets */
- silc_list_start(pw->packet_queue);
- while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
- silc_packet_free(packet);
-
- silc_mutex_unlock(pw->wait_lock);
- silc_cond_free(pw->wait_cond);
- silc_mutex_free(pw->wait_lock);
- silc_free(pw);
+ return 1;
+ }
}
-/* Blocks thread until a packet has been received. */
+/* Parses the packet. This is called when a whole packet is ready to be
+ parsed. The buffer sent must be already decrypted before calling this
+ function. The len argument must be the true length of the packet. This
+ function returns the type of the packet. The data section of the
+ buffer is parsed, not head or tail sections. */
-int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
{
- SilcPacketWait pw = waiter;
- SilcBool ret = FALSE;
+ SilcBuffer buffer = ctx->buffer;
+ SilcUInt8 tmp;
+ int len, ret;
+ SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
- silc_mutex_lock(pw->wait_lock);
+ SILC_LOG_DEBUG(("Parsing incoming packet"));
- /* Wait here until packet has arrived */
- while (silc_list_count(pw->packet_queue) == 0) {
- if (silc_unlikely(pw->stopped)) {
- silc_mutex_unlock(pw->wait_lock);
- return -1;
- }
- ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
+ /* Check the length of the buffer */
+ if (buffer->len < SILC_PACKET_MIN_LEN) {
+ SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
+ return SILC_PACKET_NONE;
}
- /* Return packet */
- silc_list_start(pw->packet_queue);
- *return_packet = silc_list_get(pw->packet_queue);
- silc_list_del(pw->packet_queue, *return_packet);
+ /* Parse the buffer. This parses the SILC header of the packet. */
+ len = silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&ctx->truelen),
+ SILC_STR_UI_CHAR(&ctx->flags),
+ SILC_STR_UI_CHAR(&ctx->type),
+ SILC_STR_UI_CHAR(&padlen),
+ SILC_STR_UI_CHAR(&tmp),
+ SILC_STR_UI_CHAR(&src_id_len),
+ SILC_STR_UI_CHAR(&dst_id_len),
+ SILC_STR_UI_CHAR(&src_id_type),
+ SILC_STR_END);
+ if (len == -1 || tmp != 0)
+ return SILC_PACKET_NONE;
- silc_mutex_unlock(pw->wait_lock);
+ if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
+ dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+ SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
+ src_id_len, dst_id_len));
+ return SILC_PACKET_NONE;
+ }
- return ret == TRUE ? 1 : 0;
-}
+ silc_buffer_pull(buffer, len);
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+ src_id_len),
+ SILC_STR_UI_CHAR(&dst_id_type),
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+ dst_id_len),
+ SILC_STR_UI_XNSTRING(NULL, padlen),
+ SILC_STR_END);
+ if (ret == -1)
+ return SILC_PACKET_NONE;
-/************************** Packet Stream Wrapper ***************************/
-
-/* Packet stream wrapper receive callback */
-static SilcBool
-silc_packet_wrap_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context);
-
-const SilcStreamOps silc_packet_stream_ops;
-
-/* Packet stream wrapper context */
-typedef struct {
- const SilcStreamOps *ops;
- SilcPacketStream stream;
- SilcMutex lock;
- void *waiter; /* Waiter context in blocking mode */
- SilcPacketWrapCoder coder;
- void *coder_context;
- SilcBuffer encbuf;
- SilcStreamNotifier callback;
- void *context;
- SilcList in_queue;
- SilcPacketType type;
- SilcPacketFlags flags;
- unsigned int closed : 1;
- unsigned int blocking : 1;
- unsigned int read_more : 1;
-} *SilcPacketWrapperStream;
-
-/* Packet wrapper callbacks */
-static SilcPacketCallbacks silc_packet_wrap_cbs =
-{
- silc_packet_wrap_packet_receive, NULL, NULL
-};
+ if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
+ SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
+ src_id_type, dst_id_type));
+ return SILC_PACKET_NONE;
+ }
-/* Packet stream wrapper receive callback, non-blocking mode */
+ ctx->src_id_len = src_id_len;
+ ctx->dst_id_len = dst_id_len;
+ ctx->src_id_type = src_id_type;
+ ctx->dst_id_type = dst_id_type;
+ ctx->padlen = padlen;
-static SilcBool
-silc_packet_wrap_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context)
-{
- SilcPacketWrapperStream pws = callback_context;
+ silc_buffer_push(buffer, len);
- if (pws->closed || !pws->callback)
- return FALSE;
+ SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
+ ctx->buffer->data, ctx->buffer->len);
- silc_mutex_lock(pws->lock);
- silc_list_add(pws->in_queue, packet);
- silc_mutex_unlock(pws->lock);
+ /* Pull SILC header and padding from packet */
+ silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
+ ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
- /* Call notifier callback */
- pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
+ SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
- return TRUE;
+ return ctx->type;
}
-/* Task callback to notify more data is available for reading */
+/* Perform special SILC Packet header parsing. This is required to some
+ packet types that have the data payload encrypted with different key
+ than the header area plus padding of the packet. Hence, this parses
+ the header in a way that it does not take the data area into account
+ and parses the header and padding area only. */
-SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
+ SilcCipher cipher)
{
- SilcPacketWrapperStream pws = context;
-
- if (pws->closed || !pws->callback)
- return;
+ SilcBuffer buffer = ctx->buffer;
+ SilcUInt8 tmp;
+ int len, ret;
+ SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
- /* Call notifier callback */
- pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
-}
-
-/* Read SILC packet */
-
-int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- SilcPacketWrapperStream pws = stream;
- SilcPacket packet;
- SilcBool read_more = FALSE;
- int len;
-
- if (pws->closed)
- return -2;
-
- if (pws->blocking) {
- /* Block until packet is received */
- if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
- return -2;
- if (pws->closed)
- return -2;
- } else {
- /* Non-blocking mode */
- silc_mutex_lock(pws->lock);
- if (!silc_list_count(pws->in_queue)) {
- silc_mutex_unlock(pws->lock);
- return -1;
- }
+ SILC_LOG_DEBUG(("Parsing incoming packet"));
- silc_list_start(pws->in_queue);
- packet = silc_list_get(pws->in_queue);
- silc_list_del(pws->in_queue, packet);
- silc_mutex_unlock(pws->lock);
+ /* Check the length of the buffer */
+ if (buffer->len < SILC_PACKET_MIN_LEN) {
+ SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
+ return SILC_PACKET_NONE;
}
- /* Call decoder if set */
- if (pws->coder && !pws->read_more)
- pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
- pws->coder_context);
-
- len = silc_buffer_len(&packet->buffer);
- if (len > buf_len) {
- len = buf_len;
- read_more = TRUE;
+ /* Parse the buffer. This parses the SILC header of the packet. */
+ len = silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&ctx->truelen),
+ SILC_STR_UI_CHAR(&ctx->flags),
+ SILC_STR_UI_CHAR(&ctx->type),
+ SILC_STR_UI_CHAR(&padlen),
+ SILC_STR_UI_CHAR(&tmp),
+ SILC_STR_UI_CHAR(&src_id_len),
+ SILC_STR_UI_CHAR(&dst_id_len),
+ SILC_STR_UI_CHAR(&src_id_type),
+ SILC_STR_END);
+ if (len == -1 || tmp != 0) {
+ SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
+ return SILC_PACKET_NONE;
}
- /* Read data */
- memcpy(buf, packet->buffer.data, len);
-
- if (read_more && !pws->blocking) {
- /* More data will be available (in blocking mode not supported). */
- silc_buffer_pull(&packet->buffer, len);
- silc_list_insert(pws->in_queue, NULL, packet);
- silc_schedule_task_add_timeout(pws->stream->sc->schedule,
- silc_packet_wrap_read_more, pws, 0, 0);
- pws->read_more = TRUE;
- return len;
+ if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
+ dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+ SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
+ src_id_len, dst_id_len));
+ return SILC_PACKET_NONE;
}
- pws->read_more = FALSE;
- silc_packet_free(packet);
- return len;
-}
-
-/* Write SILC packet */
-
-int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcPacketWrapperStream pws = stream;
- SilcBool ret = FALSE;
-
- /* Call decoder if set */
- if (pws->coder) {
- silc_buffer_reset(pws->encbuf);
- ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
- pws->coder_context);
+ silc_buffer_pull(buffer, len);
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+ src_id_len),
+ SILC_STR_UI_CHAR(&dst_id_type),
+ SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+ dst_id_len),
+ SILC_STR_UI_XNSTRING(NULL, padlen),
+ SILC_STR_END);
+ if (ret == -1) {
+ SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
+ return SILC_PACKET_NONE;
}
- /* Send the SILC packet */
- if (ret) {
- if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
- SILC_STR_DATA(silc_buffer_data(pws->encbuf),
- silc_buffer_len(pws->encbuf)),
- SILC_STR_DATA(data, data_len),
- SILC_STR_END))
- return -2;
- } else {
- if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
- return -2;
+ if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
+ SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
+ src_id_type, dst_id_type));
+ return SILC_PACKET_NONE;
}
- return data_len;
-}
-
-/* Close stream */
-
-SilcBool silc_packet_wrap_close(SilcStream stream)
-{
- SilcPacketWrapperStream pws = stream;
-
- if (pws->closed)
- return TRUE;
+ ctx->src_id_len = src_id_len;
+ ctx->dst_id_len = dst_id_len;
+ ctx->src_id_type = src_id_type;
+ ctx->dst_id_type = dst_id_type;
+ ctx->padlen = padlen;
- if (pws->blocking) {
- /* Close packet waiter */
- silc_packet_wait_uninit(pws->waiter, pws->stream);
- } else {
- /* Unlink */
- if (pws->callback)
- silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
- }
- pws->closed = TRUE;
+ silc_buffer_push(buffer, len);
- return TRUE;
-}
+ SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
+ ctx->buffer->data, ctx->buffer->len);
-/* Destroy wrapper stream */
+ /* Pull SILC header and padding from packet */
+ silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
+ ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
-void silc_packet_wrap_destroy(SilcStream stream)
+ SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
-{
- SilcPacketWrapperStream pws = stream;
- SilcPacket packet;
-
- SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
-
- silc_stream_close(stream);
- silc_list_start(pws->in_queue);
- while ((packet = silc_list_get(pws->in_queue)))
- silc_packet_free(packet);
- if (pws->lock)
- silc_mutex_free(pws->lock);
- if (pws->encbuf)
- silc_buffer_free(pws->encbuf);
- silc_packet_stream_unref(pws->stream);
-
- silc_free(pws);
+ return ctx->type;
}
-/* Link stream to receive packets */
+/* Allocate packet context */
-SilcBool silc_packet_wrap_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
+SilcPacketContext *silc_packet_context_alloc(void)
{
- SilcPacketWrapperStream pws = stream;
-
- if (pws->closed || pws->blocking)
- return FALSE;
-
- /* Link to receive packets */
- if (callback)
- silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
- 100000, pws->type, -1);
- else
- silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
-
- pws->callback = callback;
- pws->context = context;
-
- return TRUE;
+ SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+ ctx->users++;
+ return ctx;
}
-/* Return schedule */
+/* Increse the reference count of the packet context. */
-SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
{
- return NULL;
+ ctx->users++;
+ SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
+ ctx->users));
+ return ctx;
}
-/* Wraps packet stream into SilcStream. */
+/* Decrese the reference count of the packet context and free it only if
+ it is zero. */
-SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
- SilcPacketType type,
- SilcPacketFlags flags,
- SilcBool blocking_mode,
- SilcPacketWrapCoder coder,
- void *context)
+void silc_packet_context_free(SilcPacketContext *ctx)
{
- SilcPacketWrapperStream pws;
-
- pws = silc_calloc(1, sizeof(*pws));
- if (!pws)
- return NULL;
-
- SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
-
- pws->ops = &silc_packet_stream_ops;
- pws->stream = stream;
- pws->type = type;
- pws->flags = flags;
- pws->blocking = blocking_mode;
- pws->coder = coder;
- pws->coder_context = context;
-
- /* Allocate small amount for encoder buffer. */
- if (pws->coder)
- pws->encbuf = silc_buffer_alloc(8);
-
- if (pws->blocking) {
- /* Blocking mode. Use packet waiter to do the thing. */
- pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
- if (!pws->waiter) {
- silc_free(pws);
- return NULL;
+ ctx->users--;
+ SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
+ ctx->users));
+ if (ctx->users < 1)
+ {
+ if (ctx->buffer)
+ silc_buffer_free(ctx->buffer);
+ if (ctx->src_id)
+ silc_free(ctx->src_id);
+ if (ctx->dst_id)
+ silc_free(ctx->dst_id);
+ silc_free(ctx);
}
- } else {
- /* Non-blocking mode */
- silc_mutex_alloc(&pws->lock);
- silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
- }
-
- silc_packet_stream_ref(stream);
-
- return (SilcStream)pws;
}
-
-const SilcStreamOps silc_packet_stream_ops =
-{
- silc_packet_wrap_read,
- silc_packet_wrap_write,
- silc_packet_wrap_close,
- silc_packet_wrap_destroy,
- silc_packet_wrap_notifier,
- silc_packet_wrap_get_schedule,
-};
/*
- silcpacket.h
+ silcpacket.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2001 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
*/
-/****h* silccore/SILC Packet Engine Interface
+/****h* silccore/Packet Protocol Interface
*
* DESCRIPTION
*
- * 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.
+ * 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.
*
***/
#ifndef SILCPACKET_H
#define SILCPACKET_H
-/* XXX many of these could go to silcpacket_i.h */
+/* Default byte size of the packet. */
+#define SILC_PACKET_DEFAULT_SIZE SILC_SOCKET_BUF_SIZE
+
+/* Header length without source and destination ID's. */
+#define SILC_PACKET_HEADER_LEN 10
+
+/* Minimum length of SILC Packet Header. This much is decrypted always
+ when packet is received to be able to get all the relevant data out
+ from the header. */
+#define SILC_PACKET_MIN_HEADER_LEN 16
+
+/* Maximum padding length */
+#define SILC_PACKET_MAX_PADLEN 128
+
+/* Default padding length */
+#define SILC_PACKET_DEFAULT_PADLEN 16
+
+/* Minimum packet length */
+#define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
/* Maximum packet length */
#define SILC_PACKET_MAX_LEN 0xffff
/****d* silccore/SilcPacketAPI/SilcPacketType
*
* NAME
- *
+ *
* typedef SilcUInt8 SilcPacketType;
*
* DESCRIPTION
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 */
#define SILC_PACKET_RESUME_ROUTER 26 /* Backup router resume */
#define SILC_PACKET_FTP 27 /* File Transfer */
#define SILC_PACKET_RESUME_CLIENT 28 /* Client resume */
-#define SILC_PACKET_ACK 29 /* Acknowledgement */
#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
+/****d* silccore/SilcPacketAPI/SilcPacketVersion
*
* NAME
+ *
+ * typedef SilcUInt8 SilcPacketVersion;
*
+ * DESCRIPTION
+ *
+ * SILC packet version type definition.
+ *
+ ***/
+typedef SilcUInt8 SilcPacketVersion;
+
+/****d* silccore/SilcPacketAPI/SilcPacketFlags
+ *
+ * NAME
+ *
* typedef SilcUInt8 SilcPacketFlags;
*
* DESCRIPTION
#define SILC_PACKET_FLAG_LIST 0x02 /* Packet is a list */
#define SILC_PACKET_FLAG_BROADCAST 0x04 /* Packet is a broadcast */
#define SILC_PACKET_FLAG_COMPRESSED 0x08 /* Payload is compressed */
-#define SILC_PACKET_FLAG_ACK 0x10 /* Acknowledge packet */
-
-/* Impelemntation specific flags */
-#define SILC_PACKET_FLAG_LONG_PAD 0x12 /* Use maximum padding */
/***/
-/****s* silccore/SilcPacketAPI/SilcPacketEngine
- *
- * NAME
- *
- * typedef struct SilcPacketEngineStruct *SilcPacketEngine;
- *
- * DESCRIPTION
- *
- * The packet engine context, allocated by silc_packet_engine_start.
- * The engine is destroyed with silc_packet_engine_stop.
- *
- ***/
-typedef struct SilcPacketEngineStruct *SilcPacketEngine;
-
-/****s* silccore/SilcPacketAPI/SilcPacketStream
- *
- * NAME
- *
- * typedef struct SilcPacketStreamStruct *SilcPacketStream;
- *
- * DESCRIPTION
- *
- * The packet stream context, allocated by silc_packet_stream_create.
- * The stream is destroyed with silc_packet_stream_destroy.
- *
- ***/
-typedef struct SilcPacketStreamStruct *SilcPacketStream;
-
-/****s* silccore/SilcPacketAPI/SilcPacket
- *
- * NAME
- *
- * typedef struct SilcPacketStruct *SilcPacket;
- *
- * DESCRIPTION
- *
- * The SilcPacket is returned by the packet engine in the SilcPacketReceive
- * 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 if it takes it in for processing.
- *
- * The `buffer' field contains the parsed packet payload and the start
- * of the data area will point to the start of the packet payload.
- *
- * 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; /* 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;
-/***/
+/* Rest of flags still available
+#define SILC_PACKET_FLAG_XXX 0x10
+#define SILC_PACKET_FLAG_XXX 0x20
+#define SILC_PACKET_FLAG_XXX 0x40
+#define SILC_PACKET_FLAG_XXX 0x80
+*/
-/****d* silcutil/SilcPacketAPI/SilcPacketError
+/****s* silccore/SilcPacketAPI/SilcPacketContext
*
* NAME
- *
- * typedef enum { ... } SilcPacketError
+ *
+ * typedef struct { ... } SilcPacketContext;
*
* DESCRIPTION
*
- * 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. It can retrieve the underlaying stream from
- * the packet stream by calling silc_packet_stream_get_stream function.
- *
- * SOURCE
- */
-typedef enum {
- SILC_PACKET_ERR_READ, /* Error while reading */
- SILC_PACKET_ERR_WRITE, /* Error while writing */
- SILC_PACKET_ERR_MAC_FAILED, /* Packet MAC check failed */
- SILC_PACKET_ERR_DECRYPTION_FAILED, /* Packet decryption failed */
- SILC_PACKET_ERR_UNKNOWN_SID, /* Unknown SID (with IV included) */
- SILC_PACKET_ERR_MALFORMED, /* Packet is malformed */
- SILC_PACKET_ERR_NO_MEMORY, /* System out of memory */
-} SilcPacketError;
-/***/
-
-/****f* silccore/SilcPacketAPI/SilcPacketReceiveCb
+ * In packet sending this is filled and sent to silc_packet_assemble
+ * which then uses it to assemble new packet. In packet reception pointer
+ * to this context is sent to silc_packet_parse which parses the packet
+ * and returns the relevant information to this structure. On packet
+ * reception returned ID's are always the hash values of the ID's from
+ * the packet.
*
- * SYNOPSIS
+ * Short description of the fields following:
*
- * typedef SilcBool (*SilcPacketReceiveCb)(SilcPacketEngine engine,
- * SilcPacketStream stream,
- * SilcPacket packet,
- * void *callback_context,
- * void *stream_context);
+ * SilcUInt16 truelen
*
- * DESCRIPTION
+ * True length of the packet. This may be set by the caller before
+ * calling any of the silc_packet_* routines. If not provided the
+ * library will calculate the values.
*
- * 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 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.
+ * SilcPacketFlags flags
*
- * 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.
+ * Packet flags. Flags are defined above.
*
- * EXAMPLE
+ * SilcPacketType type
*
- * SilcBool
- * silc_foo_packet_receive_cb(SilcPacketEngine engine,
- * SilcPacketStream stream, SilcPacket packet,
- * void *callback_context, void *stream_context)
- * {
- * Application ctx = callback_context;
+ * Type of the packet. Types are defined below.
*
- * // If we're not up yet, let's not process the packet
- * if (ctx->initialized == FALSE)
- * return FALSE;
+ * unsigned char *src_id
+ * SilcUInt8 src_id_len
+ * SilcUInt8 src_id_type
*
- * // Process the incoming packet...
- * ...
+ * Source ID, its length and type. On packet reception retuned ID's
+ * are always the hash values of the ID's from the packet.
*
- * // It's our packet now, no one else will get it
- * return TRUE;
- * }
+ * unsigned char *dst_id;
+ * SilcUInt8 dst_id_len;
+ * SilcUInt8 src_id_type;
*
- ***/
-typedef SilcBool (*SilcPacketReceiveCb)(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *stream_context);
-
-/****f* silccore/SilcPacketAPI/SilcPacketEosCb
+ * Destination ID, its length and type. On packet reception retuned
+ * ID's are always the hash values of the ID's from the packet.
*
- * SYNOPSIS
+ * bool long_pad
+ *
+ * If set to TRUE the packet will include the maximum padding allowed
+ * in SILC packet, which is 128 bytes. If FALSE only the amount of
+ * padding needed will be applied.
*
- * typedef void (*SilcPacketEosCb)(SilcPacketEngine engine,
- * SilcPacketStream stream,
- * void *callback_context,
- * void *stream_context);
+ * SilcUInt16 users;
*
- * DESCRIPTION
+ * Reference counter for this context. The context is freed only
+ * after the reference counter hits zero. The counter is added
+ * calling silc_packet_context_dup and decreased by calling the
+ * silc_packet_context_free.
*
- * The End Of Stream (EOS) callback, that is called by the packet engine
- * when the underlaying stream has ended. No more data can be sent to
- * the stream or read from it. The `stream' must be destroyed by
- * calling the silc_packet_stream_destroy. This callback is set in the
- * SilcPacketCallbacks structure.
+ * SilcUInt8 padlen
*
- ***/
-typedef void (*SilcPacketEosCb)(SilcPacketEngine engine,
- SilcPacketStream stream,
- void *callback_context,
- void *stream_context);
-
-/****f* silccore/SilcPacketAPI/SilcPacketErrorCb
+ * The padded length of the packet. This may be set by the caller
+ * before calling any of the silc_packet_* routines. If not provided
+ * the library will calculate the values.
*
- * SYNOPSIS
+ * SilcUInt32 sequence;
*
- * typedef void (*SilcPacketErrorCb)(SilcPacketEngine engine,
- * SilcPacketStream stream,
- * SilcPacketError error,
- * void *callback_context,
- * void *stream_context);
+ * Packet sequence number. Set only when this context is a parsed
+ * packet.
*
- * DESCRIPTION
+ * SilcBuffer buffer
*
- * The error callback that is called by the packet engine if an error
- * occurs. The `error' will indicate the error. This callback is set
- * in the SilcPacketCallbacks structure.
+ * The actual packet data. Set only when this context is a parsed
+ * packet.
*
***/
-typedef void (*SilcPacketErrorCb)(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacketError error,
- void *callback_context,
- void *stream_context);
-
-/****s* silccore/SilcPacketAPI/SilcPacketCallbacks
- *
- * NAME
- *
- * typedef struct { ... } *SilcPacketCallbacks;
- *
- * DESCRIPTION
- *
- * This structure is sent as argument to the silc_packet_engine_start
- * function to set the callback functions for the packet engine. The
- * packet engine will call the callbacks when necessary. Application
- * must always be provided for the packet engine.
- *
- * SOURCE
- */
typedef struct {
- SilcPacketReceiveCb packet_receive; /* Called when packet is received */
- SilcPacketEosCb eos; /* Called on end of stream */
- SilcPacketErrorCb error; /* Called on an error */
-} SilcPacketCallbacks;
-/***/
-
-/* Prototypes */
-
-/****f* silccore/SilcPacketAPI/silc_packet_engine_start
- *
- * SYNOPSIS
- *
- * SilcPacketEngine
- * 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 `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.
- *
- * NOTES
- *
- * The packet engine is thread safe. You can use one packet engine in
- * multi threaded application.
- *
- ***/
-SilcPacketEngine
-silc_packet_engine_start(SilcRng rng, SilcBool router,
- SilcPacketCallbacks *callbacks,
- void *callback_context);
-
-/****f* silccore/SilcPacketAPI/silc_packet_engine_stop
- *
- * SYNOPSIS
- *
- * void silc_packet_engine_stop(SilcPacketEngine engine);
- *
- * DESCRIPTION
- *
- * Stop the packet engine. No new packets can be sent or received after
- * calling this, and the `engine' will become invalid.
- *
- ***/
-void silc_packet_engine_stop(SilcPacketEngine engine);
-
-/****f* silccore/SilcPacketAPI/silc_packet_stream_create
- *
- * SYNOPSIS
- *
- * SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
- * SilcSchedule schedule,
- * SilcStream stream);
+ SilcUInt16 truelen;
+ SilcPacketFlags flags;
+ SilcPacketType type;
+
+ unsigned char *src_id;
+ unsigned char *dst_id;
+ unsigned int src_id_len : 5;
+ unsigned int src_id_type : 2;
+ unsigned int dst_id_len : 5;
+ unsigned int dst_id_type : 2;
+ unsigned int long_pad : 1; /* Set when maximum padding in packet */
+ unsigned int users : 9; /* Reference counter */
+ unsigned int padlen : 8;
+
+ SilcUInt32 sequence;
+ SilcBuffer buffer;
+} SilcPacketContext;
+
+/****s* silccore/SilcPacketAPI/SilcPacketParserContext
*
- * DESCRIPTION
- *
- * Create new packet stream and use the `stream' as underlaying stream.
- * Usually the `stream' would be a socket stream, but it can be any
- * stream. After this function returns, packets can immediately be
- * sent to and received from the stream.
- *
- * NOTES
- *
- * SilcPacketStream cannot be used with silc_stream_* routines (such as
- * silc_stream_read and silc_stream_write) because of its special nature.
- * Use the silc_packet_send and the silc_packet_send_ext to send packets.
- * To read packets you will receive the packet receive callback from
- * packet engine. Destroy the stream with silc_packet_stream_destroy.
- *
- * 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_add_remote
- *
- * SYNOPSIS
- *
- * SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
- * const char *remote_ip,
- * SilcUInt16 remote_port,
- * SilcPacket packet);
- *
- * DESCRIPTION
- *
- * This function is used to add remote receivers in packet stream `stream'
- * that has UDP/IP socket stream as the underlaying stream. This function
- * cannot be used with other type of streams. This returns new packet
- * stream context that can be used to send to and receive packets from
- * the specified remote IP and remote port, or NULL on error. The `stream'
- * is the actual stream that is used to send and receive the data.
- *
- * When the parent `stream' receives packets from remote IP address
- * and port that does not have its own remote packet stream, it returns
- * the packet to the packet callback set for `stream'. The sender's
- * IP address and port can then be retrieved by using the
- * silc_packet_get_sender function and to create new packet stream by
- * calling this function. After that, all packets from that IP address
- * and port will be received by the new packet stream.
- *
- * If the `packet' is non-NULL it will be injected into the new packet
- * stream as soon as the scheduler associated with `stream' schedules
- * new tasks. It can be used to inject an incoming packet to the stream.
- *
- * This interface is for connectionless UDP streams. If it is possible
- * to create connected stream it should be done for performance reasons.
- *
- * EXAMPLE
- *
- * // Create parent packet stream, it can receive packets from anywhere
- * listener = silc_net_udp_connect("0.0.0.0", 500, NULL, 0, schedule);
- * parent = silc_packet_stream_create(engine, schedule, listener);
- *
- * ...
- * // Received a packet to the parent stream, get the sender information.
- * silc_packet_get_sender(packet, &ip, &port);
- *
- * // Create new packet stream for this remote location.
- * remote = silc_packet_stream_add_remote(parent, ip, port, packet);
- *
- ***/
-SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
- const char *remote_ip,
- SilcUInt16 remote_port,
- SilcPacket packet);
-
-/****f* silccore/SilcPacketAPI/silc_packet_stream_destroy
- *
- * SYNOPSIS
- *
- * void silc_packet_stream_destroy(SilcPacketStream stream);
- *
- * DESCRIPTION
- *
- * Destroy packet stream and the underlaying stream. This will also
- * close and destroy the underlaying stream.
- *
- ***/
-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_stream_set_iv_included
- *
- * SYNOPSIS
- *
- * void silc_packet_stream_set_iv_included(SilcPacketStream stream);
- *
- * DESCRIPTION
- *
- * Sets an IV Included property for the stream indicated by `stream'.
- * This means that the IV used in the encryption will be included in
- * the resulted ciphertext. This makes it possible to send and receive
- * packets on unreliable network transport protocol, such as UDP/IP.
- * This must be called if the underlaying stream in the `stream' is UDP
- * stream.
- *
- * When this is set to the stream the silc_packet_set_sid must be called
- * to set new Security ID. The Security ID will be included with the IV
- * in the ciphertext.
- *
- ***/
-void silc_packet_stream_set_iv_included(SilcPacketStream stream);
-
-/****f* silccore/SilcPacketAPI/silc_packet_stream_set_stream
- *
- * SYNOPSIS
- *
- * void silc_packet_stream_set_stream(SilcPacketStream packet_stream,
- * SilcStream stream);
- *
- * DESCRIPTION
- *
- * This function may be used to change the underlaying stream in the
- * packet stream indicated by `packet_stream'. Note that the old
- * stream will not be used after calling this function. The caller is
- * responsible destroying the old stream. The `stream' will use
- * the same scheduler as the `packet_stream'.
- *
- ***/
-void silc_packet_stream_set_stream(SilcPacketStream packet_stream,
- SilcStream stream);
-
-/****f* silccore/SilcPacketAPI/silc_packet_stream_get_stream
- *
- * SYNOPSIS
- *
- * SilcStream silc_packet_stream_get_stream(SilcPacketStream stream);
- *
- * DESCRIPTION
- *
- * 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 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_link
- *
- * SYNOPSIS
- *
- * SilcBool silc_packet_stream_link(SilcPacketStream stream,
- * SilcPacketCallbacks *callbacks,
- * void *callback_context,
- * int priority, ...);
+ * NAME
+ *
+ * typedef struct { ... } SilcPacketParserContext;
*
* DESCRIPTION
*
- * 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);
+ * This context is used in packet reception when the function
+ * silc_packet_receive_process calls parser callback that performs
+ * the actual packet decryption and parsing. This context is sent as
+ * argument to the parser function. This context must be free'd by
+ * the parser callback function.
*
- ***/
-SilcBool silc_packet_stream_link(SilcPacketStream stream,
- SilcPacketCallbacks *callbacks,
- void *callback_context,
- int priority, ...);
-
-/****f* silccore/SilcPacketAPI/silc_packet_stream_unlink
+ * Following description of the fields:
*
- * SYNOPSIS
- *
- * void silc_packet_stream_unlink(SilcPacketStream stream,
- * SilcPacketCallbacks *callbacks,
- * void *callback_context);
- *
- * DESCRIPTION
+ * SilcPacketContext *packet
*
- * 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.
+ * The actual packet received from the network. In this phase the
+ * context is not parsed, only the packet->buffer is allocated and
+ * it includes the raw packet data, which is encrypted.
*
- ***/
-void silc_packet_stream_unlink(SilcPacketStream stream,
- SilcPacketCallbacks *callbacks,
- void *callback_context);
-
-/****f* silccore/SilcPacketAPI/SilcPacketWrapCoder
+ * bool normal
*
- * SYNOPSIS
+ * Indicates whether the received packet is normal or special packet.
+ * If special the parsing process is special also.
*
- * typedef SilcBool (*SilcPacketWrapCoder)(SilcStream stream,
- * SilcStreamStatus status,
- * SilcBuffer buffer,
- * void *context);
+ * SilcSocketConnection sock
*
- * DESCRIPTION
+ * The associated connection.
*
- * The encoder/decoder callback for silc_packet_stream_wrap. If the
- * `status' is SILC_STREAM_CAN_WRITE then additional data can be added
- * to `buffer'. It is added before the data that is written with
- * silc_stream_write. The silc_buffer_enlarge should be called to verify
- * there is enough room in `buffer' before adding data to it. The `buffer'
- * must not be freed.
+ * void *context
*
- * If the `status' is SILC_STREAM_CAN_READ then data from the `buffer'
- * may be read before it is passed to readed when silc_stream_read is
- * called. The `buffer' may be advanced also to hide data in it.
- *
- * This function returns FALSE in case of error.
+ * User context that is sent to the silc_packet_receive_process
+ * function. This usually includes application and connection specific
+ * data.
*
***/
-typedef SilcBool (*SilcPacketWrapCoder)(SilcStream stream,
- SilcStreamStatus status,
- SilcBuffer buffer,
- void *context);
+typedef struct {
+ SilcPacketContext *packet;
+ bool normal;
+ SilcSocketConnection sock;
+ void *context;
+} SilcPacketParserContext;
-/****f* silccore/SilcPacketAPI/silc_packet_stream_wrap
+/****f* silccore/SilcPacketAPI/SilcPacketParserCallback
*
* SYNOPSIS
*
- * SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
- * SilcPacketType type,
- * SilcPacketFlags flags,
- * SilcBool blocking_mode,
- * SilcPacketWrapCoder coder,
- * void *context);
+ * typedef bool (*SilcPacketParserCallback)(SilcPacketParserContext
+ * *parse_context);
*
* DESCRIPTION
*
- * Wraps the packet stream indicated by `stream' into a SilcStream for
- * the packet type indicated by `type' with packet flags indicated by
- * `flags'. The returned SilcStream can be used to read and write the
- * specified SILC packets with the specified packet flags, by calling
- * silc_stream_read and silc_stream_write, respectively. The returned
- * stream can be destroyed by calling silc_stream_destroy. It does not
- * destroy the wrapped packet stream.
- *
- * If the `blocking_mode' mode is TRUE then the silc_stream_read and
- * silc_stream_write may block the calling process or thread until SILC
- * packet is read or written. If it is FALSE the stream is in non-blocking
- * mode and the calls never block. The returned stream is thread-safe and
- * packets may be read and written in multi-threaded environment.
- *
- * In non-blocking mode the silc_stream_set_notifier must be called before
- * the returned stream can be used to read packets. The stream status
- * SILC_STREAM_CAN_READ will be returned to the notifier callback to
- * indicate that a packet is ready for reading. Calling silc_stream_read
- * once returns one complete SILC packet data payload (which is of type of
- * `type').
- *
- * The `coder' is optional encoder/decoder callback which the packet engine
- * will call if it is non-NULL. It can be used to encode additional data
- * into each packet when silc_stream_write is called or decode data before
- * it is passed to reader when silc_stream_read is called. The `context'
- * is passed to `coder'.
- *
- * The returned SilcStream can be used as any normal stream and all
- * SilcStream API functions may be used with the stream. This returns
- * NULL on error.
- *
- ***/
-SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
- SilcPacketType type,
- SilcPacketFlags flags,
- SilcBool blocking_mode,
- SilcPacketWrapCoder coder,
- void *context);
-
-/****f* silccore/SilcPacketAPI/silc_packet_stream_is_udp
- *
- * SYNOPSIS
- *
- * SilcBool silc_packet_stream_is_udp(SilcPacketStream stream);
+ * This callback is given to the silc_packet_receive_process function.
+ * The callback is called by the library every time a packet is
+ * received from the network. After the packet has been decrypted
+ * and at least partially parsed it is passed to the application
+ * for further parsing using this callback and the SilcPacketParserContext
+ * context. The application receiving the SilcPacketParserContext
+ * must free it.
*
- * DESCRIPTION
- *
- * Returns TRUE if the packet stream indicated by `stream' is using
- * UDP transport.
+ * This returns TRUE if the library should continue packet processing
+ * (assuming there is more data to be processed), and FALSE if the
+ * upper layer does not want the library to continue but to leave the
+ * rest of the data is the packet queue untouched. Application may
+ * want to do this for example if the cipher is not ready before
+ * processing a certain packet. In this case the application wants
+ * to recall the processing function with the correct cipher.
*
***/
-SilcBool silc_packet_stream_is_udp(SilcPacketStream stream);
+typedef bool (*SilcPacketParserCallback)(SilcPacketParserContext
+ *parse_context, void *context);
-/****f* silccore/SilcPacketAPI/silc_packet_get_sender
- *
- * SYNOPSIS
- *
- * SilcBool silc_packet_get_sender(SilcPacket packet,
- * const char **sender_ip,
- * SilcUInt16 *sender_port);
- *
- * DESCRIPTION
- *
- * Returns the packet sender's IP address and port from UDP packet
- * indicated by `packet'. This can be called only from the packet
- * callback to retrieve the information of the packet's sender. Returns
- * FALSE if the information is not available.
- *
- ***/
-SilcBool silc_packet_get_sender(SilcPacket packet,
- const char **sender_ip,
- SilcUInt16 *sender_port);
+/* Macros */
-/****f* silccore/SilcPacketAPI/silc_packet_stream_ref
+/****d* silccore/SilcPacketAPI/SILC_PACKET_LENGTH
*
- * SYNOPSIS
- *
- * void silc_packet_stream_ref(SilcPacketStream stream);
+ * NAME
+ *
+ * #define SILC_PACKET_LENGTH ...
*
* DESCRIPTION
*
- * Increase reference counter for the stream indicated by `stream'. This
- * can be used to take a reference for the stream. To unreference the
- * stream call silc_packet_stream_unref function.
+ * Returns true length of the packet. This is primarily used by the
+ * libary in packet parsing phase but the application may use it as
+ * well if needed.
*
- ***/
-void silc_packet_stream_ref(SilcPacketStream stream);
+ * SOURCE
+ */
+#define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
+do { \
+ SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
+ (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
+} while(0)
+/***/
-/****f* silccore/SilcPacketAPI/silc_packet_stream_unref
+/****d* silccore/SilcPacketAPI/SILC_PACKET_DATALEN
*
- * SYNOPSIS
- *
- * void silc_packet_stream_unref(SilcPacketStream stream);
+ * NAME
+ *
+ * #define SILC_PACKET_DATALEN ...
*
* DESCRIPTION
*
- * Decrease reference counter for the stream indicated by `stream'. If
- * the counter hits zero the stream will be destroyed automatically.
+ * Calculates the data length with given header length. This macro
+ * can be used to check whether the data_len with header_len exceeds
+ * SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
+ * so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
+ * plus header_len fits SILC_PACKET_MAX_LEN the returned data length
+ * is the data_len given as argument. This macro can be used when
+ * assembling packet.
*
- ***/
-void silc_packet_stream_unref(SilcPacketStream stream);
+ * SOURCE
+ */
+#define SILC_PACKET_DATALEN(data_len, header_len) \
+ ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
+ data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
+/***/
-/****f* silccore/SilcPacketAPI/silc_packet_get_engine
- *
- * SYNOPSIS
+/****d* silccore/SilcPacketAPI/SILC_PACKET_PADLEN
*
- * SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream);
+ * NAME
+ *
+ * #define SILC_PACKET_PADLEN ...
*
* DESCRIPTION
*
- * Returns the packet engine from the `stream'.
+ * Calculates the length of the padding in the packet. This is used
+ * by various library routines to determine needed padding length.
*
- ***/
-SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream);
+ * SOURCE
+ */
+#define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
+do { \
+ __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
+ ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
+ if (__padlen < 8) \
+ __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
+} while(0)
+/***/
-/****f* silccore/SilcPacketAPI/silc_packet_set_context
- *
- * SYNOPSIS
+/****d* silccore/SilcPacketAPI/SILC_PACKET_PADLEN_MAX
*
- * void silc_packet_set_context(SilcPacketStream stream,
- * void *stream_context);
+ * NAME
+ *
+ * #define SILC_PACKET_PADLEN_MAX ...
*
* DESCRIPTION
*
- * 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, and this context as the `stream_context' argument.
+ * Returns the length of the padding up to the maximum length, which
+ * is 128 bytes. This is used by various library routines to determine
+ * needed padding length.
*
- ***/
-void silc_packet_set_context(SilcPacketStream stream, void *stream_context);
+ * SOURCE
+ */
+#define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
+do { \
+ __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
+ ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
+} while(0)
+/***/
-/****f* silccore/SilcPacketAPI/silc_packet_get_context
- *
- * SYNOPSIS
- *
- * void *silc_packet_get_context(SilcPacketStream stream);
- *
- * DESCRIPTION
- *
- * Returns the current set application context, or NULL if none is set.
- *
- ***/
-void *silc_packet_get_context(SilcPacketStream stream);
+/* Prototypes */
-/****f* silccore/SilcPacketAPI/silc_packet_set_keys
+/****f* silccore/SilcPacketAPI/silc_packet_send
*
* SYNOPSIS
*
- * void silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
- * SilcCipher receive_key, SilcHmac send_hmac,
- * SilcHmac receive_hmac, SilcBool rekey);
+ * int silc_packet_send(SilcSocketConnection sock, bool force_send);
*
* DESCRIPTION
*
- * Set ciphers and HMACs to be used to encrypt sent packets, and decrypt
- * received packets. This can be called multiple times to change the
- * ciphers and HMACs.
- *
- * If the `rekey' is TRUE this function will send SILC_PACKET_REKEY_DONE
- * to the `stream' and will set the new keys. If it is FALSE the keys
- * are changed but the packet is not changed.
- *
- * When changing keys the old cipher and HMACs will be freed. If the keys
- * are not set at all, packets will not be encrypted or decrypted.
+ * Actually sends the packet. This flushes the connections outgoing data
+ * buffer. If data is sent directly to the network this returns the bytes
+ * written, if error occured this returns -1 and if the data could not
+ * be written directly to the network at this time this returns -2, in
+ * which case the data should be queued by the caller and sent at some
+ * later time. If `force_send' is TRUE this attempts to write the data
+ * directly to the network, if FALSE, this returns -2.
*
***/
-SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
- SilcCipher receive_key, SilcHmac send_hmac,
- SilcHmac receive_hmac, SilcBool rekey);
+int silc_packet_send(SilcSocketConnection sock, bool force_send);
-/****f* silccore/SilcPacketAPI/silc_packet_get_keys
+/****f* silccore/SilcPacketAPI/silc_packet_encrypt
*
* SYNOPSIS
*
- * SilcBool silc_packet_get_keys(SilcPacketStream stream,
- * SilcCipher *send_key,
- * SilcCipher *receive_key,
- * SilcHmac *send_hmac,
- * SilcHmac *receive_hmac);
+ * void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
+ * SilcBuffer buffer, SilcUInt32 len);
*
* DESCRIPTION
*
- * Returns the pointers of current ciphers and HMACs from the `stream'.
- * Returns FALSE if keys are not set.
+ * Encrypts a packet. This also creates HMAC of the packet before
+ * encryption and adds the HMAC at the end of the buffer. This assumes
+ * that there is enough free space at the end of the buffer to add the
+ * computed HMAC. This is the normal way of encrypting packets, if some
+ * other process of HMAC computing and encryption is needed this function
+ * cannot be used.
*
***/
-SilcBool silc_packet_get_keys(SilcPacketStream stream,
- SilcCipher *send_key, SilcCipher *receive_key,
- SilcHmac *send_hmac, SilcHmac *receive_hmac);
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
+ SilcBuffer buffer, SilcUInt32 len);
-/****f* silccore/SilcPacketAPI/silc_packet_set_ids
+/****f* silccore/SilcPacketAPI/silc_packet_assemble
*
* SYNOPSIS
*
- * SilcBool silc_packet_set_ids(SilcPacketStream stream,
- * SilcIdType src_id_type, const void *src_id
- * SilcIdType dst_id_type, const void *dst_id);
+ * bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
+ * SilcCipher cipher, SilcHmac hmac,
+ * SilcSocketConnection sock,
+ * const unsigned char *data, SilcUInt32 data_len,
+ * const SilcBuffer assembled_packet);
*
* DESCRIPTION
*
- * Set the source ID and destinaion ID to be used when sending packets to
- * this packet stream. The IDs to be used for a packet stream can be
- * overridden when sending packets. However, if the IDs do not ever change
- * for the packet stream it is recommended they are set using this function.
- * In this case they can be omitted when sending packets to the stream.
- * It is also possible to set only source or destination ID.
+ * Assembles new packet to be ready for encrypting and sending out.
+ * The `packet' is filled by caller to include the packet header specific
+ * values. This prepares the socket connection's `sock' outoing buffer
+ * for sending data, and returns the assembled packet to the
+ * `assembled_packet' pointer sent by the caller. The `assembled_packet'
+ * is a reference to the socket connection's outgoing buffer. The
+ * returned packet can be encrypted, and then sent to network by calling
+ * silc_packet_send function. The `assembled_packet' may be freely
+ * modified (like encrypted etc.) but it must not be freed, since it is
+ * reference from `sock' outgoing buffer, and it is const.
*
***/
-SilcBool silc_packet_set_ids(SilcPacketStream stream,
- SilcIdType src_id_type, const void *src_id,
- SilcIdType dst_id_type, const void *dst_id);
+bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
+ SilcCipher cipher, SilcHmac hmac,
+ SilcSocketConnection sock,
+ const unsigned char *data, SilcUInt32 data_len,
+ const SilcBuffer assembled_packet);
-/****f* silccore/SilcPacketAPI/silc_packet_set_sid
+/****f* silccore/SilcPacketAPI/silc_packet_send_prepare
*
* SYNOPSIS
*
- * SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid);
+ * bool silc_packet_send_prepare(SilcSocketConnection sock,
+ * SilcUInt32 header_len,
+ * SilcUInt32 pad_len,
+ * SilcUInt32 data_len,
+ * SilcHmac hmac,
+ * const SilcBuffer packet);
*
* DESCRIPTION
*
- * Sets new Security ID to the packet stream indicated by `stream'. This
- * is called only if the IV Included property was set to the stream
- * by calling silc_packet_stream_set_iv_included. This function sets
- * new Security ID to the stream which is then included in the ciphertext
- * of a packet. The `sid' must be 0 when it is set for the very first
- * time and must be increased by one after each rekey. This function must
- * be called every time new keys are added to the stream after a rekey.
+ * This function can be used to prepare the outgoing data buffer in
+ * the socket connection specified by `sock' for packet sending.
+ * This is used internally by packet sending routines, but application
+ * may call this if it doesn't call silc_packet_assemble function.
+ * If that function is called then application must not call this since
+ * that function calls this internally.
*
- * If this function is called when the IV Included property has not been
- * set to the stream the `sid' will be ignored. Returns FALSE if the
- * IV Included has not been set, TRUE otherwise.
+ * This returns the prepared data area into the `packet' pointer provided
+ * caller, which can be used then to add data to it, and later encrypt
+ * it. The `packet' includes reference to the socket connection's
+ * outgoing buffer. The `packet' may be freely modified (like
+ * encrypted etc.) but it must not be freed, since it is reference from
+ * `sock' outgoing buffer, and it is const.
*
***/
-SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid);
+bool silc_packet_send_prepare(SilcSocketConnection sock,
+ SilcUInt32 header_len,
+ SilcUInt32 pad_len,
+ SilcUInt32 data_len,
+ SilcHmac hmac,
+ const SilcBuffer packet);
-/****f* silccore/SilcPacketAPI/silc_packet_send
+/****f* silccore/SilcPacketAPI/silc_packet_receive
*
* SYNOPSIS
*
- * SilcBool silc_packet_send(SilcPacketStream stream,
- * SilcPacketType type, SilcPacketFlags flags,
- * const unsigned char *data,
- * SilcUInt32 data_len);
+ * int silc_packet_receive(SilcSocketConnection sock);
*
* 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_keys
- * the packet will be encrypted and MAC will be 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.
- * Returns FALSE if packet could not be sent.
+ * Receives packet from network and reads the data into connection's
+ * incoming data buffer. If the data was read directly this returns the
+ * read bytes, if error occured this returns -1, if the data could not
+ * be read directly at this time this returns -2 in which case the data
+ * should be read again at some later time, or If EOF occured this returns
+ * 0.
*
***/
-SilcBool silc_packet_send(SilcPacketStream stream,
- SilcPacketType type, SilcPacketFlags flags,
- const unsigned char *data, SilcUInt32 data_len);
+int silc_packet_receive(SilcSocketConnection sock);
-/****f* silccore/SilcPacketAPI/silc_packet_send_ext
+/****f* silccore/SilcPacketAPI/silc_packet_receive_process
*
* SYNOPSIS
*
- * SilcBool
- * silc_packet_send_ext(SilcPacketStream stream,
- * SilcPacketType type, SilcPacketFlags flags,
- * SilcIdType src_id_type, void *srd_id,
- * SilcIdType dst_id_type, void *dst_id,
- * const unsigned char *data, SilcUInt32 data_len,
- * SilcCipher cipher, SilcHmac hmac);
+ * bool silc_packet_receive_process(SilcSocketConnection sock,
+ * bool local_is_router,
+ * SilcCipher cipher, SilcHmac hmac,
+ * SilcUInt32 sequence,
+ * SilcPacketParserCallback parser,
+ * void *parser_context);
*
* DESCRIPTION
*
- * 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'. If any of the extra
- * pointers are NULL, default values set to the stream will apply.
- *
- ***/
-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_send_va
- *
- * SYNOPSIS
- *
- * SilcBool silc_packet_send_va(SilcPacketStream stream,
- * SilcPacketType type,
- * SilcPacketFlags flags, ...);
- *
- * DESCRIPTION
+ * Processes and decrypts the incoming data, and calls parser callback
+ * for each received packet that will handle the actual packet parsing.
+ * If more than one packet was received this calls the parser multiple
+ * times. The parser callback will get context SilcPacketParserContext
+ * that includes the packet and the `parser_context' sent to this
+ * function.
*
- * Same as silc_packet_send but takes the data in as variable argument
- * formatted buffer (see silcbuffmt.h). The arguments must be ended
- * with SILC_STR_END. Returns FALSE if packet could not be sent or
- * the buffer could not be formatted.
- *
- * EXAMPLE
- *
- * // Send NEW_CLIENT packet
- * silc_packet_send_va(stream, SILC_PACKET_NEW_CLIENT, 0,
- * SILC_STR_UI_SHORT(username_len),
- * SILC_STR_DATA(username, username_len),
- * SILC_STR_UI_SHORT(realname_len),
- * SILC_STR_DATA(realname, realname_len),
- * SILC_STR_END);
+ * The `local_is_router' indicates whether the caller is router server
+ * in which case the receiving process of a certain packet types may
+ * be special. Normal server and client must set it to FALSE. The
+ * SilcPacketParserContext will indicate also whether the received
+ * packet was normal or special packet.
*
***/
-SilcBool silc_packet_send_va(SilcPacketStream stream,
- SilcPacketType type, SilcPacketFlags flags, ...);
+bool silc_packet_receive_process(SilcSocketConnection sock,
+ bool local_is_router,
+ SilcCipher cipher, SilcHmac hmac,
+ SilcUInt32 sequence,
+ SilcPacketParserCallback parser,
+ void *parser_context);
-/****f* silccore/SilcPacketAPI/silc_packet_send_va_ext
+/****f* silccore/SilcPacketAPI/silc_packet_parse
*
* SYNOPSIS
*
- * SilcBool
- * silc_packet_send_va_ext(SilcPacketStream stream,
- * SilcPacketType type, SilcPacketFlags flags,
- * SilcIdType src_id_type, void *srd_id,
- * SilcIdType dst_id_type, void *dst_id,
- * SilcCipher cipher, SilcHmac hmac, ...);
+ * SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
*
* DESCRIPTION
*
- * Same as silc_packet_send_va 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'. If any of the extra
- * pointers are NULL, default values set to the stream will apply.
+ * Parses the packet. This is called when a whole packet is ready to be
+ * parsed. The buffer sent must be already decrypted before calling this
+ * function. The len argument must be the true length of the packet. This
+ * function returns the type of the packet. The data section of the
+ * buffer is parsed, not head or tail sections.
*
***/
-SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
- SilcPacketType type, SilcPacketFlags flags,
- SilcIdType src_id_type, void *src_id,
- SilcIdType dst_id_type, void *dst_id,
- SilcCipher cipher, SilcHmac hmac, ...);
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher);
-/****f* silccore/SilcPacketAPI/silc_packet_wait
+/****f* silccore/SilcPacketAPI/silc_packet_parse_special
*
* SYNOPSIS
*
- * void *silc_packet_wait_init(SilcPacketStream stream, ...);
+ * SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
*
* DESCRIPTION
*
- * Initializes a packet waiter for the packet stream `stream' and
- * for the variable argument list of packet types. The function
- * silc_packet_wait can be used to block the thread until a packet
- * has been received. This function is used to initialize the waiting
- * and to give the list of packet types that caller wish to receive.
- * The variable argument list must end with -1. To receive all
- * packets use SILC_PACKET_ANY. Returns a context that must be given
- * to the silc_packet_wait function as argument. Returns NULL on
- * error. To uninitialize the waiting call silc_packet_wait_uninit.
- *
- * NOTES
- *
- * Note that packets may be available immediately after calling this
- * function and they will be buffered, until silc_packet_wait is called.
- *
- * EXAMPLE
- *
- * void *waiter;
- *
- * // Will wait for private message packets
- * waiter = silc_packet_wait_init(stream,
- * SILC_PACKET_PRIVATE_MESSAGE, -1);
- *
+ * Perform special SILC Packet header parsing. This is required to some
+ * packet types that have the data payload encrypted with different key
+ * than the header area plus padding of the packet. Hence, this parses
+ * the header in a way that it does not take the data area into account
+ * and parses the header and padding area only.
*
***/
-void *silc_packet_wait_init(SilcPacketStream stream, ...);
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
+ SilcCipher cipher);
-/****f* silccore/SilcPacketAPI/silc_packet_wait_uninit
+/****f* silccore/SilcPacketAPI/silc_packet_context_alloc
*
* SYNOPSIS
*
- * void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream);
+ * SilcPacketContext *silc_packet_context_alloc();
*
* DESCRIPTION
*
- * Uninitializes the waiting context. This may be called also from
- * another thread while other thread is waiting for packets. This will
- * inform the waiting thread to stop waiting.
+ * Allocates a packet context. Packet contexts are used when
+ * packets are assembled and parsed. The context is freed by the
+ * silc_packet_context_free function.
*
***/
-void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream);
+SilcPacketContext *silc_packet_context_alloc(void);
-/****f* silccore/SilcPacketAPI/silc_packet_wait
+/****f* silccore/SilcPacketAPI/silc_packet_context_dup
*
* SYNOPSIS
*
- * int silc_packet_wait(void *waiter, int timeout,
- * SilcPacket *return_packet)
+ * SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx);
*
* DESCRIPTION
*
- * A special function that can be used to wait for a packet to arrive.
- * This function will block the calling process or thread until either
- * a packet is received into the `return_packet' pointer or the specified
- * timeout value `timeout', which is in milliseconds, will expire. If
- * the timeout is 0, no timeout exist. Before calling this function the
- * silc_packet_wait_init must be called. The caller is responsible for
- * freeing the returned packet with silc_packet_free.
- *
- * This function can be used for example from a thread that wants to
- * block until SILC packet has been received.
- *
- * Returns 1 when packet was received, 0 if timeout occurred and -1 if
- * error occurred.
- *
- * EXAMPLE
- *
- * static int foo_read_data(FooContext c)
- * {
- * SilcPacket packet;
- * void *waiter;
- * ...
- *
- * // Will wait for private message packets
- * if (c->initialized == FALSE) {
- * waiter = silc_packet_wait_init(stream,
- * SILC_PACKET_PRIVATE_MESSAGE, -1);
- * c->initialized = TRUE;
- * }
- *
- * ...
- * // Wait here until private message packet is received
- * if ((silc_packet_wait(waiter, 0, &packet)) < 0)
- * return -1;
- *
- * ... process packet ...
- *
- * return 1;
- * }
+ * Duplicates the packet context. It actually does not duplicate
+ * any data, instead a reference counter is increased.
*
***/
-int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet);
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx);
-/****f* silccore/SilcPacketAPI/silc_packet_free
+/****f* silccore/SilcPacketAPI/silc_packet_context_free
*
* SYNOPSIS
*
- * void silc_packet_free(SilcPacket packet);
+ * void silc_packet_context_free(SilcPacketContext *ctx);
*
* DESCRIPTION
*
- * This function is used to free the SilcPacket pointer that application
- * receives in the SilcPacketReceive callback. Application must free
- * the packet if it takes it in to processing.
+ * Frees the packet context. The context is actually freed when the
+ * reference counter hits zero.
*
***/
-void silc_packet_free(SilcPacket packet);
+void silc_packet_context_free(SilcPacketContext *ctx);
-#endif /* SILCPACKET_H */
+#endif
+++ /dev/null
-/*
-
- silcpubkey.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"
-
-/* Encodes Public Key Payload for transmitting public keys and certificates. */
-
-SilcBuffer silc_public_key_payload_encode(SilcPublicKey public_key)
-{
- SilcBuffer buffer;
- unsigned char *pk;
- SilcUInt32 pk_len;
- SilcPKCSType type;
-
- if (!public_key)
- return NULL;
-
- type = silc_pkcs_get_type(public_key);
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
- if (!pk)
- return NULL;
-
- buffer = silc_buffer_alloc_size(4 + pk_len);
- if (!buffer) {
- silc_free(pk);
- return NULL;
- }
-
- if (silc_buffer_format(buffer,
- SILC_STR_UI_SHORT(pk_len),
- SILC_STR_UI_SHORT(type),
- SILC_STR_DATA(pk, pk_len),
- SILC_STR_END) < 0) {
- silc_buffer_free(buffer);
- silc_free(pk);
- return NULL;
- }
-
- silc_free(pk);
- return buffer;
-}
-
-/* Decodes public key payload and returns allocated public key */
-
-SilcBool silc_public_key_payload_decode(unsigned char *data,
- SilcUInt32 data_len,
- SilcPublicKey *public_key)
-{
- SilcBufferStruct buf;
- SilcUInt16 pk_len, pk_type;
- unsigned char *pk;
- int ret;
-
- if (!public_key)
- return FALSE;
-
- silc_buffer_set(&buf, data, data_len);
- ret = silc_buffer_unformat(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI_SHORT(&pk_len),
- SILC_STR_UI_SHORT(&pk_type),
- SILC_STR_END);
- if (ret < 0 || pk_len > data_len - 4)
- return FALSE;
-
- if (pk_type < SILC_PKCS_SILC || pk_type > SILC_PKCS_SPKI)
- return FALSE;
-
- ret = silc_buffer_unformat(&buf,
- SILC_STR_DATA(&pk, pk_len),
- SILC_STR_END);
- if (ret < 0)
- return FALSE;
-
- return silc_pkcs_public_key_alloc((SilcPKCSType)pk_type,
- pk, pk_len, public_key);
-}
+++ /dev/null
-/*
-
- silcpubkey.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* silccore/SILC Public Key Payload
- *
- * DESCRIPTION
- *
- * Implementation of the Public Key Payload. Public Key Payload is used to
- * deliver different types of public keys and certificates in the SILC
- * protocol.
- *
- ***/
-
-#ifndef SILCPUBKEY_H
-#define SILCPUBKEY_H
-
-/****f* silccore/SilcPubKeyAPI/silc_public_key_payload_encode
- *
- * SYNOPSIS
- *
- * SilcBool silc_public_key_payload_encode(SilcPublicKey public_key);
- *
- * DESCRIPTION
- *
- * Encodes the Public Key Payload from the public key indicated by
- * `public_key'. Returns the allocated and encoded payload buffer,
- * or NULL on error.
- *
- ***/
-SilcBuffer silc_public_key_payload_encode(SilcPublicKey public_key);
-
-/****f* silccore/SilcPubKeyAPI/silc_public_key_payload_decode
- *
- * SYNOPSIS
- *
- * SilcBool silc_public_key_payload_decode(unsigned char *data,
- * SilcUInt32 data_len,
- * SilcPublicKey *public_key);
- *
- * DESCRIPTION
- *
- * Decodes Public Key Payload from `data' of `data_len' bytes in length
- * data buffer into `public_key' pointer. Returns FALSE if the payload
- * cannot be decoded.
- *
- ***/
-SilcBool silc_public_key_payload_decode(unsigned char *data,
- SilcUInt32 data_len,
- SilcPublicKey *public_key);
-
-#endif /* SILCPUBKEY_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2003 - 2006 Pekka Riikonen
+ Copyright (C) 2003 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcstatus.h"
/* Returns arguments by the status type. */
case SILC_STATUS_ERR_NO_SUCH_CLIENT_ID:
case SILC_STATUS_ERR_BAD_CLIENT_ID:
- {
- SilcID id;
- tmp = silc_argument_get_arg_type(args, 2, &len);
- if (!tmp)
- return 0;
- if (silc_id_payload_parse_id(tmp, len, &id))
- return 0;
- *ret_arg1 = silc_id_dup(&id.u.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:
- {
- SilcID id;
- tmp = silc_argument_get_arg_type(args, 2, &len);
- if (!tmp)
- return 0;
- if (silc_id_payload_parse_id(tmp, len, &id))
- return 0;
- *ret_arg1 = silc_id_dup(&id.u.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:
case SILC_STATUS_ERR_BANNED_FROM_CHANNEL:
case SILC_STATUS_ERR_NO_CHANNEL_PRIV:
case SILC_STATUS_ERR_NO_CHANNEL_FOPRIV:
- {
- SilcID id;
- tmp = silc_argument_get_arg_type(args, 2, &len);
- if (!tmp)
- return 0;
- if (silc_id_payload_parse_id(tmp, len, &id))
- return 0;
- *ret_arg1 = silc_id_dup(&id.u.channel_id, SILC_ID_CHANNEL);
- if (!(*ret_arg1))
- return 0;
- num = 1;
- }
+ 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;
break;
case SILC_STATUS_ERR_USER_NOT_ON_CHANNEL:
case SILC_STATUS_ERR_USER_ON_CHANNEL:
- {
- SilcID id;
- tmp = silc_argument_get_arg_type(args, 2, &len);
- if (!tmp)
- return 0;
- if (silc_id_payload_parse_id(tmp, len, &id))
- return 0;
- *ret_arg1 = silc_id_dup(&id.u.client_id, 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, &id))
- return 0;
- *ret_arg2 = silc_id_dup(&id.u.channel_id, id.type);
- if (!(*ret_arg2))
- return num;
- num = 2;
- }
+ 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;
break;
default:
AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
-bin_PROGRAMS = test_silcargument test_silcmessage
+bin_PROGRAMS = test_silcargument
test_silcargument_SOURCES = test_silcargument.c
-test_silcmessage_SOURCES = test_silcmessage.c
LIBS = $(SILC_COMMON_LIBS)
LDADD = -L.. -L../.. -lsilc
silc_argument_get_arg_type
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "silcargument.h"
#define ARG_NUM 250
unsigned char **argvv, *a;
SilcUInt32 *argvv_lens, l;
SilcUInt32 *argvv_types, t;
- SilcBool success = FALSE;
+ bool success = FALSE;
if (argc > 1 && !strcmp(argv[1], "-d")) {
silc_debug = 1;
+++ /dev/null
-/* SILC Message Payload tests */
-
-#include "silc.h"
-#include "silcapputil.h"
-
-SilcPublicKey public_key, pk2;
-SilcPrivateKey private_key;
-SilcCipher key;
-SilcHash hash;
-SilcHmac hmac;
-SilcRng rng;
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcMessagePayload message;
- SilcBuffer buf;
- const char *msg = "FOOBAR MESSAGE";
- unsigned char *data, tmp[1023], *tmp2;
- SilcUInt32 data_len;
- SilcUInt16 flags;
- int i, n;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*message*");
- }
-
- silc_cipher_register_default();
- silc_hash_register_default();
- silc_hmac_register_default();
- silc_pkcs_register_default();
-
- SILC_LOG_DEBUG(("Load keypair"));
- if (!silc_load_key_pair("pubkey.pub", "privkey.prv", "",
- &public_key, &private_key)) {
- SILC_LOG_DEBUG(("Create keypair"));
- if (!silc_create_key_pair("rsa", 2048, "pubkey.pub", "privkey.prv",
- NULL, "", &public_key, &private_key, FALSE))
- goto err;
- }
-
- SILC_LOG_DEBUG(("Alloc RNG"));
- rng = silc_rng_alloc();
- silc_rng_init(rng);
-
- SILC_LOG_DEBUG(("Alloc AES"));
- if (!silc_cipher_alloc("aes-128-cbc", &key))
- goto err;
-
- SILC_LOG_DEBUG(("Alloc SHA-256"));
- if (!silc_hash_alloc("sha256", &hash))
- goto err;
-
- SILC_LOG_DEBUG(("Alloc HMAC"));
- if (!silc_hmac_alloc("hmac-sha256-96", hash, &hmac))
- goto err;
-
- SILC_LOG_DEBUG(("Set static key: '1234567890123456'"));
- if (!silc_cipher_set_key(key, "1234567890123456", 16 * 8))
- goto err;
- SILC_LOG_DEBUG(("Set HMAC key: '1234567890123456'"));
- silc_hmac_set_key(hmac, "1234567890123456", 16);
-
- /* Simple private message */
- SILC_LOG_DEBUG(("Encoding private message len %d (static key)",
- strlen(msg)));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK,
- msg, strlen(msg), TRUE, TRUE,
- key, hmac, rng, NULL, NULL, NULL, NULL);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), TRUE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != strlen(msg) || memcmp(data, msg, strlen(msg)))
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- silc_message_payload_free(message);
-
- /* Simple private message */
- n = 10;
- SILC_LOG_DEBUG(("Encoding private message len %d (static key)", n));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK,
- msg, n, TRUE, TRUE,
- key, hmac, rng, NULL, NULL, NULL, buf);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), TRUE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != n || memcmp(data, msg, n))
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- silc_message_payload_free(message);
-
- /* Simple private message */
- n = 1;
- SILC_LOG_DEBUG(("Encoding private message len %d (static key)", n));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK,
- msg, n, TRUE, TRUE,
- key, hmac, rng, NULL, NULL, NULL, buf);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), TRUE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != n || memcmp(data, msg, n))
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- silc_message_payload_free(message);
-
- /* Simple private message */
- for (i = 0; i < sizeof(tmp); i++)
- tmp[i] = (32 + i) & 127;
- SILC_LOG_DEBUG(("Encoding private message len %d (static key)",
- sizeof(tmp)));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK,
- tmp, sizeof(tmp), TRUE, TRUE,
- key, hmac, rng, NULL, NULL, NULL, buf);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), TRUE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != sizeof(tmp) || memcmp(data, tmp, sizeof(tmp)))
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- silc_message_payload_free(message);
-
- /* Digitally signed private message */
- for (i = 0; i < sizeof(tmp); i++)
- tmp[i] = (32 + i) & 127;
- SILC_LOG_DEBUG(("Encoding private message len %d (static key) SIGNED",
- sizeof(tmp)));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK |
- SILC_MESSAGE_FLAG_SIGNED,
- tmp, sizeof(tmp), TRUE, TRUE,
- key, hmac, rng,
- public_key, private_key, hash, buf);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), TRUE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != sizeof(tmp) || memcmp(data, tmp, sizeof(tmp)))
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- SILC_LOG_DEBUG(("Verifying signature"));
- if (silc_message_signed_verify(message, public_key, hash) !=
- SILC_AUTH_OK)
- goto err;
- SILC_LOG_DEBUG(("Signature Ok"));
- SILC_LOG_DEBUG(("Get public key"));
- pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
- if (!pk2)
- goto err;
- SILC_LOG_DEBUG(("Verify public key"));
- if (!silc_pkcs_public_key_compare(public_key, pk2))
- goto err;
- SILC_LOG_DEBUG(("Public key Ok"));
- silc_pkcs_public_key_free(pk2);
- silc_message_payload_free(message);
-
- /* Digitally signed channel message */
- for (i = 0; i < sizeof(tmp) / 2; i++)
- tmp[i] = (32 + i) & 127;
- SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED",
- sizeof(tmp) / 2));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK |
- SILC_MESSAGE_FLAG_SIGNED,
- tmp, sizeof(tmp) / 2, TRUE, FALSE,
- key, hmac, rng,
- public_key, private_key, hash, buf);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing channel messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), FALSE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2))
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- SILC_LOG_DEBUG(("Verifying signature"));
- if (silc_message_signed_verify(message, public_key, hash) !=
- SILC_AUTH_OK)
- goto err;
- SILC_LOG_DEBUG(("Signature Ok"));
- SILC_LOG_DEBUG(("Get public key"));
- pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
- if (!pk2)
- goto err;
- SILC_LOG_DEBUG(("Verify public key"));
- if (!silc_pkcs_public_key_compare(public_key, pk2))
- goto err;
- SILC_LOG_DEBUG(("Public key Ok"));
- silc_pkcs_public_key_free(pk2);
- silc_message_payload_free(message);
-
- /* Digitally signed private message (no encryption) */
- for (i = 0; i < sizeof(tmp) / 2; i++)
- tmp[i] = (32 + i) & 127;
- SILC_LOG_DEBUG(("Encoding private message len %d SIGNED",
- sizeof(tmp) / 2));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK |
- SILC_MESSAGE_FLAG_SIGNED,
- tmp, sizeof(tmp) / 2, FALSE, TRUE,
- NULL, NULL, rng,
- public_key, private_key, hash, buf);
- if (!buf)
- goto err;
- SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
- SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), TRUE, FALSE,
- NULL, NULL, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_HEXDUMP(("Data"), data, data_len);
- if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2))
- goto err;
- SILC_LOG_DEBUG(("Verifying signature"));
- if (silc_message_signed_verify(message, public_key, hash) !=
- SILC_AUTH_OK)
- goto err;
- SILC_LOG_DEBUG(("Signature Ok"));
- SILC_LOG_DEBUG(("Get public key"));
- pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
- if (!pk2)
- goto err;
- SILC_LOG_DEBUG(("Verify public key"));
- if (!silc_pkcs_public_key_compare(public_key, pk2))
- goto err;
- SILC_LOG_DEBUG(("Public key Ok"));
- silc_pkcs_public_key_free(pk2);
- silc_message_payload_free(message);
-
- /* Digitally signed channel message (LARGE) */
- n = 65550;
- tmp2 = silc_malloc(n);
- if (!tmp2)
- goto err;
- SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED LARGE",
- n));
- buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
- SILC_MESSAGE_FLAG_UTF8 |
- SILC_MESSAGE_FLAG_ACK |
- SILC_MESSAGE_FLAG_SIGNED,
- tmp2, n, TRUE, FALSE,
- key, hmac, rng,
- public_key, private_key, hash, buf);
- if (!buf)
- goto err;
- SILC_LOG_DEBUG(("Message length: %d", silc_buffer_len(buf)));
- if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN)
- goto err;
- SILC_LOG_DEBUG(("Parsing channel messsage (static key)"));
- message = silc_message_payload_parse(silc_buffer_data(buf),
- silc_buffer_len(buf), FALSE, TRUE,
- key, hmac, NULL, FALSE, NULL);
- if (!message)
- goto err;
- flags = silc_message_get_flags(message);
- SILC_LOG_DEBUG(("Flags: %x", flags));
- if (!(flags & SILC_MESSAGE_FLAG_ACTION))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_UTF8))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_ACK))
- goto err;
- if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
- goto err;
- data = silc_message_get_data(message, &data_len);
- SILC_LOG_DEBUG(("Data len: %d", data_len));
- if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN)
- goto err;
- SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
- silc_hmac_len(hmac));
- SILC_LOG_DEBUG(("Verifying signature"));
- if (silc_message_signed_verify(message, public_key, hash) !=
- SILC_AUTH_OK)
- goto err;
- SILC_LOG_DEBUG(("Signature Ok"));
- SILC_LOG_DEBUG(("Get public key"));
- pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
- if (!pk2)
- goto err;
- SILC_LOG_DEBUG(("Verify public key"));
- if (!silc_pkcs_public_key_compare(public_key, pk2))
- goto err;
- SILC_LOG_DEBUG(("Public key Ok"));
- silc_pkcs_public_key_free(pk2);
- silc_message_payload_free(message);
- silc_free(tmp2);
-
-
- success = TRUE;
- SILC_LOG_DEBUG(("Cleanup"));
- silc_pkcs_public_key_free(public_key);
- silc_pkcs_private_key_free(private_key);
- silc_cipher_free(key);
- silc_hash_free(hash);
- silc_rng_free(rng);
-
- err:
- silc_cipher_unregister_all();
- silc_hash_unregister_all();
- silc_hmac_unregister_all();
- silc_pkcs_unregister_all();
-
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
@LINK=silcrng.html:SILC RNG Interface
@LINK=silccipher.html:SILC Cipher API
@LINK=silcpkcs.html:SILC PKCS API
-@LINK=silcpk.html:SILC Public Key API
-@LINK=silcpkcs1.html:SILC PKCS #1 API
+@LINK=silcpkcs1.html:SILC PKCS#1 API
@LINK=silchash.html:SILC Hash Interface
@LINK=silchmac.html:SILC HMAC Interface
-->
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2000 - 2006 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
noinst_LTLIBRARIES = libsilccrypt.la
-if SILC_AES_ASM
-if SILC_I486
-SILC_AES_S = aes_x86.asm aes.c
-endif
-if SILC_X86_64
-SILC_AES_S = aes_x86_64.asm aes.c
-endif
-else
-SILC_AES_S = aes.c
-endif
-
-libsilccrypt_la_SOURCES = \
- none.c \
- rc5.c \
- md5.c \
- $(SILC_AES_S) \
- rsa.c \
- sha1.c \
- sha256.c \
- twofish.c \
- blowfish.c \
- cast.c \
- silccipher.c \
- silchash.c \
- silchmac.c \
- silcrng.c \
- silcpkcs.c \
- silcpkcs1.c \
- silcpk.c
+libsilccrypt_la_SOURCES = \
+ none.c \
+ rc5.c \
+ md5.c \
+ aes.c \
+ rsa.c \
+ sha1.c \
+ sha256.c \
+ twofish.c \
+ blowfish.c \
+ cast.c \
+ silccipher.c \
+ silchash.c \
+ silchmac.c \
+ silcrng.c \
+ silcpkcs.c \
+ silcpkcs1.c
if SILC_LIBTOOLFIX
# Tell libtool to compile silccrypt as shared since silcsim will need it.
LTFLAGS =
endif
-CFLAGS = $(LTFLAGS) @SILC_CRYPTO_CFLAGS@
+CFLAGS = $(LTFLAGS)
#ifdef SILC_DIST_TOOLKIT
-include_HEADERS = \
- silccipher.h \
- silchash.h \
- silchmac.h \
- silcpkcs.h \
- silcrng.h \
- silcpkcs1.h \
- silcpk.h
+include_HEADERS = \
+ aes.h \
+ blowfish.h \
+ cast.h \
+ ciphers_def.h \
+ ciphers.h \
+ md5.h \
+ none.h \
+ rc5.h \
+ rsa.h \
+ sha1.h \
+ sha256.h \
+ silccipher.h \
+ silcdh.h \
+ silchash.h \
+ silchmac.h \
+ silcpkcs.h \
+ silcrng.h \
+ silcpkcs1.h \
+ twofish.h
SILC_EXTRA_DIST = tests
#endif SILC_DIST_TOOLKIT
-SUFFIXES = .asm
-
-.asm.lo:
- $(LIBTOOL) --tag=CC --mode=compile @SILC_ASSEMBLER@ $<
-
-EXTRA_DIST = *.h *.asm $(SILC_EXTRA_DIST)
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
include $(top_srcdir)/Makefile.defines.in
-/* Modified for SILC -Pekka */
-/* Includes key scheduling in C always, and encryption and decryption in C
- when assembler optimized version cannot be used. */
-/*
- ---------------------------------------------------------------------------
- Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
+/* Modified for SILC. -Pekka */
+/* The AES */
+
+/* This is an independent implementation of the encryption algorithm: */
+/* */
+/* RIJNDAEL by Joan Daemen and Vincent Rijmen */
+/* */
+/* which is a candidate algorithm in the Advanced Encryption Standard */
+/* programme of the US National Institute of Standards and Technology. */
+/* */
+/* Copyright in this implementation is held by Dr B R Gladman but I */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions */
+/* that the originators of the algorithm place on its exploitation. */
+/* */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
+
+/* Timing data for Rijndael (rijndael.c)
+
+Algorithm: rijndael (rijndael.c)
+
+128 bit key:
+Key Setup: 305/1389 cycles (encrypt/decrypt)
+Encrypt: 374 cycles = 68.4 mbits/sec
+Decrypt: 352 cycles = 72.7 mbits/sec
+Mean: 363 cycles = 70.5 mbits/sec
+
+192 bit key:
+Key Setup: 277/1595 cycles (encrypt/decrypt)
+Encrypt: 439 cycles = 58.3 mbits/sec
+Decrypt: 425 cycles = 60.2 mbits/sec
+Mean: 432 cycles = 59.3 mbits/sec
+
+256 bit key:
+Key Setup: 374/1960 cycles (encrypt/decrypt)
+Encrypt: 502 cycles = 51.0 mbits/sec
+Decrypt: 498 cycles = 51.4 mbits/sec
+Mean: 500 cycles = 51.2 mbits/sec
- LICENSE TERMS
-
- The free distribution and use of this software in both source and binary
- form is allowed (with or without changes) provided that:
-
- 1. distributions of this source code include the above copyright
- notice, this list of conditions and the following disclaimer;
-
- 2. distributions in binary form include the above copyright
- notice, this list of conditions and the following disclaimer
- in the documentation and/or other associated materials;
-
- 3. the copyright holder's name is not used to endorse products
- built using this software without specific written permission.
-
- ALTERNATIVELY, provided that this notice is retained in full, this product
- may be distributed under the terms of the GNU General Public License (GPL),
- in which case the provisions of the GPL apply INSTEAD OF those given above.
-
- DISCLAIMER
-
- This software is provided 'as is' with no explicit or implied warranties
- in respect of its properties, including, but not limited to, correctness
- and/or fitness for purpose.
- ---------------------------------------------------------------------------
- Issue 09/09/2006
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "rijndael_internal.h"
#include "aes.h"
-/*
- * SILC Crypto API for AES
+/*
+ * SILC Crypto API for Rijndael
*/
-/* CBC mode */
-
/* Sets the key for the cipher. */
-SILC_CIPHER_API_SET_KEY(aes_cbc)
+SILC_CIPHER_API_SET_KEY(aes)
{
- if (encryption)
- aes_encrypt_key(key, keylen, &((AesContext *)context)->u.enc);
- else
- aes_decrypt_key(key, keylen, &((AesContext *)context)->u.dec);
+ SilcUInt32 k[8];
+
+ SILC_GET_WORD_KEY(key, k, keylen);
+ rijndael_set_key((RijndaelContext *)context, k, keylen);
+
return TRUE;
}
-/* Sets IV for the cipher. */
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
-SILC_CIPHER_API_SET_IV(aes_cbc)
+SILC_CIPHER_API_SET_KEY_WITH_STRING(aes)
{
-
+ return 1;
}
/* Returns the size of the cipher context. */
-SILC_CIPHER_API_CONTEXT_LEN(aes_cbc)
+SILC_CIPHER_API_CONTEXT_LEN(aes)
{
- return sizeof(AesContext);
+ return sizeof(RijndaelContext);
}
/* Encrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_ENCRYPT(aes_cbc)
+SILC_CIPHER_API_ENCRYPT_CBC(aes)
{
- int nb = len >> 4;
-
- SILC_ASSERT((len & (16 - 1)) == 0);
- if (len & (16 - 1))
- return FALSE;
-
- while(nb--) {
- lp32(iv)[0] ^= lp32(src)[0];
- lp32(iv)[1] ^= lp32(src)[1];
- lp32(iv)[2] ^= lp32(src)[2];
- lp32(iv)[3] ^= lp32(src)[3];
- aes_encrypt(iv, iv, &((AesContext *)context)->u.enc);
- memcpy(dst, iv, 16);
- src += 16;
- dst += 16;
- }
+ SilcUInt32 tiv[4];
+ int i;
- return TRUE;
-}
+ SILC_CBC_GET_IV(tiv, iv);
-/* Decrypts with the cipher in CBC mode. Source and destination buffers
- maybe one and same. */
+ SILC_CBC_ENC_PRE(tiv, src);
+ rijndael_encrypt((RijndaelContext *)context, tiv, tiv);
+ SILC_CBC_ENC_POST(tiv, dst, src);
-SILC_CIPHER_API_DECRYPT(aes_cbc)
-{
- unsigned char tmp[16];
- int nb = len >> 4;
-
- if (len & (16 - 1))
- return FALSE;
-
- while(nb--) {
- memcpy(tmp, src, 16);
- aes_decrypt(src, dst, &((AesContext *)context)->u.dec);
- lp32(dst)[0] ^= lp32(iv)[0];
- lp32(dst)[1] ^= lp32(iv)[1];
- lp32(dst)[2] ^= lp32(iv)[2];
- lp32(dst)[3] ^= lp32(iv)[3];
- memcpy(iv, tmp, 16);
- src += 16;
- dst += 16;
+ for (i = 16; i < len; i += 16) {
+ SILC_CBC_ENC_PRE(tiv, src);
+ rijndael_encrypt((RijndaelContext *)context, tiv, tiv);
+ SILC_CBC_ENC_POST(tiv, dst, src);
}
- return TRUE;
-}
-
-/* CTR mode */
+ SILC_CBC_PUT_IV(tiv, iv);
-/* Sets the key for the cipher. */
-
-SILC_CIPHER_API_SET_KEY(aes_ctr)
-{
- AesContext *aes = context;
- memset(&aes->u.enc, 0, sizeof(aes->u.enc));
- aes_encrypt_key(key, keylen, &aes->u.enc);
return TRUE;
}
-/* Sets IV for the cipher. */
-
-SILC_CIPHER_API_SET_IV(aes_ctr)
-{
- AesContext *aes = context;
-
- /* Starts new block. */
- aes->u.enc.inf.b[2] = 0;
-}
-
-/* Returns the size of the cipher context. */
-
-SILC_CIPHER_API_CONTEXT_LEN(aes_ctr)
-{
- return sizeof(AesContext);
-}
-
-/* Encrypts with the cipher in CTR mode. Source and destination buffers
- may be one and same. Assumes MSB first ordered counter. */
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+ maybe one and same. */
-SILC_CIPHER_API_ENCRYPT(aes_ctr)
+SILC_CIPHER_API_DECRYPT_CBC(aes)
{
- AesContext *aes = context;
- SilcUInt32 ctr[4];
+ SilcUInt32 tmp[4], tmp2[4], tiv[4];
int i;
- SILC_GET32_MSB(ctr[0], iv);
- SILC_GET32_MSB(ctr[1], iv + 4);
- SILC_GET32_MSB(ctr[2], iv + 8);
- SILC_GET32_MSB(ctr[3], iv + 12);
-
- i = aes->u.enc.inf.b[2];
- if (!i)
- i = 16;
-
- while (len-- > 0) {
- if (i == 16) {
- if (++ctr[3] == 0)
- if (++ctr[2] == 0)
- if (++ctr[1] == 0)
- ++ctr[0];
-
- SILC_PUT32_MSB(ctr[0], iv);
- SILC_PUT32_MSB(ctr[1], iv + 4);
- SILC_PUT32_MSB(ctr[2], iv + 8);
- SILC_PUT32_MSB(ctr[3], iv + 12);
-
- aes_encrypt(iv, iv, &aes->u.enc);
- i = 0;
- }
- *dst++ = *src++ ^ iv[i++];
- }
- aes->u.enc.inf.b[2] = i;
+ SILC_CBC_GET_IV(tiv, iv);
- SILC_PUT32_MSB(ctr[0], iv);
- SILC_PUT32_MSB(ctr[1], iv + 4);
- SILC_PUT32_MSB(ctr[2], iv + 8);
- SILC_PUT32_MSB(ctr[3], iv + 12);
+ SILC_CBC_DEC_PRE(tmp, src);
+ rijndael_decrypt((RijndaelContext *)context, tmp, tmp2);
+ SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
+ for (i = 16; i < len; i += 16) {
+ SILC_CBC_DEC_PRE(tmp, src);
+ rijndael_decrypt((RijndaelContext *)context, tmp, tmp2);
+ SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
+ }
+
+ SILC_CBC_PUT_IV(tiv, iv);
+
return TRUE;
}
-/* Decrypts with the cipher in CTR mode. Source and destination buffers
- maybe one and same. */
+#define LARGE_TABLES
-SILC_CIPHER_API_DECRYPT(aes_ctr)
-{
- return silc_aes_ctr_encrypt(context, src, dst, len, iv);
-}
+u1byte pow_tab[256];
+u1byte log_tab[256];
+u1byte sbx_tab[256];
+u1byte isb_tab[256];
+u4byte rco_tab[ 10];
+u4byte ft_tab[4][256];
+u4byte it_tab[4][256];
-/****************************************************************************/
+u4byte fl_tab[4][256];
+u4byte il_tab[4][256];
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
+u4byte tab_gen = 0;
-#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
-# define XP_DIR __cdecl
-#else
-# define XP_DIR
-#endif
+#define ff_mult(a,b) (a && b ? pow_tab[(log_tab[a] + log_tab[b]) % 255] : 0)
-#define d_1(t,n,b,e) ALIGN const XP_DIR t n[256] = b(e)
-#define d_4(t,n,b,e,f,g,h) ALIGN const XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
-ALIGN const uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
-
-#ifdef SILC_AES_ASM
-d_1(uint_8t, t_dec(i,box), isb_data, h0);
-#endif /* SILC_AES_ASM */
-d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3);
-d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3);
-d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3);
-d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3);
-d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3);
-
-#define ke4(k,i) \
-{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
- k[4*(i)+5] = ss[1] ^= ss[0]; \
- k[4*(i)+6] = ss[2] ^= ss[1]; \
- k[4*(i)+7] = ss[3] ^= ss[2]; \
-}
+#define f_rn(bo, bi, n, k) \
+ bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
+ ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
+ ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1])
-{ uint_32t ss[4];
-
- cx->ks[0] = ss[0] = word_in(key, 0);
- cx->ks[1] = ss[1] = word_in(key, 1);
- cx->ks[2] = ss[2] = word_in(key, 2);
- cx->ks[3] = ss[3] = word_in(key, 3);
-
- ke4(cx->ks, 0); ke4(cx->ks, 1);
- ke4(cx->ks, 2); ke4(cx->ks, 3);
- ke4(cx->ks, 4); ke4(cx->ks, 5);
- ke4(cx->ks, 6); ke4(cx->ks, 7);
- ke4(cx->ks, 8);
- ke4(cx->ks, 9);
- cx->inf.l = 0;
- cx->inf.b[0] = 10 * 16;
-}
-
-#define kef6(k,i) \
-{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
- k[6*(i)+ 7] = ss[1] ^= ss[0]; \
- k[6*(i)+ 8] = ss[2] ^= ss[1]; \
- k[6*(i)+ 9] = ss[3] ^= ss[2]; \
-}
-
-#define ke6(k,i) \
-{ kef6(k,i); \
- k[6*(i)+10] = ss[4] ^= ss[3]; \
- k[6*(i)+11] = ss[5] ^= ss[4]; \
-}
-
-AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1])
-{ uint_32t ss[6];
-
- cx->ks[0] = ss[0] = word_in(key, 0);
- cx->ks[1] = ss[1] = word_in(key, 1);
- cx->ks[2] = ss[2] = word_in(key, 2);
- cx->ks[3] = ss[3] = word_in(key, 3);
- cx->ks[4] = ss[4] = word_in(key, 4);
- cx->ks[5] = ss[5] = word_in(key, 5);
-
- ke6(cx->ks, 0); ke6(cx->ks, 1);
- ke6(cx->ks, 2); ke6(cx->ks, 3);
- ke6(cx->ks, 4); ke6(cx->ks, 5);
- ke6(cx->ks, 6);
- kef6(cx->ks, 7);
- cx->inf.l = 0;
- cx->inf.b[0] = 12 * 16;
-}
+#define i_rn(bo, bi, n, k) \
+ bo[n] = it_tab[0][byte(bi[n],0)] ^ \
+ it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
+ it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-#define kef8(k,i) \
-{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
- k[8*(i)+ 9] = ss[1] ^= ss[0]; \
- k[8*(i)+10] = ss[2] ^= ss[1]; \
- k[8*(i)+11] = ss[3] ^= ss[2]; \
-}
+#ifdef LARGE_TABLES
-#define ke8(k,i) \
-{ kef8(k,i); \
- k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
- k[8*(i)+13] = ss[5] ^= ss[4]; \
- k[8*(i)+14] = ss[6] ^= ss[5]; \
- k[8*(i)+15] = ss[7] ^= ss[6]; \
-}
+#define ls_box(x) \
+ ( fl_tab[0][byte(x, 0)] ^ \
+ fl_tab[1][byte(x, 1)] ^ \
+ fl_tab[2][byte(x, 2)] ^ \
+ fl_tab[3][byte(x, 3)] )
-AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1])
-{ uint_32t ss[8];
-
- cx->ks[0] = ss[0] = word_in(key, 0);
- cx->ks[1] = ss[1] = word_in(key, 1);
- cx->ks[2] = ss[2] = word_in(key, 2);
- cx->ks[3] = ss[3] = word_in(key, 3);
- cx->ks[4] = ss[4] = word_in(key, 4);
- cx->ks[5] = ss[5] = word_in(key, 5);
- cx->ks[6] = ss[6] = word_in(key, 6);
- cx->ks[7] = ss[7] = word_in(key, 7);
-
- ke8(cx->ks, 0); ke8(cx->ks, 1);
- ke8(cx->ks, 2); ke8(cx->ks, 3);
- ke8(cx->ks, 4); ke8(cx->ks, 5);
- kef8(cx->ks, 6);
- cx->inf.l = 0;
- cx->inf.b[0] = 14 * 16;
-}
+#define f_rl(bo, bi, n, k) \
+ bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
+ fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
+ fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1])
-{
- switch(key_len)
- {
- case 16: case 128: aes_encrypt_key128(key, cx); return;
- case 24: case 192: aes_encrypt_key192(key, cx); return;
- case 32: case 256: aes_encrypt_key256(key, cx); return;
- }
-}
+#define i_rl(bo, bi, n, k) \
+ bo[n] = il_tab[0][byte(bi[n],0)] ^ \
+ il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
+ il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
+ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-#define v(n,i) ((n) - (i) + 2 * ((i) & 3))
-#define k4e(k,i) \
-{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
- k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \
- k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \
- k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \
-}
+#else
-#define kdf4(k,i) \
-{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
- ss[1] = ss[1] ^ ss[3]; \
- ss[2] = ss[2] ^ ss[3]; \
- ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
- ss[i % 4] ^= ss[4]; \
- ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \
- ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \
- ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \
- ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \
-}
+#define ls_box(x) \
+ ((u4byte)sbx_tab[byte(x, 0)] << 0) ^ \
+ ((u4byte)sbx_tab[byte(x, 1)] << 8) ^ \
+ ((u4byte)sbx_tab[byte(x, 2)] << 16) ^ \
+ ((u4byte)sbx_tab[byte(x, 3)] << 24)
-#define kd4(k,i) \
-{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
- ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
- k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \
- k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \
- k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \
- k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \
-}
+#define f_rl(bo, bi, n, k) \
+ bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^ \
+ rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]), 8) ^ \
+ rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
+ rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
-#define kdl4(k,i) \
-{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
- k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
- k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \
- k[v(40,(4*(i))+6)] = ss[0]; \
- k[v(40,(4*(i))+7)] = ss[1]; \
-}
+#define i_rl(bo, bi, n, k) \
+ bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^ \
+ rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]), 8) ^ \
+ rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^ \
+ rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
-AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1])
-{ uint_32t ss[5];
-#if defined( d_vars )
- d_vars;
#endif
- cx->ks[v(40,(0))] = ss[0] = word_in(key, 0);
- cx->ks[v(40,(1))] = ss[1] = word_in(key, 1);
- cx->ks[v(40,(2))] = ss[2] = word_in(key, 2);
- cx->ks[v(40,(3))] = ss[3] = word_in(key, 3);
-
- kdf4(cx->ks, 0); kd4(cx->ks, 1);
- kd4(cx->ks, 2); kd4(cx->ks, 3);
- kd4(cx->ks, 4); kd4(cx->ks, 5);
- kd4(cx->ks, 6); kd4(cx->ks, 7);
- kd4(cx->ks, 8); kdl4(cx->ks, 9);
- cx->inf.l = 0;
- cx->inf.b[0] = 10 * 16;
-}
-#define k6ef(k,i) \
-{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
- k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \
- k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \
- k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \
-}
+void gen_tabs(void)
+{ u4byte i, t;
+ u1byte p, q;
-#define k6e(k,i) \
-{ k6ef(k,i); \
- k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \
- k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \
-}
-
-#define kdf6(k,i) \
-{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \
- ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \
- ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \
- ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \
- ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \
- ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \
-}
-
-#define kd6(k,i) \
-{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
- ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \
- ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \
- ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \
- ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \
- ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \
- ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \
-}
-
-#define kdl6(k,i) \
-{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \
- ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \
- ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \
- ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \
-}
+ /* log and power tables for GF(2**8) finite field with */
+ /* 0x11b as modular polynomial - the simplest prmitive */
+ /* root is 0x11, used here to generate the tables */
-AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
-{ uint_32t ss[7];
-#if defined( d_vars )
- d_vars;
-#endif
- cx->ks[v(48,(0))] = ss[0] = word_in(key, 0);
- cx->ks[v(48,(1))] = ss[1] = word_in(key, 1);
- cx->ks[v(48,(2))] = ss[2] = word_in(key, 2);
- cx->ks[v(48,(3))] = ss[3] = word_in(key, 3);
-
- cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4));
- cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5));
- kdf6(cx->ks, 0); kd6(cx->ks, 1);
- kd6(cx->ks, 2); kd6(cx->ks, 3);
- kd6(cx->ks, 4); kd6(cx->ks, 5);
- kd6(cx->ks, 6); kdl6(cx->ks, 7);
- cx->inf.l = 0;
- cx->inf.b[0] = 12 * 16;
-}
+ for(i = 0,p = 1; i < 256; ++i)
+ {
+ pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i;
-#define k8ef(k,i) \
-{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
- k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \
- k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \
- k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \
-}
+ p = p ^ (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+ }
-#define k8e(k,i) \
-{ k8ef(k,i); \
- k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \
- k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \
- k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \
- k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \
-}
+ log_tab[1] = 0; p = 1;
-#define kdf8(k,i) \
-{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \
- ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \
- ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \
- ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \
- ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \
- ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \
- ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \
- ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \
-}
+ for(i = 0; i < 10; ++i)
+ {
+ rco_tab[i] = p;
-#define kd8(k,i) \
-{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
- ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \
- ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \
- ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \
- ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \
- ss[8] = ls_box(ss[3],0); \
- ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \
- ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \
- ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \
- ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \
-}
+ p = (p << 1) ^ (p & 0x80 ? 0x1b : 0);
+ }
-#define kdl8(k,i) \
-{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \
- ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \
- ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \
- ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
-}
+ /* note that the affine byte transformation matrix in */
+ /* rijndael specification is in big endian format with */
+ /* bit 0 as the most significant bit. In the remainder */
+ /* of the specification the bits are numbered from the */
+ /* least significant end of a byte. */
+
+ for(i = 0; i < 256; ++i)
+ {
+ p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p;
+ q = (q >> 7) | (q << 1); p ^= q;
+ q = (q >> 7) | (q << 1); p ^= q;
+ q = (q >> 7) | (q << 1); p ^= q;
+ q = (q >> 7) | (q << 1); p ^= q ^ 0x63;
+ sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i;
+ }
-AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
-{ uint_32t ss[9];
-#if defined( d_vars )
- d_vars;
+ for(i = 0; i < 256; ++i)
+ {
+ p = sbx_tab[i];
+
+#ifdef LARGE_TABLES
+
+ t = p; fl_tab[0][i] = t;
+ fl_tab[1][i] = rotl(t, 8);
+ fl_tab[2][i] = rotl(t, 16);
+ fl_tab[3][i] = rotl(t, 24);
#endif
- cx->ks[v(56,(0))] = ss[0] = word_in(key, 0);
- cx->ks[v(56,(1))] = ss[1] = word_in(key, 1);
- cx->ks[v(56,(2))] = ss[2] = word_in(key, 2);
- cx->ks[v(56,(3))] = ss[3] = word_in(key, 3);
-
- cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4));
- cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5));
- cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6));
- cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7));
- kdf8(cx->ks, 0); kd8(cx->ks, 1);
- kd8(cx->ks, 2); kd8(cx->ks, 3);
- kd8(cx->ks, 4); kd8(cx->ks, 5);
- kdl8(cx->ks, 6);
- cx->inf.l = 0;
- cx->inf.b[0] = 14 * 16;
-}
+ t = ((u4byte)ff_mult(2, p)) |
+ ((u4byte)p << 8) |
+ ((u4byte)p << 16) |
+ ((u4byte)ff_mult(3, p) << 24);
+
+ ft_tab[0][i] = t;
+ ft_tab[1][i] = rotl(t, 8);
+ ft_tab[2][i] = rotl(t, 16);
+ ft_tab[3][i] = rotl(t, 24);
+
+ p = isb_tab[i];
+
+#ifdef LARGE_TABLES
+
+ t = p; il_tab[0][i] = t;
+ il_tab[1][i] = rotl(t, 8);
+ il_tab[2][i] = rotl(t, 16);
+ il_tab[3][i] = rotl(t, 24);
+#endif
+ t = ((u4byte)ff_mult(14, p)) |
+ ((u4byte)ff_mult( 9, p) << 8) |
+ ((u4byte)ff_mult(13, p) << 16) |
+ ((u4byte)ff_mult(11, p) << 24);
+
+ it_tab[0][i] = t;
+ it_tab[1][i] = rotl(t, 8);
+ it_tab[2][i] = rotl(t, 16);
+ it_tab[3][i] = rotl(t, 24);
+ }
-AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
-{
- switch(key_len)
+ tab_gen = 1;
+};
+
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
+
+#define imix_col(y,x) \
+ u = star_x(x); \
+ v = star_x(u); \
+ w = star_x(v); \
+ t = w ^ (x); \
+ (y) = u ^ v ^ w; \
+ (y) ^= rotr(u ^ t, 8) ^ \
+ rotr(v ^ t, 16) ^ \
+ rotr(t,24)
+
+/* initialise the key schedule from the user supplied key */
+
+#define loop4(i) \
+{ \
+ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
+ t ^= e_key[4 * i]; e_key[4 * i + 4] = t; \
+ t ^= e_key[4 * i + 1]; e_key[4 * i + 5] = t; \
+ t ^= e_key[4 * i + 2]; e_key[4 * i + 6] = t; \
+ t ^= e_key[4 * i + 3]; e_key[4 * i + 7] = t; \
+}
+
+#define loop6(i) \
+{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
+ t ^= e_key[6 * i]; e_key[6 * i + 6] = t; \
+ t ^= e_key[6 * i + 1]; e_key[6 * i + 7] = t; \
+ t ^= e_key[6 * i + 2]; e_key[6 * i + 8] = t; \
+ t ^= e_key[6 * i + 3]; e_key[6 * i + 9] = t; \
+ t ^= e_key[6 * i + 4]; e_key[6 * i + 10] = t; \
+ t ^= e_key[6 * i + 5]; e_key[6 * i + 11] = t; \
+}
+
+#define loop8(i) \
+{ t = ls_box(rotr(t, 8)) ^ rco_tab[i]; \
+ t ^= e_key[8 * i]; e_key[8 * i + 8] = t; \
+ t ^= e_key[8 * i + 1]; e_key[8 * i + 9] = t; \
+ t ^= e_key[8 * i + 2]; e_key[8 * i + 10] = t; \
+ t ^= e_key[8 * i + 3]; e_key[8 * i + 11] = t; \
+ t = e_key[8 * i + 4] ^ ls_box(t); \
+ e_key[8 * i + 12] = t; \
+ t ^= e_key[8 * i + 5]; e_key[8 * i + 13] = t; \
+ t ^= e_key[8 * i + 6]; e_key[8 * i + 14] = t; \
+ t ^= e_key[8 * i + 7]; e_key[8 * i + 15] = t; \
+}
+
+u4byte *rijndael_set_key(RijndaelContext *ctx,
+ const u4byte in_key[], const u4byte key_len)
+{
+ u4byte i, t, u, v, w;
+ u4byte *e_key = ctx->e_key;
+ u4byte *d_key = ctx->d_key;
+ u4byte k_len;
+
+ if(!tab_gen)
+ gen_tabs();
+
+ k_len = ctx->k_len = (key_len + 31) / 32;
+
+ e_key[0] = in_key[0]; e_key[1] = in_key[1];
+ e_key[2] = in_key[2]; e_key[3] = in_key[3];
+
+ switch(k_len)
{
- case 16: case 128: aes_decrypt_key128(key, cx); return;
- case 24: case 192: aes_decrypt_key192(key, cx); return;
- case 32: case 256: aes_decrypt_key256(key, cx); return;
+ case 4: t = e_key[3];
+ for(i = 0; i < 10; ++i)
+ loop4(i);
+ break;
+
+ case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5];
+ for(i = 0; i < 8; ++i)
+ loop6(i);
+ break;
+
+ case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5];
+ e_key[6] = in_key[6]; t = e_key[7] = in_key[7];
+ for(i = 0; i < 7; ++i)
+ loop8(i);
+ break;
}
-}
-#ifndef SILC_AES_ASM
-/* C version of AES */
-
-#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
-#define so(y,x,c) word_out(y, c, s(x,c))
-#define locals(y,x) x[4],y[4]
-#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
- s(y,2) = s(x,2); s(y,3) = s(x,3);
-#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
-#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
-#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
-
-/* Visual C++ .Net v7.1 provides the fastest encryption code when using
- Pentium optimiation with small code but this is poor for decryption
- so we need to control this with the following VC++ pragmas
-*/
+ d_key[0] = e_key[0]; d_key[1] = e_key[1];
+ d_key[2] = e_key[2]; d_key[3] = e_key[3];
-#if defined( _MSC_VER ) && !defined( _WIN64 )
-#pragma optimize( "s", on )
-#endif
+ for(i = 4; i < 4 * k_len + 24; ++i)
+ {
+ imix_col(d_key[i], e_key[i]);
+ }
-#define fwd_var(x,r,c)\
- ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
- : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
- : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
- : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
-#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
-#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
+ return e_key;
+};
-AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
-{ uint_32t locals(b0, b1);
- const uint_32t *kp;
+/* encrypt a block of text */
- kp = cx->ks;
- state_in(b0, in, kp);
+#define f_nround(bo, bi, k) \
+ f_rn(bo, bi, 0, k); \
+ f_rn(bo, bi, 1, k); \
+ f_rn(bo, bi, 2, k); \
+ f_rn(bo, bi, 3, k); \
+ k += 4
- switch(cx->inf.b[0])
- {
- case 14 * 16:
- round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
- round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
- kp += 2 * N_COLS;
- case 12 * 16:
- round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
- round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
- kp += 2 * N_COLS;
- case 10 * 16:
- round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
- round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
- round(fwd_rnd, b1, b0, kp + 3 * N_COLS);
- round(fwd_rnd, b0, b1, kp + 4 * N_COLS);
- round(fwd_rnd, b1, b0, kp + 5 * N_COLS);
- round(fwd_rnd, b0, b1, kp + 6 * N_COLS);
- round(fwd_rnd, b1, b0, kp + 7 * N_COLS);
- round(fwd_rnd, b0, b1, kp + 8 * N_COLS);
- round(fwd_rnd, b1, b0, kp + 9 * N_COLS);
- round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
- }
+#define f_lround(bo, bi, k) \
+ f_rl(bo, bi, 0, k); \
+ f_rl(bo, bi, 1, k); \
+ f_rl(bo, bi, 2, k); \
+ f_rl(bo, bi, 3, k)
- state_out(out, b0);
-}
+void rijndael_encrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte b0[4], b1[4], *kp;
+ u4byte *e_key = ctx->e_key;
+ u4byte k_len = ctx->k_len;
-#define inv_var(x,r,c)\
- ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
- : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
- : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
- : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
+ b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1];
+ b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3];
-#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
-#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
-#define key_ofs 0
-#define rnd_key(n) (kp + n * N_COLS)
+ kp = e_key + 4;
-AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
-{ uint_32t locals(b0, b1);
- const uint_32t *kp;
+ if(k_len > 6)
+ {
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ }
- kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
- state_in(b0, in, kp);
+ if(k_len > 4)
+ {
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ }
- kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
- switch(cx->inf.b[0])
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+ f_nround(b1, b0, kp); f_lround(b0, b1, kp);
+
+ out_blk[0] = b0[0]; out_blk[1] = b0[1];
+ out_blk[2] = b0[2]; out_blk[3] = b0[3];
+};
+
+/* decrypt a block of text */
+
+#define i_nround(bo, bi, k) \
+ i_rn(bo, bi, 0, k); \
+ i_rn(bo, bi, 1, k); \
+ i_rn(bo, bi, 2, k); \
+ i_rn(bo, bi, 3, k); \
+ k -= 4
+
+#define i_lround(bo, bi, k) \
+ i_rl(bo, bi, 0, k); \
+ i_rl(bo, bi, 1, k); \
+ i_rl(bo, bi, 2, k); \
+ i_rl(bo, bi, 3, k)
+
+void rijndael_decrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4])
+{
+ u4byte b0[4], b1[4], *kp;
+ u4byte *e_key = ctx->e_key;
+ u4byte *d_key = ctx->d_key;
+ u4byte k_len = ctx->k_len;
+
+ b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25];
+ b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27];
+
+ kp = d_key + 4 * (k_len + 5);
+
+ if(k_len > 6)
{
- case 14 * 16:
- round(inv_rnd, b1, b0, rnd_key(-13));
- round(inv_rnd, b0, b1, rnd_key(-12));
- case 12 * 16:
- round(inv_rnd, b1, b0, rnd_key(-11));
- round(inv_rnd, b0, b1, rnd_key(-10));
- case 10 * 16:
- round(inv_rnd, b1, b0, rnd_key(-9));
- round(inv_rnd, b0, b1, rnd_key(-8));
- round(inv_rnd, b1, b0, rnd_key(-7));
- round(inv_rnd, b0, b1, rnd_key(-6));
- round(inv_rnd, b1, b0, rnd_key(-5));
- round(inv_rnd, b0, b1, rnd_key(-4));
- round(inv_rnd, b1, b0, rnd_key(-3));
- round(inv_rnd, b0, b1, rnd_key(-2));
- round(inv_rnd, b1, b0, rnd_key(-1));
- round(inv_lrnd, b0, b1, rnd_key( 0));
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
}
- state_out(out, b0);
-}
+ if(k_len > 4)
+ {
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ }
-#if defined(__cplusplus)
-}
-#endif
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+ i_nround(b1, b0, kp); i_lround(b0, b1, kp);
-#endif /* SILC_AES_ASM */
+ out_blk[0] = b0[0]; out_blk[1] = b0[1];
+ out_blk[2] = b0[2]; out_blk[3] = b0[3];
+};
/*
- aes.h
+ rijndael.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2000 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
*/
-#ifndef AES_H
-#define AES_H
+#ifndef RIJNDAEL_H
+#define RIJNDAEL_H
-/*
- * SILC Crypto API for AES
+/*
+ * SILC Crypto API for Rijndael
*/
-SILC_CIPHER_API_SET_KEY(aes_cbc);
-SILC_CIPHER_API_SET_IV(aes_cbc);
-SILC_CIPHER_API_ENCRYPT(aes_cbc);
-SILC_CIPHER_API_DECRYPT(aes_cbc);
-SILC_CIPHER_API_CONTEXT_LEN(aes_cbc);
-SILC_CIPHER_API_SET_KEY(aes_ctr);
-SILC_CIPHER_API_SET_IV(aes_ctr);
-SILC_CIPHER_API_ENCRYPT(aes_ctr);
-SILC_CIPHER_API_DECRYPT(aes_ctr);
-SILC_CIPHER_API_CONTEXT_LEN(aes_ctr);
+SILC_CIPHER_API_SET_KEY(aes);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(aes);
+SILC_CIPHER_API_CONTEXT_LEN(aes);
+SILC_CIPHER_API_ENCRYPT_CBC(aes);
+SILC_CIPHER_API_DECRYPT_CBC(aes);
#endif
+++ /dev/null
-
-; ---------------------------------------------------------------------------
-; Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
-;
-; LICENSE TERMS
-;
-; The free distribution and use of this software in both source and binary
-; form is allowed (with or without changes) provided that:
-;
-; 1. distributions of this source code include the above copyright
-; notice, this list of conditions and the following disclaimer;
-;
-; 2. distributions in binary form include the above copyright
-; notice, this list of conditions and the following disclaimer
-; in the documentation and/or other associated materials;
-;
-; 3. the copyright holder's name is not used to endorse products
-; built using this software without specific written permission.
-;
-; ALTERNATIVELY, provided that this notice is retained in full, this product
-; may be distributed under the terms of the GNU General Public License (GPL),
-; in which case the provisions of the GPL apply INSTEAD OF those given above.
-;
-; DISCLAIMER
-;
-; This software is provided 'as is' with no explicit or implied warranties
-; in respect of its properties, including, but not limited to, correctness
-; and/or fitness for purpose.
-; ---------------------------------------------------------------------------
-; Issue 09/09/2006
-
-; An AES implementation for x86 processors using the YASM (or NASM) assembler.
-; This is an assembler implementation that covers encryption and decryption
-; only and is intended as a replacement of the C file aescrypt.c. It hence
-; requires the file aeskey.c for keying and aestab.c for the AES tables. It
-; employs full tables rather than compressed tables.
-
-; This code provides the standard AES block size (128 bits, 16 bytes) and the
-; three standard AES key sizes (128, 192 and 256 bits). It has the same call
-; interface as my C implementation. The ebx, esi, edi and ebp registers are
-; preserved across calls but eax, ecx and edx and the artihmetic status flags
-; are not. It is also important that the defines below match those used in the
-; C code. This code uses the VC++ register saving conentions; if it is used
-; with another compiler, conventions for using and saving registers may need to
-; be checked (and calling conventions). The YASM command line for the VC++
-; custom build step is:
-;
-; yasm -Xvc -f win32 -o "$(TargetDir)\$(InputName).obj" "$(InputPath)"
-;
-; The calling intefaces are:
-;
-; AES_RETURN aes_encrypt(const unsigned char in_blk[],
-; unsigned char out_blk[], const aes_encrypt_ctx cx[1]);
-;
-; AES_RETURN aes_decrypt(const unsigned char in_blk[],
-; unsigned char out_blk[], const aes_decrypt_ctx cx[1]);
-;
-; AES_RETURN aes_encrypt_key<NNN>(const unsigned char key[],
-; const aes_encrypt_ctx cx[1]);
-;
-; AES_RETURN aes_decrypt_key<NNN>(const unsigned char key[],
-; const aes_decrypt_ctx cx[1]);
-;
-; AES_RETURN aes_encrypt_key(const unsigned char key[],
-; unsigned int len, const aes_decrypt_ctx cx[1]);
-;
-; AES_RETURN aes_decrypt_key(const unsigned char key[],
-; unsigned int len, const aes_decrypt_ctx cx[1]);
-;
-; where <NNN> is 128, 102 or 256. In the last two calls the length can be in
-; either bits or bytes.
-;
-; Comment in/out the following lines to obtain the desired subroutines. These
-; selections MUST match those in the C header file aes.h
-
-%define AES_128 ; define if AES with 128 bit keys is needed
-%define AES_192 ; define if AES with 192 bit keys is needed
-%define AES_256 ; define if AES with 256 bit keys is needed
-%define AES_VAR ; define if a variable key size is needed
-%define ENCRYPTION ; define if encryption is needed
-%define DECRYPTION ; define if decryption is needed
-%define AES_REV_DKS ; define if key decryption schedule is reversed
-%define LAST_ROUND_TABLES ; define if tables are to be used for last round
-
-; offsets to parameters
-
-in_blk equ 4 ; input byte array address parameter
-out_blk equ 8 ; output byte array address parameter
-ctx equ 12 ; AES context structure
-stk_spc equ 20 ; stack space
-%define parms 12 ; parameter space on stack
-
-; The encryption key schedule has the following in memory layout where N is the
-; number of rounds (10, 12 or 14):
-;
-; lo: | input key (round 0) | ; each round is four 32-bit words
-; | encryption round 1 |
-; | encryption round 2 |
-; ....
-; | encryption round N-1 |
-; hi: | encryption round N |
-;
-; The decryption key schedule is normally set up so that it has the same
-; layout as above by actually reversing the order of the encryption key
-; schedule in memory (this happens when AES_REV_DKS is set):
-;
-; lo: | decryption round 0 | = | encryption round N |
-; | decryption round 1 | = INV_MIX_COL[ | encryption round N-1 | ]
-; | decryption round 2 | = INV_MIX_COL[ | encryption round N-2 | ]
-; .... ....
-; | decryption round N-1 | = INV_MIX_COL[ | encryption round 1 | ]
-; hi: | decryption round N | = | input key (round 0) |
-;
-; with rounds except the first and last modified using inv_mix_column()
-; But if AES_REV_DKS is NOT set the order of keys is left as it is for
-; encryption so that it has to be accessed in reverse when used for
-; decryption (although the inverse mix column modifications are done)
-;
-; lo: | decryption round 0 | = | input key (round 0) |
-; | decryption round 1 | = INV_MIX_COL[ | encryption round 1 | ]
-; | decryption round 2 | = INV_MIX_COL[ | encryption round 2 | ]
-; .... ....
-; | decryption round N-1 | = INV_MIX_COL[ | encryption round N-1 | ]
-; hi: | decryption round N | = | encryption round N |
-;
-; This layout is faster when the assembler key scheduling provided here
-; is used.
-;
-; The DLL interface must use the _stdcall convention in which the number
-; of bytes of parameter space is added after an @ to the sutine's name.
-; We must also remove our parameters from the stack before return (see
-; the do_exit macro). Define DLL_EXPORT for the Dynamic Link Library version.
-
-;%define DLL_EXPORT
-
-; End of user defines
-
-%ifdef AES_VAR
-%ifndef AES_128
-%define AES_128
-%endif
-%ifndef AES_192
-%define AES_192
-%endif
-%ifndef AES_256
-%define AES_256
-%endif
-%endif
-
-%ifdef AES_VAR
-%define KS_LENGTH 60
-%elifdef AES_256
-%define KS_LENGTH 60
-%elifdef AES_192
-%define KS_LENGTH 52
-%else
-%define KS_LENGTH 44
-%endif
-
-; These macros implement stack based local variables
-
-%macro save 2
- mov [esp+4*%1],%2
-%endmacro
-
-%macro restore 2
- mov %1,[esp+4*%2]
-%endmacro
-
-; the DLL has to implement the _stdcall calling interface on return
-; In this case we have to take our parameters (3 4-byte pointers)
-; off the stack
-
-%macro do_name 1-2 parms
-%ifndef DLL_EXPORT
- align 32
- global %1
-%1:
-%else
- align 32
- global %1@%2
- export %1@%2
-%1@%2:
-%endif
-%endmacro
-
-%macro do_call 1-2 parms
-%ifndef DLL_EXPORT
- call %1
- add esp,%2
-%else
- call %1@%2
-%endif
-%endmacro
-
-%macro do_exit 0-1 parms
-%ifdef DLL_EXPORT
- ret %1
-%else
- ret
-%endif
-%endmacro
-
-%ifdef ENCRYPTION
-
- extern t_fn
-
-%define etab_0(x) [t_fn+4*x]
-%define etab_1(x) [t_fn+1024+4*x]
-%define etab_2(x) [t_fn+2048+4*x]
-%define etab_3(x) [t_fn+3072+4*x]
-
-%ifdef LAST_ROUND_TABLES
-
- extern t_fl
-
-%define eltab_0(x) [t_fl+4*x]
-%define eltab_1(x) [t_fl+1024+4*x]
-%define eltab_2(x) [t_fl+2048+4*x]
-%define eltab_3(x) [t_fl+3072+4*x]
-
-%endif
-
-; ROUND FUNCTION. Build column[2] on ESI and column[3] on EDI that have the
-; round keys pre-loaded. Build column[0] in EBP and column[1] in EBX.
-;
-; Input:
-;
-; EAX column[0]
-; EBX column[1]
-; ECX column[2]
-; EDX column[3]
-; ESI column key[round][2]
-; EDI column key[round][3]
-; EBP scratch
-;
-; Output:
-;
-; EBP column[0] unkeyed
-; EBX column[1] unkeyed
-; ESI column[2] keyed
-; EDI column[3] keyed
-; EAX scratch
-; ECX scratch
-; EDX scratch
-
-%macro rnd_fun 2
-
- rol ebx,16
- %1 esi, cl, 0, ebp
- %1 esi, dh, 1, ebp
- %1 esi, bh, 3, ebp
- %1 edi, dl, 0, ebp
- %1 edi, ah, 1, ebp
- %1 edi, bl, 2, ebp
- %2 ebp, al, 0, ebp
- shr ebx,16
- and eax,0xffff0000
- or eax,ebx
- shr edx,16
- %1 ebp, ah, 1, ebx
- %1 ebp, dh, 3, ebx
- %2 ebx, dl, 2, ebx
- %1 ebx, ch, 1, edx
- %1 ebx, al, 0, edx
- shr eax,16
- shr ecx,16
- %1 ebp, cl, 2, edx
- %1 edi, ch, 3, edx
- %1 esi, al, 2, edx
- %1 ebx, ah, 3, edx
-
-%endmacro
-
-; Basic MOV and XOR Operations for normal rounds
-
-%macro nr_xor 4
- movzx %4,%2
- xor %1,etab_%3(%4)
-%endmacro
-
-%macro nr_mov 4
- movzx %4,%2
- mov %1,etab_%3(%4)
-%endmacro
-
-; Basic MOV and XOR Operations for last round
-
-%ifdef LAST_ROUND_TABLES
-
- %macro lr_xor 4
- movzx %4,%2
- xor %1,eltab_%3(%4)
- %endmacro
-
- %macro lr_mov 4
- movzx %4,%2
- mov %1,eltab_%3(%4)
- %endmacro
-
-%endif
-
-%macro enc_round 0
-
- add ebp,16
- save 0,ebp
- mov esi,[ebp+8]
- mov edi,[ebp+12]
-
- rnd_fun nr_xor, nr_mov
-
- mov eax,ebp
- mov ecx,esi
- mov edx,edi
- restore ebp,0
- xor eax,[ebp]
- xor ebx,[ebp+4]
-
-%endmacro
-
-%macro enc_last_round 0
-
- add ebp,16
- save 0,ebp
- mov esi,[ebp+8]
- mov edi,[ebp+12]
-
- rnd_fun lr_xor, lr_mov
-
- mov eax,ebp
- restore ebp,0
- xor eax,[ebp]
- xor ebx,[ebp+4]
-
-%endmacro
-
- section .text align=32
-
-; AES Encryption Subroutine
-
- do_name aes_encrypt
-
- sub esp,stk_spc
- mov [esp+16],ebp
- mov [esp+12],ebx
- mov [esp+ 8],esi
- mov [esp+ 4],edi
-
- mov esi,[esp+in_blk+stk_spc] ; input pointer
- mov eax,[esi ]
- mov ebx,[esi+ 4]
- mov ecx,[esi+ 8]
- mov edx,[esi+12]
-
- mov ebp,[esp+ctx+stk_spc] ; key pointer
- movzx edi,byte [ebp+4*KS_LENGTH]
- xor eax,[ebp ]
- xor ebx,[ebp+ 4]
- xor ecx,[ebp+ 8]
- xor edx,[ebp+12]
-
-; determine the number of rounds
-
- cmp edi,10*16
- je .3
- cmp edi,12*16
- je .2
- cmp edi,14*16
- je .1
- mov eax,-1
- jmp .5
-
-.1: enc_round
- enc_round
-.2: enc_round
- enc_round
-.3: enc_round
- enc_round
- enc_round
- enc_round
- enc_round
- enc_round
- enc_round
- enc_round
- enc_round
- enc_last_round
-
- mov edx,[esp+out_blk+stk_spc]
- mov [edx],eax
- mov [edx+4],ebx
- mov [edx+8],esi
- mov [edx+12],edi
- xor eax,eax
-
-.5: mov ebp,[esp+16]
- mov ebx,[esp+12]
- mov esi,[esp+ 8]
- mov edi,[esp+ 4]
- add esp,stk_spc
- do_exit
-
-%endif
-
-%ifdef DECRYPTION
-
- extern t_in
-
-%define dtab_0(x) [t_in+4*x]
-%define dtab_1(x) [t_in+1024+4*x]
-%define dtab_2(x) [t_in+2048+4*x]
-%define dtab_3(x) [t_in+3072+4*x]
-
-%ifdef LAST_ROUND_TABLES
-
- extern t_il
-
-%define dltab_0(x) [t_il+4*x]
-%define dltab_1(x) [t_il+1024+4*x]
-%define dltab_2(x) [t_il+2048+4*x]
-%define dltab_3(x) [t_il+3072+4*x]
-
-%endif
-
-%macro irn_fun 2
-
- rol eax,16
- %1 esi, cl, 0, ebp
- %1 esi, bh, 1, ebp
- %1 esi, al, 2, ebp
- %1 edi, dl, 0, ebp
- %1 edi, ch, 1, ebp
- %1 edi, ah, 3, ebp
- %2 ebp, bl, 0, ebp
- shr eax,16
- and ebx,0xffff0000
- or ebx,eax
- shr ecx,16
- %1 ebp, bh, 1, eax
- %1 ebp, ch, 3, eax
- %2 eax, cl, 2, ecx
- %1 eax, bl, 0, ecx
- %1 eax, dh, 1, ecx
- shr ebx,16
- shr edx,16
- %1 esi, dh, 3, ecx
- %1 ebp, dl, 2, ecx
- %1 eax, bh, 3, ecx
- %1 edi, bl, 2, ecx
-
-%endmacro
-
-; Basic MOV and XOR Operations for normal rounds
-
-%macro ni_xor 4
- movzx %4,%2
- xor %1,dtab_%3(%4)
-%endmacro
-
-%macro ni_mov 4
- movzx %4,%2
- mov %1,dtab_%3(%4)
-%endmacro
-
-; Basic MOV and XOR Operations for last round
-
-%ifdef LAST_ROUND_TABLES
-
-%macro li_xor 4
- movzx %4,%2
- xor %1,dltab_%3(%4)
-%endmacro
-
-%macro li_mov 4
- movzx %4,%2
- mov %1,dltab_%3(%4)
-%endmacro
-
-%endif
-
-%macro dec_round 0
-
-%ifdef AES_REV_DKS
- add ebp,16
-%else
- sub ebp,16
-%endif
- save 0,ebp
- mov esi,[ebp+8]
- mov edi,[ebp+12]
-
- irn_fun ni_xor, ni_mov
-
- mov ebx,ebp
- mov ecx,esi
- mov edx,edi
- restore ebp,0
- xor eax,[ebp]
- xor ebx,[ebp+4]
-
-%endmacro
-
-%macro dec_last_round 0
-
-%ifdef AES_REV_DKS
- add ebp,16
-%else
- sub ebp,16
-%endif
- save 0,ebp
- mov esi,[ebp+8]
- mov edi,[ebp+12]
-
- irn_fun li_xor, li_mov
-
- mov ebx,ebp
- restore ebp,0
- xor eax,[ebp]
- xor ebx,[ebp+4]
-
-%endmacro
-
- section .text align=32
-
-; AES Decryption Subroutine
-
- do_name aes_decrypt
-
- sub esp,stk_spc
- mov [esp+16],ebp
- mov [esp+12],ebx
- mov [esp+ 8],esi
- mov [esp+ 4],edi
-
-; input four columns and xor in first round key
-
- mov esi,[esp+in_blk+stk_spc] ; input pointer
- mov eax,[esi ]
- mov ebx,[esi+ 4]
- mov ecx,[esi+ 8]
- mov edx,[esi+12]
- lea esi,[esi+16]
-
- mov ebp,[esp+ctx+stk_spc] ; key pointer
- movzx edi,byte[ebp+4*KS_LENGTH]
-%ifndef AES_REV_DKS ; if decryption key schedule is not reversed
- lea ebp,[ebp+edi] ; we have to access it from the top down
-%endif
- xor eax,[ebp ] ; key schedule
- xor ebx,[ebp+ 4]
- xor ecx,[ebp+ 8]
- xor edx,[ebp+12]
-
-; determine the number of rounds
-
- cmp edi,10*16
- je .3
- cmp edi,12*16
- je .2
- cmp edi,14*16
- je .1
- mov eax,-1
- jmp .5
-
-.1: dec_round
- dec_round
-.2: dec_round
- dec_round
-.3: dec_round
- dec_round
- dec_round
- dec_round
- dec_round
- dec_round
- dec_round
- dec_round
- dec_round
- dec_last_round
-
-; move final values to the output array.
-
- mov ebp,[esp+out_blk+stk_spc]
- mov [ebp],eax
- mov [ebp+4],ebx
- mov [ebp+8],esi
- mov [ebp+12],edi
- xor eax,eax
-
-.5: mov ebp,[esp+16]
- mov ebx,[esp+12]
- mov esi,[esp+ 8]
- mov edi,[esp+ 4]
- add esp,stk_spc
- do_exit
-
-%endif
-
- end
+++ /dev/null
-\r
-; ---------------------------------------------------------------------------\r
-; Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.\r
-;\r
-; LICENSE TERMS\r
-;\r
-; The free distribution and use of this software in both source and binary\r
-; form is allowed (with or without changes) provided that:\r
-;\r
-; 1. distributions of this source code include the above copyright\r
-; notice, this list of conditions and the following disclaimer;\r
-;\r
-; 2. distributions in binary form include the above copyright\r
-; notice, this list of conditions and the following disclaimer\r
-; in the documentation and/or other associated materials;\r
-;\r
-; 3. the copyright holder's name is not used to endorse products\r
-; built using this software without specific written permission.\r
-;\r
-; ALTERNATIVELY, provided that this notice is retained in full, this product\r
-; may be distributed under the terms of the GNU General Public License (GPL),\r
-; in which case the provisions of the GPL apply INSTEAD OF those given above.\r
-;\r
-; DISCLAIMER\r
-;\r
-; This software is provided 'as is' with no explicit or implied warranties\r
-; in respect of its properties, including, but not limited to, correctness\r
-; and/or fitness for purpose.\r
-; ---------------------------------------------------------------------------\r
-; Issue 09/09/2006\r
-\r
-; I am grateful to Dag Arne Osvik for many discussions of the techniques that\r
-; can be used to optimise AES assembler code on AMD64/EM64T architectures.\r
-; Some of the techniques used in this implementation are the result of\r
-; suggestions made by him for which I am most grateful.\r
-\r
-; An AES implementation for AMD64 processors using the YASM assembler. This\r
-; implemetation provides only encryption, decryption and hence requires key\r
-; scheduling support in C. It uses 8k bytes of tables but its encryption and\r
-; decryption performance is very close to that obtained using large tables.\r
-; It can use either Windows or Gnu/Linux calling conventions, which are as\r
-; follows:\r
-; windows gnu/linux\r
-;\r
-; in_blk rcx rdi\r
-; out_blk rdx rsi\r
-; context (cx) r8 rdx\r
-;\r
-; preserved rsi - + rbx, rbp, rsp, r12, r13, r14 & r15\r
-; registers rdi - on both\r
-;\r
-; destroyed - rsi + rax, rcx, rdx, r8, r9, r10 & r11\r
-; registers - rdi on both\r
-;\r
-; The default convention is that for windows, the gnu/linux convention being\r
-; used if __GNUC__ is defined.\r
-;\r
-; This code provides the standard AES block size (128 bits, 16 bytes) and the\r
-; three standard AES key sizes (128, 192 and 256 bits). It has the same call\r
-; interface as my C implementation. It uses the Microsoft C AMD64 calling\r
-; conventions in which the three parameters are placed in rcx, rdx and r8\r
-; respectively. The rbx, rsi, rdi, rbp and r12..r15 registers are preserved.\r
-;\r
-; AES_RETURN aes_encrypt(const unsigned char in_blk[],\r
-; unsigned char out_blk[], const aes_encrypt_ctx cx[1]);\r
-;\r
-; AES_RETURN aes_decrypt(const unsigned char in_blk[],\r
-; unsigned char out_blk[], const aes_decrypt_ctx cx[1]);\r
-;\r
-; AES_RETURN aes_encrypt_key<NNN>(const unsigned char key[],\r
-; const aes_encrypt_ctx cx[1]);\r
-;\r
-; AES_RETURN aes_decrypt_key<NNN>(const unsigned char key[],\r
-; const aes_decrypt_ctx cx[1]);\r
-;\r
-; AES_RETURN aes_encrypt_key(const unsigned char key[],\r
-; unsigned int len, const aes_decrypt_ctx cx[1]);\r
-;\r
-; AES_RETURN aes_decrypt_key(const unsigned char key[],\r
-; unsigned int len, const aes_decrypt_ctx cx[1]);\r
-;\r
-; where <NNN> is 128, 102 or 256. In the last two calls the length can be in\r
-; either bits or bytes.\r
-;\r
-; Comment in/out the following lines to obtain the desired subroutines. These\r
-; selections MUST match those in the C header file aes.h\r
-\r
-%define AES_128 ; define if AES with 128 bit keys is needed\r
-%define AES_192 ; define if AES with 192 bit keys is needed\r
-%define AES_256 ; define if AES with 256 bit keys is needed\r
-%define AES_VAR ; define if a variable key size is needed\r
-%define ENCRYPTION ; define if encryption is needed\r
-%define DECRYPTION ; define if decryption is needed\r
-%define AES_REV_DKS ; define if key decryption schedule is reversed\r
-%define LAST_ROUND_TABLES ; define for the faster version using extra tables\r
-\r
-; The encryption key schedule has the following in memory layout where N is the\r
-; number of rounds (10, 12 or 14):\r
-;\r
-; lo: | input key (round 0) | ; each round is four 32-bit words\r
-; | encryption round 1 |\r
-; | encryption round 2 |\r
-; ....\r
-; | encryption round N-1 |\r
-; hi: | encryption round N |\r
-;\r
-; The decryption key schedule is normally set up so that it has the same\r
-; layout as above by actually reversing the order of the encryption key\r
-; schedule in memory (this happens when AES_REV_DKS is set):\r
-;\r
-; lo: | decryption round 0 | = | encryption round N |\r
-; | decryption round 1 | = INV_MIX_COL[ | encryption round N-1 | ]\r
-; | decryption round 2 | = INV_MIX_COL[ | encryption round N-2 | ]\r
-; .... ....\r
-; | decryption round N-1 | = INV_MIX_COL[ | encryption round 1 | ]\r
-; hi: | decryption round N | = | input key (round 0) |\r
-;\r
-; with rounds except the first and last modified using inv_mix_column()\r
-; But if AES_REV_DKS is NOT set the order of keys is left as it is for\r
-; encryption so that it has to be accessed in reverse when used for\r
-; decryption (although the inverse mix column modifications are done)\r
-;\r
-; lo: | decryption round 0 | = | input key (round 0) |\r
-; | decryption round 1 | = INV_MIX_COL[ | encryption round 1 | ]\r
-; | decryption round 2 | = INV_MIX_COL[ | encryption round 2 | ]\r
-; .... ....\r
-; | decryption round N-1 | = INV_MIX_COL[ | encryption round N-1 | ]\r
-; hi: | decryption round N | = | encryption round N |\r
-;\r
-; This layout is faster when the assembler key scheduling provided here\r
-; is used.\r
-;\r
-; The DLL interface must use the _stdcall convention in which the number\r
-; of bytes of parameter space is added after an @ to the sutine's name.\r
-; We must also remove our parameters from the stack before return (see\r
-; the do_exit macro). Define DLL_EXPORT for the Dynamic Link Library version.\r
-\r
-;%define DLL_EXPORT\r
-\r
-; End of user defines\r
-\r
-%ifdef AES_VAR\r
-%ifndef AES_128\r
-%define AES_128\r
-%endif\r
-%ifndef AES_192\r
-%define AES_192\r
-%endif\r
-%ifndef AES_256\r
-%define AES_256\r
-%endif\r
-%endif\r
-\r
-%ifdef AES_VAR\r
-%define KS_LENGTH 60\r
-%elifdef AES_256\r
-%define KS_LENGTH 60\r
-%elifdef AES_192\r
-%define KS_LENGTH 52\r
-%else\r
-%define KS_LENGTH 44\r
-%endif\r
-\r
-%define r0 rax\r
-%define r1 rdx\r
-%define r2 rcx\r
-%define r3 rbx\r
-%define r4 rsi\r
-%define r5 rdi\r
-%define r6 rbp\r
-%define r7 rsp\r
-\r
-%define raxd eax\r
-%define rdxd edx\r
-%define rcxd ecx\r
-%define rbxd ebx\r
-%define rsid esi\r
-%define rdid edi\r
-%define rbpd ebp\r
-%define rspd esp\r
-\r
-%define raxb al\r
-%define rdxb dl\r
-%define rcxb cl\r
-%define rbxb bl\r
-%define rsib sil\r
-%define rdib dil\r
-%define rbpb bpl\r
-%define rspb spl\r
-\r
-%define r0h ah\r
-%define r1h dh\r
-%define r2h ch\r
-%define r3h bh\r
-\r
-%define r0d eax\r
-%define r1d edx\r
-%define r2d ecx\r
-%define r3d ebx\r
-\r
-; finite field multiplies by {02}, {04} and {08}\r
-\r
-%define f2(x) ((x<<1)^(((x>>7)&1)*0x11b))\r
-%define f4(x) ((x<<2)^(((x>>6)&1)*0x11b)^(((x>>6)&2)*0x11b))\r
-%define f8(x) ((x<<3)^(((x>>5)&1)*0x11b)^(((x>>5)&2)*0x11b)^(((x>>5)&4)*0x11b))\r
-\r
-; finite field multiplies required in table generation\r
-\r
-%define f3(x) (f2(x) ^ x)\r
-%define f9(x) (f8(x) ^ x)\r
-%define fb(x) (f8(x) ^ f2(x) ^ x)\r
-%define fd(x) (f8(x) ^ f4(x) ^ x)\r
-%define fe(x) (f8(x) ^ f4(x) ^ f2(x))\r
-\r
-; macro for expanding S-box data\r
-\r
-%macro enc_vals 1\r
- db %1(0x63),%1(0x7c),%1(0x77),%1(0x7b),%1(0xf2),%1(0x6b),%1(0x6f),%1(0xc5)\r
- db %1(0x30),%1(0x01),%1(0x67),%1(0x2b),%1(0xfe),%1(0xd7),%1(0xab),%1(0x76)\r
- db %1(0xca),%1(0x82),%1(0xc9),%1(0x7d),%1(0xfa),%1(0x59),%1(0x47),%1(0xf0)\r
- db %1(0xad),%1(0xd4),%1(0xa2),%1(0xaf),%1(0x9c),%1(0xa4),%1(0x72),%1(0xc0)\r
- db %1(0xb7),%1(0xfd),%1(0x93),%1(0x26),%1(0x36),%1(0x3f),%1(0xf7),%1(0xcc)\r
- db %1(0x34),%1(0xa5),%1(0xe5),%1(0xf1),%1(0x71),%1(0xd8),%1(0x31),%1(0x15)\r
- db %1(0x04),%1(0xc7),%1(0x23),%1(0xc3),%1(0x18),%1(0x96),%1(0x05),%1(0x9a)\r
- db %1(0x07),%1(0x12),%1(0x80),%1(0xe2),%1(0xeb),%1(0x27),%1(0xb2),%1(0x75)\r
- db %1(0x09),%1(0x83),%1(0x2c),%1(0x1a),%1(0x1b),%1(0x6e),%1(0x5a),%1(0xa0)\r
- db %1(0x52),%1(0x3b),%1(0xd6),%1(0xb3),%1(0x29),%1(0xe3),%1(0x2f),%1(0x84)\r
- db %1(0x53),%1(0xd1),%1(0x00),%1(0xed),%1(0x20),%1(0xfc),%1(0xb1),%1(0x5b)\r
- db %1(0x6a),%1(0xcb),%1(0xbe),%1(0x39),%1(0x4a),%1(0x4c),%1(0x58),%1(0xcf)\r
- db %1(0xd0),%1(0xef),%1(0xaa),%1(0xfb),%1(0x43),%1(0x4d),%1(0x33),%1(0x85)\r
- db %1(0x45),%1(0xf9),%1(0x02),%1(0x7f),%1(0x50),%1(0x3c),%1(0x9f),%1(0xa8)\r
- db %1(0x51),%1(0xa3),%1(0x40),%1(0x8f),%1(0x92),%1(0x9d),%1(0x38),%1(0xf5)\r
- db %1(0xbc),%1(0xb6),%1(0xda),%1(0x21),%1(0x10),%1(0xff),%1(0xf3),%1(0xd2)\r
- db %1(0xcd),%1(0x0c),%1(0x13),%1(0xec),%1(0x5f),%1(0x97),%1(0x44),%1(0x17)\r
- db %1(0xc4),%1(0xa7),%1(0x7e),%1(0x3d),%1(0x64),%1(0x5d),%1(0x19),%1(0x73)\r
- db %1(0x60),%1(0x81),%1(0x4f),%1(0xdc),%1(0x22),%1(0x2a),%1(0x90),%1(0x88)\r
- db %1(0x46),%1(0xee),%1(0xb8),%1(0x14),%1(0xde),%1(0x5e),%1(0x0b),%1(0xdb)\r
- db %1(0xe0),%1(0x32),%1(0x3a),%1(0x0a),%1(0x49),%1(0x06),%1(0x24),%1(0x5c)\r
- db %1(0xc2),%1(0xd3),%1(0xac),%1(0x62),%1(0x91),%1(0x95),%1(0xe4),%1(0x79)\r
- db %1(0xe7),%1(0xc8),%1(0x37),%1(0x6d),%1(0x8d),%1(0xd5),%1(0x4e),%1(0xa9)\r
- db %1(0x6c),%1(0x56),%1(0xf4),%1(0xea),%1(0x65),%1(0x7a),%1(0xae),%1(0x08)\r
- db %1(0xba),%1(0x78),%1(0x25),%1(0x2e),%1(0x1c),%1(0xa6),%1(0xb4),%1(0xc6)\r
- db %1(0xe8),%1(0xdd),%1(0x74),%1(0x1f),%1(0x4b),%1(0xbd),%1(0x8b),%1(0x8a)\r
- db %1(0x70),%1(0x3e),%1(0xb5),%1(0x66),%1(0x48),%1(0x03),%1(0xf6),%1(0x0e)\r
- db %1(0x61),%1(0x35),%1(0x57),%1(0xb9),%1(0x86),%1(0xc1),%1(0x1d),%1(0x9e)\r
- db %1(0xe1),%1(0xf8),%1(0x98),%1(0x11),%1(0x69),%1(0xd9),%1(0x8e),%1(0x94)\r
- db %1(0x9b),%1(0x1e),%1(0x87),%1(0xe9),%1(0xce),%1(0x55),%1(0x28),%1(0xdf)\r
- db %1(0x8c),%1(0xa1),%1(0x89),%1(0x0d),%1(0xbf),%1(0xe6),%1(0x42),%1(0x68)\r
- db %1(0x41),%1(0x99),%1(0x2d),%1(0x0f),%1(0xb0),%1(0x54),%1(0xbb),%1(0x16)\r
-%endmacro\r
-\r
-%macro dec_vals 1\r
- db %1(0x52),%1(0x09),%1(0x6a),%1(0xd5),%1(0x30),%1(0x36),%1(0xa5),%1(0x38)\r
- db %1(0xbf),%1(0x40),%1(0xa3),%1(0x9e),%1(0x81),%1(0xf3),%1(0xd7),%1(0xfb)\r
- db %1(0x7c),%1(0xe3),%1(0x39),%1(0x82),%1(0x9b),%1(0x2f),%1(0xff),%1(0x87)\r
- db %1(0x34),%1(0x8e),%1(0x43),%1(0x44),%1(0xc4),%1(0xde),%1(0xe9),%1(0xcb)\r
- db %1(0x54),%1(0x7b),%1(0x94),%1(0x32),%1(0xa6),%1(0xc2),%1(0x23),%1(0x3d)\r
- db %1(0xee),%1(0x4c),%1(0x95),%1(0x0b),%1(0x42),%1(0xfa),%1(0xc3),%1(0x4e)\r
- db %1(0x08),%1(0x2e),%1(0xa1),%1(0x66),%1(0x28),%1(0xd9),%1(0x24),%1(0xb2)\r
- db %1(0x76),%1(0x5b),%1(0xa2),%1(0x49),%1(0x6d),%1(0x8b),%1(0xd1),%1(0x25)\r
- db %1(0x72),%1(0xf8),%1(0xf6),%1(0x64),%1(0x86),%1(0x68),%1(0x98),%1(0x16)\r
- db %1(0xd4),%1(0xa4),%1(0x5c),%1(0xcc),%1(0x5d),%1(0x65),%1(0xb6),%1(0x92)\r
- db %1(0x6c),%1(0x70),%1(0x48),%1(0x50),%1(0xfd),%1(0xed),%1(0xb9),%1(0xda)\r
- db %1(0x5e),%1(0x15),%1(0x46),%1(0x57),%1(0xa7),%1(0x8d),%1(0x9d),%1(0x84)\r
- db %1(0x90),%1(0xd8),%1(0xab),%1(0x00),%1(0x8c),%1(0xbc),%1(0xd3),%1(0x0a)\r
- db %1(0xf7),%1(0xe4),%1(0x58),%1(0x05),%1(0xb8),%1(0xb3),%1(0x45),%1(0x06)\r
- db %1(0xd0),%1(0x2c),%1(0x1e),%1(0x8f),%1(0xca),%1(0x3f),%1(0x0f),%1(0x02)\r
- db %1(0xc1),%1(0xaf),%1(0xbd),%1(0x03),%1(0x01),%1(0x13),%1(0x8a),%1(0x6b)\r
- db %1(0x3a),%1(0x91),%1(0x11),%1(0x41),%1(0x4f),%1(0x67),%1(0xdc),%1(0xea)\r
- db %1(0x97),%1(0xf2),%1(0xcf),%1(0xce),%1(0xf0),%1(0xb4),%1(0xe6),%1(0x73)\r
- db %1(0x96),%1(0xac),%1(0x74),%1(0x22),%1(0xe7),%1(0xad),%1(0x35),%1(0x85)\r
- db %1(0xe2),%1(0xf9),%1(0x37),%1(0xe8),%1(0x1c),%1(0x75),%1(0xdf),%1(0x6e)\r
- db %1(0x47),%1(0xf1),%1(0x1a),%1(0x71),%1(0x1d),%1(0x29),%1(0xc5),%1(0x89)\r
- db %1(0x6f),%1(0xb7),%1(0x62),%1(0x0e),%1(0xaa),%1(0x18),%1(0xbe),%1(0x1b)\r
- db %1(0xfc),%1(0x56),%1(0x3e),%1(0x4b),%1(0xc6),%1(0xd2),%1(0x79),%1(0x20)\r
- db %1(0x9a),%1(0xdb),%1(0xc0),%1(0xfe),%1(0x78),%1(0xcd),%1(0x5a),%1(0xf4)\r
- db %1(0x1f),%1(0xdd),%1(0xa8),%1(0x33),%1(0x88),%1(0x07),%1(0xc7),%1(0x31)\r
- db %1(0xb1),%1(0x12),%1(0x10),%1(0x59),%1(0x27),%1(0x80),%1(0xec),%1(0x5f)\r
- db %1(0x60),%1(0x51),%1(0x7f),%1(0xa9),%1(0x19),%1(0xb5),%1(0x4a),%1(0x0d)\r
- db %1(0x2d),%1(0xe5),%1(0x7a),%1(0x9f),%1(0x93),%1(0xc9),%1(0x9c),%1(0xef)\r
- db %1(0xa0),%1(0xe0),%1(0x3b),%1(0x4d),%1(0xae),%1(0x2a),%1(0xf5),%1(0xb0)\r
- db %1(0xc8),%1(0xeb),%1(0xbb),%1(0x3c),%1(0x83),%1(0x53),%1(0x99),%1(0x61)\r
- db %1(0x17),%1(0x2b),%1(0x04),%1(0x7e),%1(0xba),%1(0x77),%1(0xd6),%1(0x26)\r
- db %1(0xe1),%1(0x69),%1(0x14),%1(0x63),%1(0x55),%1(0x21),%1(0x0c),%1(0x7d)\r
-%endmacro\r
-\r
-%define u8(x) f2(x), x, x, f3(x), f2(x), x, x, f3(x)\r
-%define v8(x) fe(x), f9(x), fd(x), fb(x), fe(x), f9(x), fd(x), x\r
-%define w8(x) x, 0, 0, 0, x, 0, 0, 0\r
-\r
-%define tptr rbp ; table pointer\r
-%define kptr r8 ; key schedule pointer\r
-%define fofs 128 ; adjust offset in key schedule to keep |disp| < 128\r
-%define fk_ref(x,y) [kptr-16*x+fofs+4*y]\r
-%ifdef AES_REV_DKS\r
-%define rofs 128\r
-%define ik_ref(x,y) [kptr-16*x+rofs+4*y]\r
-%else\r
-%define rofs -128\r
-%define ik_ref(x,y) [kptr+16*x+rofs+4*y]\r
-%endif\r
-\r
-%define tab_0(x) [tptr+8*x]\r
-%define tab_1(x) [tptr+8*x+3]\r
-%define tab_2(x) [tptr+8*x+2]\r
-%define tab_3(x) [tptr+8*x+1]\r
-%define tab_f(x) byte [tptr+8*x+1]\r
-%define tab_i(x) byte [tptr+8*x+7]\r
-%define t_ref(x,r) tab_ %+ x(r)\r
-\r
-%macro ff_rnd 5 ; normal forward round\r
- mov %1d, fk_ref(%5,0)\r
- mov %2d, fk_ref(%5,1)\r
- mov %3d, fk_ref(%5,2)\r
- mov %4d, fk_ref(%5,3)\r
-\r
- movzx esi, al\r
- movzx edi, ah\r
- shr eax, 16\r
- xor %1d, t_ref(0,rsi)\r
- xor %4d, t_ref(1,rdi)\r
- movzx esi, al\r
- movzx edi, ah\r
- xor %3d, t_ref(2,rsi)\r
- xor %2d, t_ref(3,rdi)\r
-\r
- movzx esi, bl\r
- movzx edi, bh\r
- shr ebx, 16\r
- xor %2d, t_ref(0,rsi)\r
- xor %1d, t_ref(1,rdi)\r
- movzx esi, bl\r
- movzx edi, bh\r
- xor %4d, t_ref(2,rsi)\r
- xor %3d, t_ref(3,rdi)\r
-\r
- movzx esi, cl\r
- movzx edi, ch\r
- shr ecx, 16\r
- xor %3d, t_ref(0,rsi)\r
- xor %2d, t_ref(1,rdi)\r
- movzx esi, cl\r
- movzx edi, ch\r
- xor %1d, t_ref(2,rsi)\r
- xor %4d, t_ref(3,rdi)\r
-\r
- movzx esi, dl\r
- movzx edi, dh\r
- shr edx, 16\r
- xor %4d, t_ref(0,rsi)\r
- xor %3d, t_ref(1,rdi)\r
- movzx esi, dl\r
- movzx edi, dh\r
- xor %2d, t_ref(2,rsi)\r
- xor %1d, t_ref(3,rdi)\r
-\r
- mov eax,%1d\r
- mov ebx,%2d\r
- mov ecx,%3d\r
- mov edx,%4d\r
-%endmacro\r
-\r
-%ifdef LAST_ROUND_TABLES\r
-\r
-%macro fl_rnd 5 ; last forward round\r
- add tptr, 2048\r
- mov %1d, fk_ref(%5,0)\r
- mov %2d, fk_ref(%5,1)\r
- mov %3d, fk_ref(%5,2)\r
- mov %4d, fk_ref(%5,3)\r
-\r
- movzx esi, al\r
- movzx edi, ah\r
- shr eax, 16\r
- xor %1d, t_ref(0,rsi)\r
- xor %4d, t_ref(1,rdi)\r
- movzx esi, al\r
- movzx edi, ah\r
- xor %3d, t_ref(2,rsi)\r
- xor %2d, t_ref(3,rdi)\r
-\r
- movzx esi, bl\r
- movzx edi, bh\r
- shr ebx, 16\r
- xor %2d, t_ref(0,rsi)\r
- xor %1d, t_ref(1,rdi)\r
- movzx esi, bl\r
- movzx edi, bh\r
- xor %4d, t_ref(2,rsi)\r
- xor %3d, t_ref(3,rdi)\r
-\r
- movzx esi, cl\r
- movzx edi, ch\r
- shr ecx, 16\r
- xor %3d, t_ref(0,rsi)\r
- xor %2d, t_ref(1,rdi)\r
- movzx esi, cl\r
- movzx edi, ch\r
- xor %1d, t_ref(2,rsi)\r
- xor %4d, t_ref(3,rdi)\r
-\r
- movzx esi, dl\r
- movzx edi, dh\r
- shr edx, 16\r
- xor %4d, t_ref(0,rsi)\r
- xor %3d, t_ref(1,rdi)\r
- movzx esi, dl\r
- movzx edi, dh\r
- xor %2d, t_ref(2,rsi)\r
- xor %1d, t_ref(3,rdi)\r
-%endmacro\r
-\r
-%else\r
-\r
-%macro fl_rnd 5 ; last forward round\r
- mov %1d, fk_ref(%5,0)\r
- mov %2d, fk_ref(%5,1)\r
- mov %3d, fk_ref(%5,2)\r
- mov %4d, fk_ref(%5,3)\r
-\r
- movzx esi, al\r
- movzx edi, ah\r
- shr eax, 16\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- xor %1d, esi\r
- rol edi, 8\r
- xor %4d, edi\r
- movzx esi, al\r
- movzx edi, ah\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %3d, esi\r
- xor %2d, edi\r
-\r
- movzx esi, bl\r
- movzx edi, bh\r
- shr ebx, 16\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- xor %2d, esi\r
- rol edi, 8\r
- xor %1d, edi\r
- movzx esi, bl\r
- movzx edi, bh\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %4d, esi\r
- xor %3d, edi\r
-\r
- movzx esi, cl\r
- movzx edi, ch\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- shr ecx, 16\r
- xor %3d, esi\r
- rol edi, 8\r
- xor %2d, edi\r
- movzx esi, cl\r
- movzx edi, ch\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %1d, esi\r
- xor %4d, edi\r
-\r
- movzx esi, dl\r
- movzx edi, dh\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- shr edx, 16\r
- xor %4d, esi\r
- rol edi, 8\r
- xor %3d, edi\r
- movzx esi, dl\r
- movzx edi, dh\r
- movzx esi, t_ref(f,rsi)\r
- movzx edi, t_ref(f,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %2d, esi\r
- xor %1d, edi\r
-%endmacro\r
-\r
-%endif\r
-\r
-%macro ii_rnd 5 ; normal inverse round\r
- mov %1d, ik_ref(%5,0)\r
- mov %2d, ik_ref(%5,1)\r
- mov %3d, ik_ref(%5,2)\r
- mov %4d, ik_ref(%5,3)\r
-\r
- movzx esi, al\r
- movzx edi, ah\r
- shr eax, 16\r
- xor %1d, t_ref(0,rsi)\r
- xor %2d, t_ref(1,rdi)\r
- movzx esi, al\r
- movzx edi, ah\r
- xor %3d, t_ref(2,rsi)\r
- xor %4d, t_ref(3,rdi)\r
-\r
- movzx esi, bl\r
- movzx edi, bh\r
- shr ebx, 16\r
- xor %2d, t_ref(0,rsi)\r
- xor %3d, t_ref(1,rdi)\r
- movzx esi, bl\r
- movzx edi, bh\r
- xor %4d, t_ref(2,rsi)\r
- xor %1d, t_ref(3,rdi)\r
-\r
- movzx esi, cl\r
- movzx edi, ch\r
- shr ecx, 16\r
- xor %3d, t_ref(0,rsi)\r
- xor %4d, t_ref(1,rdi)\r
- movzx esi, cl\r
- movzx edi, ch\r
- xor %1d, t_ref(2,rsi)\r
- xor %2d, t_ref(3,rdi)\r
-\r
- movzx esi, dl\r
- movzx edi, dh\r
- shr edx, 16\r
- xor %4d, t_ref(0,rsi)\r
- xor %1d, t_ref(1,rdi)\r
- movzx esi, dl\r
- movzx edi, dh\r
- xor %2d, t_ref(2,rsi)\r
- xor %3d, t_ref(3,rdi)\r
-\r
- mov eax,%1d\r
- mov ebx,%2d\r
- mov ecx,%3d\r
- mov edx,%4d\r
-%endmacro\r
-\r
-%ifdef LAST_ROUND_TABLES\r
-\r
-%macro il_rnd 5 ; last inverse round\r
- add tptr, 2048\r
- mov %1d, ik_ref(%5,0)\r
- mov %2d, ik_ref(%5,1)\r
- mov %3d, ik_ref(%5,2)\r
- mov %4d, ik_ref(%5,3)\r
-\r
- movzx esi, al\r
- movzx edi, ah\r
- shr eax, 16\r
- xor %1d, t_ref(0,rsi)\r
- xor %2d, t_ref(1,rdi)\r
- movzx esi, al\r
- movzx edi, ah\r
- xor %3d, t_ref(2,rsi)\r
- xor %4d, t_ref(3,rdi)\r
-\r
- movzx esi, bl\r
- movzx edi, bh\r
- shr ebx, 16\r
- xor %2d, t_ref(0,rsi)\r
- xor %3d, t_ref(1,rdi)\r
- movzx esi, bl\r
- movzx edi, bh\r
- xor %4d, t_ref(2,rsi)\r
- xor %1d, t_ref(3,rdi)\r
-\r
- movzx esi, cl\r
- movzx edi, ch\r
- shr ecx, 16\r
- xor %3d, t_ref(0,rsi)\r
- xor %4d, t_ref(1,rdi)\r
- movzx esi, cl\r
- movzx edi, ch\r
- xor %1d, t_ref(2,rsi)\r
- xor %2d, t_ref(3,rdi)\r
-\r
- movzx esi, dl\r
- movzx edi, dh\r
- shr edx, 16\r
- xor %4d, t_ref(0,rsi)\r
- xor %1d, t_ref(1,rdi)\r
- movzx esi, dl\r
- movzx edi, dh\r
- xor %2d, t_ref(2,rsi)\r
- xor %3d, t_ref(3,rdi)\r
-%endmacro\r
-\r
-%else\r
-\r
-%macro il_rnd 5 ; last inverse round\r
- mov %1d, ik_ref(%5,0)\r
- mov %2d, ik_ref(%5,1)\r
- mov %3d, ik_ref(%5,2)\r
- mov %4d, ik_ref(%5,3)\r
-\r
- movzx esi, al\r
- movzx edi, ah\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- shr eax, 16\r
- xor %1d, esi\r
- rol edi, 8\r
- xor %2d, edi\r
- movzx esi, al\r
- movzx edi, ah\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %3d, esi\r
- xor %4d, edi\r
-\r
- movzx esi, bl\r
- movzx edi, bh\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- shr ebx, 16\r
- xor %2d, esi\r
- rol edi, 8\r
- xor %3d, edi\r
- movzx esi, bl\r
- movzx edi, bh\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %4d, esi\r
- xor %1d, edi\r
-\r
- movzx esi, cl\r
- movzx edi, ch\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- shr ecx, 16\r
- xor %3d, esi\r
- rol edi, 8\r
- xor %4d, edi\r
- movzx esi, cl\r
- movzx edi, ch\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %1d, esi\r
- xor %2d, edi\r
-\r
- movzx esi, dl\r
- movzx edi, dh\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- shr edx, 16\r
- xor %4d, esi\r
- rol edi, 8\r
- xor %1d, edi\r
- movzx esi, dl\r
- movzx edi, dh\r
- movzx esi, t_ref(i,rsi)\r
- movzx edi, t_ref(i,rdi)\r
- rol esi, 16\r
- rol edi, 24\r
- xor %2d, esi\r
- xor %3d, edi\r
-%endmacro\r
-\r
-%endif\r
-\r
-%ifdef ENCRYPTION\r
-\r
- global aes_encrypt\r
-%ifdef DLL_EXPORT\r
- export aes_encrypt\r
-%endif\r
-\r
- section .data align=64\r
- align 64\r
-enc_tab:\r
- enc_vals u8\r
-%ifdef LAST_ROUND_TABLES\r
- enc_vals w8\r
-%endif\r
-\r
- section .text align=16\r
- align 16\r
-aes_encrypt:\r
-\r
-%ifdef __GNUC__\r
- sub rsp, 4*8 ; gnu/linux binary interface\r
- mov [rsp+0*8], rsi ; output pointer\r
- mov r8, rdx ; context\r
-%else\r
- sub rsp, 6*8 ; windows binary interface\r
- mov [rsp+4*8], rsi\r
- mov [rsp+5*8], rdi\r
- mov [rsp+0*8], rdx ; output pointer\r
- mov rdi, rcx ; input pointer\r
-%endif\r
- mov [rsp+1*8], rbx ; input pointer in rdi\r
- mov [rsp+2*8], rbp ; output pointer in [rsp]\r
- mov [rsp+3*8], r12 ; context in r8\r
-\r
- movzx esi, byte [kptr+4*KS_LENGTH]\r
- lea tptr,[enc_tab wrt rip]\r
- sub kptr, fofs\r
-\r
- mov eax, [rdi+0*4]\r
- mov ebx, [rdi+1*4]\r
- mov ecx, [rdi+2*4]\r
- mov edx, [rdi+3*4]\r
-\r
- xor eax, [kptr+fofs]\r
- xor ebx, [kptr+fofs+4]\r
- xor ecx, [kptr+fofs+8]\r
- xor edx, [kptr+fofs+12]\r
-\r
- lea kptr,[kptr+rsi]\r
- cmp esi, 10*16\r
- je .3\r
- cmp esi, 12*16\r
- je .2\r
- cmp esi, 14*16\r
- je .1\r
- mov rax, -1\r
- jmp .4\r
-\r
-.1: ff_rnd r9, r10, r11, r12, 13\r
- ff_rnd r9, r10, r11, r12, 12\r
-.2: ff_rnd r9, r10, r11, r12, 11\r
- ff_rnd r9, r10, r11, r12, 10\r
-.3: ff_rnd r9, r10, r11, r12, 9\r
- ff_rnd r9, r10, r11, r12, 8\r
- ff_rnd r9, r10, r11, r12, 7\r
- ff_rnd r9, r10, r11, r12, 6\r
- ff_rnd r9, r10, r11, r12, 5\r
- ff_rnd r9, r10, r11, r12, 4\r
- ff_rnd r9, r10, r11, r12, 3\r
- ff_rnd r9, r10, r11, r12, 2\r
- ff_rnd r9, r10, r11, r12, 1\r
- fl_rnd r9, r10, r11, r12, 0\r
-\r
- mov rbx, [rsp]\r
- mov [rbx], r9d\r
- mov [rbx+4], r10d\r
- mov [rbx+8], r11d\r
- mov [rbx+12], r12d\r
- xor rax, rax\r
-.4:\r
- mov rbx, [rsp+1*8]\r
- mov rbp, [rsp+2*8]\r
- mov r12, [rsp+3*8]\r
-%ifdef __GNUC__\r
- add rsp, 4*8\r
-%else\r
- mov rsi, [rsp+4*8]\r
- mov rdi, [rsp+5*8]\r
- add rsp, 6*8\r
-%endif\r
- ret\r
-\r
-%endif\r
-\r
-%ifdef DECRYPTION\r
-\r
- global aes_decrypt\r
-%ifdef DLL_EXPORT\r
- export aes_decrypt\r
-%endif\r
-\r
- section .data align=64\r
- align 64\r
-dec_tab:\r
- dec_vals v8\r
-%ifdef LAST_ROUND_TABLES\r
- dec_vals w8\r
-%endif\r
-\r
- section .text align=16\r
- align 16\r
-aes_decrypt:\r
-\r
-%ifdef __GNUC__\r
- sub rsp, 4*8 ; gnu/linux binary interface\r
- mov [rsp+0*8], rsi ; output pointer\r
- mov r8, rdx ; context\r
-%else\r
- sub rsp, 6*8 ; windows binary interface\r
- mov [rsp+4*8], rsi\r
- mov [rsp+5*8], rdi\r
- mov [rsp+0*8], rdx ; output pointer\r
- mov rdi, rcx ; input pointer\r
-%endif\r
- mov [rsp+1*8], rbx ; input pointer in rdi\r
- mov [rsp+2*8], rbp ; output pointer in [rsp]\r
- mov [rsp+3*8], r12 ; context in r8\r
-\r
- movzx esi,byte[kptr+4*KS_LENGTH]\r
- lea tptr,[dec_tab wrt rip]\r
- sub kptr, rofs\r
-\r
- mov eax, [rdi+0*4]\r
- mov ebx, [rdi+1*4]\r
- mov ecx, [rdi+2*4]\r
- mov edx, [rdi+3*4]\r
-\r
-%ifdef AES_REV_DKS\r
- mov rdi, kptr\r
- lea kptr,[kptr+rsi]\r
-%else\r
- lea rdi,[kptr+rsi]\r
-%endif\r
-\r
- xor eax, [rdi+rofs]\r
- xor ebx, [rdi+rofs+4]\r
- xor ecx, [rdi+rofs+8]\r
- xor edx, [rdi+rofs+12]\r
-\r
- cmp esi, 10*16\r
- je .3\r
- cmp esi, 12*16\r
- je .2\r
- cmp esi, 14*16\r
- je .1\r
- mov rax, -1\r
- jmp .4\r
-\r
-.1: ii_rnd r9, r10, r11, r12, 13\r
- ii_rnd r9, r10, r11, r12, 12\r
-.2: ii_rnd r9, r10, r11, r12, 11\r
- ii_rnd r9, r10, r11, r12, 10\r
-.3: ii_rnd r9, r10, r11, r12, 9\r
- ii_rnd r9, r10, r11, r12, 8\r
- ii_rnd r9, r10, r11, r12, 7\r
- ii_rnd r9, r10, r11, r12, 6\r
- ii_rnd r9, r10, r11, r12, 5\r
- ii_rnd r9, r10, r11, r12, 4\r
- ii_rnd r9, r10, r11, r12, 3\r
- ii_rnd r9, r10, r11, r12, 2\r
- ii_rnd r9, r10, r11, r12, 1\r
- il_rnd r9, r10, r11, r12, 0\r
-\r
- mov rbx, [rsp]\r
- mov [rbx], r9d\r
- mov [rbx+4], r10d\r
- mov [rbx+8], r11d\r
- mov [rbx+12], r12d\r
- xor rax, rax\r
-.4: mov rbx, [rsp+1*8]\r
- mov rbp, [rsp+2*8]\r
- mov r12, [rsp+3*8]\r
-%ifdef __GNUC__\r
- add rsp, 4*8\r
-%else\r
- mov rsi, [rsp+4*8]\r
- mov rdi, [rsp+5*8]\r
- add rsp, 6*8\r
-%endif\r
- ret\r
-\r
-%endif\r
-\r
- end\r
*
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "blowfish_internal.h"
#include "blowfish.h"
-/*
+/*
* SILC Crypto API for Blowfish
*/
/* Sets the key for the cipher. */
-SILC_CIPHER_API_SET_KEY(blowfish_cbc)
+SILC_CIPHER_API_SET_KEY(blowfish)
{
blowfish_set_key((BlowfishContext *)context, (unsigned char *)key, keylen);
return TRUE;
}
-/* Sets IV for the cipher. */
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
-SILC_CIPHER_API_SET_IV(blowfish_cbc)
+SILC_CIPHER_API_SET_KEY_WITH_STRING(blowfish)
{
-
+ return 1;
}
/* Returns the size of the cipher context. */
-SILC_CIPHER_API_CONTEXT_LEN(blowfish_cbc)
+SILC_CIPHER_API_CONTEXT_LEN(blowfish)
{
return sizeof(BlowfishContext);
}
/* Encrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_ENCRYPT(blowfish_cbc)
+SILC_CIPHER_API_ENCRYPT_CBC(blowfish)
{
SilcUInt32 tiv[4];
int i;
/* Decrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_DECRYPT(blowfish_cbc)
+SILC_CIPHER_API_DECRYPT_CBC(blowfish)
{
SilcUInt32 tmp[4], tmp2[4], tiv[4];
int i;
blowfish_decrypt((BlowfishContext *)context, tmp, tmp2, 16);
SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
}
-
+
SILC_CBC_PUT_IV(tiv, iv);
-
+
return TRUE;
}
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
};
-/*
+/*
* Round loop unrolling macros, S is a pointer to a S-Box array
* organized in 4 SilcUInt32s at a row.
*/
/*
* The blowfish encipher, processes 64-bit blocks.
- * NOTE: This function MUSTN'T respect endianess
+ * NOTE: This function MUSTN'T respect endianess
*/
int blowfish_encrypt(BlowfishContext *ctx,
for (i = 0; i < 16 + 2; i += 2)
{
blowfish_encrypt(ctx, data, data, 8);
-
+
P[i] = data[0];
P[i + 1] = data[1];
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 Pekka Riikonen
+ Copyright (C) 1997 - 2000 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
#ifndef BLOWFISH_H
#define BLOWFISH_H
-/*
+/*
* SILC Crypto API for Blowfish
*/
-SILC_CIPHER_API_SET_KEY(blowfish_cbc);
-SILC_CIPHER_API_SET_IV(blowfish_cbc);
-SILC_CIPHER_API_CONTEXT_LEN(blowfish_cbc);
-SILC_CIPHER_API_ENCRYPT(blowfish_cbc);
-SILC_CIPHER_API_DECRYPT(blowfish_cbc);
+SILC_CIPHER_API_SET_KEY(blowfish);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(blowfish);
+SILC_CIPHER_API_CONTEXT_LEN(blowfish);
+SILC_CIPHER_API_ENCRYPT_CBC(blowfish);
+SILC_CIPHER_API_DECRYPT_CBC(blowfish);
#endif
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "cast_internal.h"
#include "cast.h"
#define io_swap
-
-/*
+
+/*
* SILC Crypto API for Cast-256
*/
/* Sets the key for the cipher. */
-SILC_CIPHER_API_SET_KEY(cast_cbc)
+SILC_CIPHER_API_SET_KEY(cast)
{
SilcUInt32 k[8];
return TRUE;
}
-/* Sets IV for the cipher. */
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
-SILC_CIPHER_API_SET_IV(cast_cbc)
+SILC_CIPHER_API_SET_KEY_WITH_STRING(cast)
{
-
+ return 1;
}
/* Returns the size of the cipher context. */
-SILC_CIPHER_API_CONTEXT_LEN(cast_cbc)
+SILC_CIPHER_API_CONTEXT_LEN(cast)
{
return sizeof(CastContext);
}
/* Encrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_ENCRYPT(cast_cbc)
+SILC_CIPHER_API_ENCRYPT_CBC(cast)
{
SilcUInt32 tiv[4];
int i;
- SILC_ASSERT((len & (16 - 1)) == 0);
- if (len & (16 - 1))
- return FALSE;
-
SILC_CBC_GET_IV(tiv, iv);
SILC_CBC_ENC_PRE(tiv, src);
/* Decrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_DECRYPT(cast_cbc)
+SILC_CIPHER_API_DECRYPT_CBC(cast)
{
SilcUInt32 tmp[4], tmp2[4], tiv[4];
int i;
- if (len & (16 - 1))
- return FALSE;
-
SILC_CBC_GET_IV(tiv, iv);
SILC_CBC_DEC_PRE(tmp, src);
for (i = 16; i < len; i += 16) {
SILC_CBC_DEC_PRE(tmp, src);
- cast_decrypt((CastContext *)context, tmp, tmp2);
+ cast_decrypt((CastContext *)context, tmp, tmp2);
SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
}
-
+
SILC_CBC_PUT_IV(tiv, iv);
-
+
return TRUE;
}
-u4byte s_box[4][256] =
+u4byte s_box[4][256] =
{ {
- 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9C004dd3,
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9C004dd3,
0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675,
- 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059,
+ 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059,
0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
- 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b,
- 0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de,
- 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b,
+ 0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de,
+ 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159,
0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f,
0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,
- 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0C50, 0x882240f2, 0x0c6e4f38,
+ 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0C50, 0x882240f2, 0x0c6e4f38,
0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
- 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493,
- 0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a,
- 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493,
+ 0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a,
+ 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb,
0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
- 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14,
0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6,
0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6C2, 0x81383f05, 0x6963c5c8,
0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
- 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495,
0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e,
- 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426,
- 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
- 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98,
+ 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426,
+ 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98,
0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f,
- 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, 0x7b5a41f0, 0xd37cfbad,
- 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
- 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464,
+ 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, 0x7b5a41f0, 0xd37cfbad,
+ 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464,
0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,
- 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f, 0x6188b153,
- 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
- 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274,
+ 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f, 0x6188b153,
+ 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274,
0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755,
- 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1,
+ 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1,
0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
- 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1,
0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79,
- 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814C, 0x474d6ad7, 0x7c0c5e5c,
+ 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814C, 0x474d6ad7, 0x7c0c5e5c,
0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
- 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff,
- 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff,
+ 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d,
0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
},
{
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a,
- 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba,
- 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605,
+ 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba,
+ 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605,
0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
- 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b,
- 0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4,
- 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b,
+ 0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4,
+ 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083,
0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
- 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f,
- 0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d,
- 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f,
+ 0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d,
+ 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e,
0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
- 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366,
- 0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4,
- 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366,
+ 0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4,
+ 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064,
0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
- 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6,
- 0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709,
- 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6,
+ 0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709,
+ 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364,
0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
- 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b,
- 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9,
- 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b,
+ 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9,
+ 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c,
0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
- 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741,
- 0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab,
- 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741,
+ 0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab,
+ 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b,
0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
- 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa,
- 0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8,
- 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa,
+ 0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8,
+ 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028,
0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6,
- 0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b,
- 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1,
+ 0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b,
+ 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1,
0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
- 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb,
- 0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea,
- 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb,
+ 0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea,
+ 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d,
0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
- 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e,
- 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e,
+ 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef,
0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
},
{
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b,
- 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae,
+ 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae,
0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9,
0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd,
0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e,
0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264,
0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
- 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e,
- 0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f,
- 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e,
+ 0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f,
+ 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e,
0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
- 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790,
- 0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504,
- 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790,
+ 0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504,
+ 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e,
0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
- 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8,
- 0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d,
- 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8,
+ 0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d,
+ 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240,
0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
- 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c,
0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15,
- 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788,
+ 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788,
0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
- 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa,
- 0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392,
- 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa,
+ 0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392,
+ 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f,
0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
- 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae,
- 0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67,
- 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae,
+ 0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67,
+ 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9,
0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
- 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888,
- 0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d,
- 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888,
+ 0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d,
+ 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2,
0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
- 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2,
- 0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce,
- 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2,
+ 0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce,
+ 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d,
0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
- 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00,
- 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00,
+ 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5,
0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
},
- {
- 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57,
- 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120,
- 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd,
+ {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57,
+ 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120,
+ 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd,
0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
- 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe,
- 0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701,
- 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe,
+ 0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701,
+ 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801,
0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
- 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1,
0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,
- 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3,
+ 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3,
0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c,
0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c,
- 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16,
+ 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16,
0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7,
- 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327,
- 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002,
+ 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327,
+ 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002,
0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
- 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7,
- 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031,
- 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7,
+ 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031,
+ 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff,
0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
- 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035,
- 0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69,
- 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035,
+ 0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69,
+ 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec,
0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
- 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e,
- 0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e,
+ 0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3,
0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6,
0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
- 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f,
- 0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091,
- 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f,
+ 0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091,
+ 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6,
0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2,
- 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367,
+ 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367,
0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda,
0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6,
u4byte *cast_set_key(CastContext *ctx,
const u4byte in_key[], const u4byte key_len)
-{
+{
u4byte i, j, t, u, cm, cr, lk[8], tm[8], tr[8];
u4byte *l_key = ctx->l_key;
}
k_rnd(lk, tr, tm);
-
+
for(j = 0; j < 8; ++j)
{
tm[j] = cm; cm += 0x6ed9eba1;
void cast_encrypt(CastContext *ctx,
const u4byte in_blk[4], u4byte out_blk[])
-{
+{
u4byte t, u, blk[4];
u4byte *l_key = ctx->l_key;
void cast_decrypt(CastContext *ctx,
const u4byte in_blk[4], u4byte out_blk[4])
-{
+{
u4byte t, u, blk[4];
u4byte *l_key = ctx->l_key;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2000, 2006, 2007 Pekka Riikonen
+ Copyright (C) 1999 - 2000 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
#ifndef CAST_H
#define CAST_H
-/*
+/*
* SILC Crypto API for Cast-256
*/
-SILC_CIPHER_API_SET_KEY(cast_cbc);
-SILC_CIPHER_API_SET_IV(cast_cbc);
-SILC_CIPHER_API_CONTEXT_LEN(cast_cbc);
-SILC_CIPHER_API_ENCRYPT(cast_cbc);
-SILC_CIPHER_API_DECRYPT(cast_cbc);
+SILC_CIPHER_API_SET_KEY(cast);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(cast);
+SILC_CIPHER_API_CONTEXT_LEN(cast);
+SILC_CIPHER_API_ENCRYPT_CBC(cast);
+SILC_CIPHER_API_DECRYPT_CBC(cast);
#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2006 Pekka Riikonen
+ Copyright (C) 1999 - 2000 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
typedef unsigned char u1byte;
typedef SilcUInt32 u4byte;
typedef SilcUInt32 u32;
-typedef SilcUInt32 uint_32t;
-typedef SilcUInt8 uint_8t;
#define rotr(x, nr) (((x) >> ((int)(nr))) | ((x) << (32 - (int)(nr))))
#define rotl(x, nr) (((x) << ((int)(nr))) | ((x) >> (32 - (int)(nr))))
+++ /dev/null
-#ifdef SILC_DIST_CRYPTO
-#
-# lib/silccrypt/configure.ad
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2006 - 2007 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.
-#
-
-if test x$compile_libs = xtrue; then
-
-AC_MSG_NOTICE([configuring crypto library])
-SILC_CRYPTO_CFLAGS=
-
-aes_asm=false
-case "$host_cpu" in
- i?86)
- # Don't enable ASM AES with shared libs as the code doesn't support PIC.
- if test x$have_assembler = xtrue -a "$enable_shared" != "yes"; then
- aes_asm=true
- AC_DEFINE([SILC_AES_ASM], [], [SILC_AES_ASM])
- fi
- ;;
- x86_64)
- if test x$have_assembler = xtrue -a "$enable_shared" != "yes"; then
- aes_asm=true
- AC_DEFINE([SILC_AES_ASM], [], [SILC_AES_ASM])
- fi
- ;;
- default)
- aes_asm=false
- ;;
-esac
-
-SILC_ADD_CC_FLAGS(SILC_CRYPTO, -fno-regmove)
-if test x$summary_debug = xno; then
- SILC_ADD_CC_FLAGS(SILC_CRYPTO, -fomit-frame-pointer -O3)
-fi
-
-AC_SUBST(SILC_CRYPTO_CFLAGS)
-
-AC_CONFIG_FILES(
-lib/silccrypt/Makefile
-#ifdef SILC_DIST_INPLACE
-lib/silccrypt/tests/Makefile
-#endif SILC_DIST_INPLACE
-)
-
-fi # compile_libs
-
-# AM_CONDITIONAL is so bad that it itself cannot be defined in conditional
-AM_CONDITIONAL(SILC_AES_ASM, test x$aes_asm = xtrue)
-
-#endif SILC_DIST_CRYPTO
* will fill a supplied 16-byte array with the digest.
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "md5_internal.h"
#include "md5.h"
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2000 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
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "none.h"
-/*
+/*
* SILC Crypto API for None cipher (ie. no cipher) :)
*/
return TRUE;
}
-SILC_CIPHER_API_SET_IV(none)
+SILC_CIPHER_API_SET_KEY_WITH_STRING(none)
{
-
+ return TRUE;
}
SILC_CIPHER_API_CONTEXT_LEN(none)
return 1;
}
-SILC_CIPHER_API_ENCRYPT(none)
+SILC_CIPHER_API_ENCRYPT_CBC(none)
{
- memmove(dst, src, len);
+ memcpy(dst, src, len);
return TRUE;
}
-SILC_CIPHER_API_DECRYPT(none)
+SILC_CIPHER_API_DECRYPT_CBC(none)
{
- memmove(dst, src, len);
+ memcpy(dst, src, len);
return TRUE;
}
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$
+ * $Log$
+ * Revision 1.1.1.1.4.1 2005/04/30 15:31:26 priikone
+ * Header changes.
+ *
+ * Revision 1.1.1.1 2000/06/27 11:36:54 priikone
+ * Importet from internal CVS/Added Log headers.
+ *
+ *
+ */
#ifndef NONE_H
#define NONE_H
-/*
+/*
* SILC Crypto API for None cipher (ie. no cipher) :)
*/
SILC_CIPHER_API_SET_KEY(none);
-SILC_CIPHER_API_SET_IV(none);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(none);
SILC_CIPHER_API_CONTEXT_LEN(none);
-SILC_CIPHER_API_ENCRYPT(none);
-SILC_CIPHER_API_DECRYPT(none);
+SILC_CIPHER_API_ENCRYPT_CBC(none);
+SILC_CIPHER_API_DECRYPT_CBC(none);
#endif
*/
/*
- * Based on RC5 reference code and on description of Bruce Schneier's
+ * Based on RC5 reference code and on description of Bruce Schneier's
* Applied Cryptography.
*
- * This implementation has a word size of 32 bits, a rounds of 16 and
+ * This implementation has a word size of 32 bits, a rounds of 16 and
* variable key length from 128 and 192 up to 256 bits.
*
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "rc5_internal.h"
#include "rc5.h"
-/*
+/*
* SILC Crypto API for RC5
*/
/* Sets the key for the cipher. */
-SILC_CIPHER_API_SET_KEY(rc5_cbc)
+SILC_CIPHER_API_SET_KEY(rc5)
{
SilcUInt32 k[8];
return TRUE;
}
-/* Sets IV for the cipher. */
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
-SILC_CIPHER_API_SET_IV(rc5_cbc)
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc5)
{
-
+ return 1;
}
/* Returns the size of the cipher context. */
-SILC_CIPHER_API_CONTEXT_LEN(rc5_cbc)
+SILC_CIPHER_API_CONTEXT_LEN(rc5)
{
return sizeof(RC5Context);
}
/* Encrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_ENCRYPT(rc5_cbc)
+SILC_CIPHER_API_ENCRYPT_CBC(rc5)
{
SilcUInt32 tiv[4];
int i;
/* Decrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_DECRYPT(rc5_cbc)
+SILC_CIPHER_API_DECRYPT_CBC(rc5)
{
SilcUInt32 tmp[4], tmp2[4], tiv[4];
int i;
for (i = 16; i < len; i += 16) {
SILC_CBC_DEC_PRE(tmp, src);
- rc5_decrypt((RC5Context *)context, tmp, tmp2);
+ rc5_decrypt((RC5Context *)context, tmp, tmp2);
SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
}
-
+
SILC_CBC_PUT_IV(tiv, iv);
-
+
return TRUE;
}
A = in[0];
B = in[1];
- RC5D(32, A, B); RC5D(30, A, B);
- RC5D(28, A, B); RC5D(26, A, B);
- RC5D(24, A, B); RC5D(22, A, B);
+ RC5D(32, A, B); RC5D(30, A, B);
+ RC5D(28, A, B); RC5D(26, A, B);
+ RC5D(24, A, B); RC5D(22, A, B);
RC5D(20, A, B); RC5D(18, A, B);
RC5D(16, A, B); RC5D(14, A, B);
RC5D(12, A, B); RC5D(10, A, B);
out[1] = B - S[1];
return 0;
-}
+}
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
#ifndef RC5_H
#define RC5_H
-/*
+/*
* SILC Crypto API for RC5
*/
-SILC_CIPHER_API_SET_KEY(rc5_cbc);
-SILC_CIPHER_API_SET_IV(rc5_cbc);
-SILC_CIPHER_API_CONTEXT_LEN(rc5_cbc);
-SILC_CIPHER_API_ENCRYPT(rc5_cbc);
-SILC_CIPHER_API_DECRYPT(rc5_cbc);
+SILC_CIPHER_API_SET_KEY(rc5);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc5);
+SILC_CIPHER_API_CONTEXT_LEN(rc5);
+SILC_CIPHER_API_ENCRYPT_CBC(rc5);
+SILC_CIPHER_API_DECRYPT_CBC(rc5);
#endif
-/* ---------------------------------------------------------------------------
- Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
+/*
- LICENSE TERMS
+ rijndael_internal.h
- The free distribution and use of this software in both source and binary
- form is allowed (with or without changes) provided that:
+ Author: Pekka Riikonen <priikone@silcnet.org>
- 1. distributions of this source code include the above copyright
- notice, this list of conditions and the following disclaimer;
+ Copyright (C) 1997 - 2000 Pekka Riikonen
- 2. distributions in binary form include the above copyright
- notice, this list of conditions and the following disclaimer
- in the documentation and/or other associated materials;
+ 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.
- 3. the copyright holder's name is not used to endorse products
- built using this software without specific written permission.
-
- ALTERNATIVELY, provided that this notice is retained in full, this product
- may be distributed under the terms of the GNU General Public License (GPL),
- in which case the provisions of the GPL apply INSTEAD OF those given above.
-
- DISCLAIMER
-
- This software is provided 'as is' with no explicit or implied warranties
- in respect of its properties, including, but not limited to, correctness
- and/or fitness for purpose.
- ---------------------------------------------------------------------------
- Issue 09/09/2006
*/
#ifndef RIJNDAEL_INTERNAL_H
#include "ciphers_def.h"
-#define KS_LENGTH 60
-
-typedef union {
- uint_32t l;
- uint_8t b[4];
-} aes_inf;
-
-typedef struct {
- uint_32t ks[KS_LENGTH];
- aes_inf inf;
-} aes_encrypt_ctx;
-
-typedef struct {
- uint_32t ks[KS_LENGTH];
- aes_inf inf;
-} aes_decrypt_ctx;
-
+/* Cipher's context */
typedef struct {
- union {
- aes_encrypt_ctx enc;
- aes_decrypt_ctx dec;
- } u;
-} AesContext;
+ u4byte e_key[60];
+ u4byte d_key[60];
+ u4byte k_len;
+} RijndaelContext;
+
+/* Prototypes */
+u4byte *rijndael_set_key(RijndaelContext *ctx,
+ const u4byte in_key[], const u4byte key_len);
+void rijndael_encrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
+void rijndael_decrypt(RijndaelContext *ctx,
+ const u4byte in_blk[4], u4byte out_blk[4]);
-#define AES_RETURN void
-#define AES_REV_DKS /* define to reverse decryption key schedule */
-#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */
-#define N_COLS 4 /* the number of columns in the state */
-#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
-#define WPOLY 0x011b
-#define BPOLY 0x1b
-#define m1 0x80808080
-#define m2 0x7f7f7f7f
-#define gf_mulx(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY))
-#define s(x,c) x[c]
-#define lp32(x) ((uint_32t*)(x))
-
-#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
-#define TABLE_ALIGN 32
-#endif
-
-#if defined( bswap32 )
-#define aes_sw32 bswap32
-#elif defined( bswap_32 )
-#define aes_sw32 bswap_32
-#else
-#define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n)))
-#define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00))
#endif
-
-#ifdef WORDS_BIGENDIAN
-#define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | \
- ((uint_32t)(x) << (32 - 8 * (n))))
-#define ups(x,n) ((uint_32t) (x) >> (8 * (n)))
-#define bval(x,n) ((uint_8t)((x) >> (24 - 8 * (n))))
-#define bytes2word(b0, b1, b2, b3) (((uint_32t)(b0) << 24) | \
- ((uint_32t)(b1) << 16) | \
- ((uint_32t)(b2) << 8) | (b3))
-#else
-#define upr(x,n) (((uint_32t)(x) << (8 * (n))) | \
- ((uint_32t)(x) >> (32 - 8 * (n))))
-#define ups(x,n) ((uint_32t) (x) << (8 * (n)))
-#define bval(x,n) ((uint_8t)((x) >> (8 * (n))))
-#define bytes2word(b0, b1, b2, b3) (((uint_32t)(b3) << 24) | \
- ((uint_32t)(b2) << 16) | \
- ((uint_32t)(b1) << 8) | (b0))
-#endif /* WORDS_BIGENDIAN */
-
-#define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], \
- ((const uint_8t*)(x)+4*c)[1], \
- ((const uint_8t*)(x)+4*c)[2], \
- ((const uint_8t*)(x)+4*c)[3])
-#define word_out(x,c,v) { \
- ((uint_8t*)(x)+4*c)[0] = bval(v,0); \
- ((uint_8t*)(x)+4*c)[1] = bval(v,1); \
- ((uint_8t*)(x)+4*c)[2] = bval(v,2); \
- ((uint_8t*)(x)+4*c)[3] = bval(v,3); \
-}
-
-#define four_tables(x,tab,vf,rf,c) \
- ( tab[0][bval(vf(x,0,c),rf(0,c))] \
- ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
- ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
- ^ tab[3][bval(vf(x,3,c),rf(3,c))])
-
-#define vf1(x,r,c) (x)
-#define rf1(r,c) (r)
-#define rf2(r,c) ((8+r-c)&3)
-
-#define dec_fmvars uint_32t g2
-#define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
-#define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0)
-#define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c)
-
-#define ff(x) inv_mcol(x)
-#if defined( dec_imvars )
-#define d_vars dec_imvars
-#endif
-
-#define sb_data(w) {\
- w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
- w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
- w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
- w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
- w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
- w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
- w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
- w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
- w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
- w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
- w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
- w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
- w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
- w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
- w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
- w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
- w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
- w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
- w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
- w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
- w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
- w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
- w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
- w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
- w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
- w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
- w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
- w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
- w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
- w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
- w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
- w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
-
-#define isb_data(w) {\
- w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
- w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
- w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
- w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
- w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
- w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
- w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
- w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
- w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
- w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
- w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
- w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
- w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
- w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
- w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
- w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
- w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
- w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
- w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
- w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
- w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
- w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
- w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
- w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
- w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
- w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
- w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
- w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
- w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
- w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
- w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
- w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
-
-#define mm_data(w) {\
- w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
- w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
- w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
- w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
- w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
- w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
- w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
- w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
- w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
- w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
- w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
- w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
- w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
- w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
- w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
- w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
- w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
- w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
- w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
- w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
- w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
- w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
- w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
- w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
- w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
- w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
- w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
- w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
- w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
- w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
- w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
- w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
-
-#define rc_data(w) {\
- w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
- w(0x1b), w(0x36) }
-
-#define h0(x) (x)
-
-#define w0(p) bytes2word(p, 0, 0, 0)
-#define w1(p) bytes2word(0, p, 0, 0)
-#define w2(p) bytes2word(0, 0, p, 0)
-#define w3(p) bytes2word(0, 0, 0, p)
-
-#define u0(p) bytes2word(f2(p), p, p, f3(p))
-#define u1(p) bytes2word(f3(p), f2(p), p, p)
-#define u2(p) bytes2word(p, f3(p), f2(p), p)
-#define u3(p) bytes2word(p, p, f3(p), f2(p))
-
-#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
-#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
-#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
-#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
-
-#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
-#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
-#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
- ^ (((x>>5) & 4) * WPOLY))
-#define f3(x) (f2(x) ^ x)
-#define f9(x) (f8(x) ^ x)
-#define fb(x) (f8(x) ^ f2(x) ^ x)
-#define fd(x) (f8(x) ^ f4(x) ^ x)
-#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
-
-#define t_dec(m,n) t_##m##n
-#define t_set(m,n) t_##m##n
-#define t_use(m,n) t_##m##n
-
-#if defined(_MSC_VER) && defined(TABLE_ALIGN)
-#define ALIGN __declspec(align(TABLE_ALIGN))
-#else
-#define ALIGN
-#endif
-
-AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
-AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
-AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
-AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]);
-AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
-AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
-AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
-AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
-AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]);
-AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
-
-#endif /* RIJNGDAEL_INTERNAL */
rsa.c RSA Public and Private key generation functions,
RSA encrypt and decrypt functions.
-
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2007 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
GNU General Public License for more details.
-
+
Created: Sat Mar 1 13:26:45 1997 pekka
-
+
RSA public key cryptographic algorithm used in this distribution is:
-
+
Key generation:
p, q primes
p != q
n = p * q modulus
-
+
Public key exponent:
e relatively prime to (p-1) * (q-1)
Private key exponent:
d = e ^ -1 mod lcm(((p-1) * (q-1)))
-
+
Encryption:
c = m ^ e mod n
Decryption:
m = c ^ d mod n
-
+
Supports CRT (Chinese Remainder Theorem) for private key operations.
-
+
The SSH's (Secure Shell), PGP's (Pretty Good Privacy) and RSAREF
Toolkit were used as reference when coding this implementation. They
all were a big help for me.
-
+
I also suggest reading Bruce Schneier's; Applied Cryptography, Second
Edition, John Wiley & Sons, Inc. 1996. This book deals about RSA and
everything else too about cryptography.
-
+
*/
/* $Id$ */
Fixed double free in public key setting. Use a bit larger e as
starting point in key generation.
+
*/
-#include "silc.h"
+#include "silcincludes.h"
+#include "rsa_internal.h"
#include "rsa.h"
+/*
+ * SILC PKCS API for RSA
+ */
+
+/* Generates RSA key pair. */
+
+SILC_PKCS_API_INIT(rsa)
+{
+ SilcUInt32 prime_bits = keylen / 2;
+ SilcMPInt p, q;
+ bool found = FALSE;
+
+ if (keylen < 768 || keylen > 16384)
+ return FALSE;
+
+ printf("Generating RSA Public and Private keys, might take a while...\n");
+
+ silc_mp_init(&p);
+ silc_mp_init(&q);
+
+ /* Find p and q */
+ while (!found) {
+ printf("Finding p: ");
+ silc_math_gen_prime(&p, prime_bits, TRUE, rng);
+
+ printf("\nFinding q: ");
+ silc_math_gen_prime(&q, prime_bits, TRUE, rng);
+
+ if ((silc_mp_cmp(&p, &q)) == 0)
+ printf("\nFound equal primes, not good, retrying...\n");
+ else
+ found = TRUE;
+ }
+
+ /* If p is smaller than q, switch them */
+ if ((silc_mp_cmp(&p, &q)) > 0) {
+ SilcMPInt hlp;
+ silc_mp_init(&hlp);
+
+ silc_mp_set(&hlp, &p);
+ silc_mp_set(&p, &q);
+ silc_mp_set(&q, &hlp);
+
+ silc_mp_uninit(&hlp);
+ }
+
+ /* Generate the actual keys */
+ rsa_generate_keys((RsaKey *)context, keylen, &p, &q);
+
+ silc_mp_uninit(&p);
+ silc_mp_uninit(&q);
+
+ printf("\nKeys generated successfully.\n");
+
+ return TRUE;
+}
+
+SILC_PKCS_API_CLEAR_KEYS(rsa)
+{
+ rsa_clear_keys((RsaKey *)context);
+}
+
+/* Returns SILC style encoded RSA public key. */
+
+SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ unsigned char *e, *n, *ret;
+ SilcUInt32 e_len, n_len;
+ unsigned char tmp[4];
+
+ e = silc_mp_mp2bin(&key->e, 0, &e_len);
+ n = silc_mp_mp2bin(&key->n, (key->bits + 7) / 8, &n_len);
+
+ *ret_len = e_len + 4 + n_len + 4;
+ ret = silc_calloc(*ret_len, sizeof(unsigned char));
+
+ /* Put the length of the e. */
+ SILC_PUT32_MSB(e_len, tmp);
+ memcpy(ret, tmp, 4);
+
+ /* Put the e. */
+ memcpy(ret + 4, e, e_len);
+
+ /* Put the length of the n. */
+ SILC_PUT32_MSB(n_len, tmp);
+ memcpy(ret + 4 + e_len, tmp, 4);
+
+ /* Put the n. */
+ memcpy(ret + 4 + e_len + 4, n, n_len);
+
+ memset(e, 0, e_len);
+ memset(n, 0, n_len);
+ silc_free(e);
+ silc_free(n);
+
+ return ret;
+}
+
+/* Returns SILC style encoded RSA private key. Public key is always
+ returned in private key as well. Public keys are often derived
+ directly from private key. */
+
+SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ SilcBuffer buf;
+ unsigned char *e, *n, *d, *ret, *dp = NULL, *dq = NULL;
+ unsigned char *pq = NULL, *qp = NULL, *p = NULL, *q = NULL;
+ SilcUInt32 e_len, n_len, d_len, dp_len, dq_len, pq_len, qp_len, p_len, q_len;
+ SilcUInt32 len = 0;
+
+ e = silc_mp_mp2bin(&key->e, 0, &e_len);
+ n = silc_mp_mp2bin(&key->n, (key->bits + 7) / 8, &n_len);
+ d = silc_mp_mp2bin(&key->d, 0, &d_len);
+ if (key->crt) {
+ dp = silc_mp_mp2bin(&key->dP, 0, &dp_len);
+ dq = silc_mp_mp2bin(&key->dQ, 0, &dq_len);
+ pq = silc_mp_mp2bin(&key->pQ, 0, &pq_len);
+ qp = silc_mp_mp2bin(&key->qP, 0, &qp_len);
+ p = silc_mp_mp2bin(&key->p, 0, &p_len);
+ q = silc_mp_mp2bin(&key->q, 0, &q_len);
+ len = dp_len + 4 + dq_len + 4 + pq_len + 4 + qp_len + 4 + p_len + 4 +
+ q_len + 4;
+ }
+
+ buf = silc_buffer_alloc_size(e_len + 4 + n_len + 4 + d_len + 4 + len);
+ len = silc_buffer_format(buf,
+ SILC_STR_UI_INT(e_len),
+ SILC_STR_UI_XNSTRING(e, e_len),
+ SILC_STR_UI_INT(n_len),
+ SILC_STR_UI_XNSTRING(n, n_len),
+ SILC_STR_UI_INT(d_len),
+ SILC_STR_UI_XNSTRING(d, d_len),
+ SILC_STR_END);
+
+ if (key->crt) {
+ silc_buffer_pull(buf, len);
+ silc_buffer_format(buf,
+ SILC_STR_UI_INT(dp_len),
+ SILC_STR_UI_XNSTRING(dp, dp_len),
+ SILC_STR_UI_INT(dq_len),
+ SILC_STR_UI_XNSTRING(dq, dq_len),
+ SILC_STR_UI_INT(pq_len),
+ SILC_STR_UI_XNSTRING(pq, pq_len),
+ SILC_STR_UI_INT(qp_len),
+ SILC_STR_UI_XNSTRING(qp, qp_len),
+ SILC_STR_UI_INT(p_len),
+ SILC_STR_UI_XNSTRING(p, p_len),
+ SILC_STR_UI_INT(q_len),
+ SILC_STR_UI_XNSTRING(q, q_len),
+ SILC_STR_END);
+ silc_buffer_push(buf, len);
+
+ memset(dp, 0, dp_len);
+ memset(dq, 0, dq_len);
+ memset(pq, 0, pq_len);
+ memset(qp, 0, qp_len);
+ memset(p, 0, p_len);
+ memset(q, 0, q_len);
+ silc_free(dp);
+ silc_free(dq);
+ silc_free(pq);
+ silc_free(qp);
+ silc_free(p);
+ silc_free(q);
+ }
+
+ memset(d, 0, d_len);
+ silc_free(e);
+ silc_free(n);
+ silc_free(d);
+
+ ret = silc_buffer_steal(buf, ret_len);
+ silc_buffer_free(buf);
+ return ret;
+}
+
+/* Set public key */
+
+SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ unsigned char tmp[4];
+ SilcUInt32 e_len, n_len;
+
+ if (key->pub_set) {
+ silc_mp_uninit(&key->e);
+ silc_mp_uninit(&key->n);
+ key->pub_set = FALSE;
+ }
+
+ if (key_len < 4)
+ return 0;
+
+ silc_mp_init(&key->e);
+ silc_mp_init(&key->n);
+
+ memcpy(tmp, key_data, 4);
+ SILC_GET32_MSB(e_len, tmp);
+ if (!e_len || e_len + 4 > key_len) {
+ silc_mp_uninit(&key->e);
+ silc_mp_uninit(&key->n);
+ return 0;
+ }
+
+ silc_mp_bin2mp(key_data + 4, e_len, &key->e);
+
+ if (key_len < 4 + e_len + 4) {
+ silc_mp_uninit(&key->e);
+ silc_mp_uninit(&key->n);
+ return 0;
+ }
+
+ memcpy(tmp, key_data + 4 + e_len, 4);
+ SILC_GET32_MSB(n_len, tmp);
+ if (!n_len || e_len + 4 + n_len + 4 > key_len) {
+ silc_mp_uninit(&key->e);
+ silc_mp_uninit(&key->n);
+ return 0;
+ }
+
+ silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &key->n);
+
+ key->bits = silc_mp_sizeinbase(&key->n, 2);
+ key->pub_set = TRUE;
+
+ return key->bits;
+}
+
+/* Set private key. This derives the public key from the private
+ key and sets the public key as well. Public key should not be set
+ already and should not be set after setting private key. */
+
+SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ SilcBufferStruct k;
+ unsigned char *tmp;
+ SilcUInt32 len;
+
+ if (key->prv_set) {
+ silc_mp_uninit(&key->d);
+ key->prv_set = FALSE;
+ }
+
+ if (key->pub_set) {
+ silc_mp_uninit(&key->e);
+ silc_mp_uninit(&key->n);
+ key->pub_set = FALSE;
+ }
+
+ if (key_len < 4)
+ return FALSE;
+
+ silc_buffer_set(&k, key_data, key_len);
+
+ silc_mp_init(&key->e);
+ silc_mp_init(&key->n);
+ silc_mp_init(&key->d);
+ key->prv_set = TRUE;
+ key->pub_set = TRUE;
+
+ /* Get e */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->e);
+ silc_buffer_pull(&k, len);
+
+ /* Get n */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->n);
+ silc_buffer_pull(&k, len);
+
+ /* Get d */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->d);
+ silc_buffer_pull(&k, len);
+
+ /* Get optimized d for CRT, if present. */
+ if (k.len > 4) {
+ key->crt = TRUE;
+ silc_mp_init(&key->dP);
+ silc_mp_init(&key->dQ);
+ silc_mp_init(&key->pQ);
+ silc_mp_init(&key->qP);
+ silc_mp_init(&key->p);
+ silc_mp_init(&key->q);
+
+ /* Get dP */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->dP);
+ silc_buffer_pull(&k, len);
+
+ /* Get dQ */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->dQ);
+ silc_buffer_pull(&k, len);
+
+ /* Get pQ */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->pQ);
+ silc_buffer_pull(&k, len);
+
+ /* Get qP */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->qP);
+ silc_buffer_pull(&k, len);
+
+ /* Get p */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->p);
+ silc_buffer_pull(&k, len);
+
+ /* Get q */
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_buffer_pull(&k, 4);
+ if (silc_buffer_unformat(&k,
+ SILC_STR_UI_XNSTRING(&tmp, len),
+ SILC_STR_END) < 0)
+ goto err;
+ silc_mp_bin2mp(tmp, len, &key->q);
+ silc_buffer_pull(&k, len);
+ }
+
+ key->bits = silc_mp_sizeinbase(&key->n, 2);
+ return key->bits;
+
+ err:
+ rsa_clear_keys(key);
+ return FALSE;
+}
+
+SILC_PKCS_API_CONTEXT_LEN(rsa)
+{
+ return sizeof(RsaKey);
+}
+
+/* Raw RSA routines */
+
+SILC_PKCS_API_ENCRYPT(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int tmplen;
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Format the data into MP int */
+ silc_mp_bin2mp(src, src_len, &mp_tmp);
+
+ /* Encrypt */
+ rsa_public_operation(key, &mp_tmp, &mp_dst);
+
+ tmplen = (key->bits + 7) / 8;
+
+ /* Format the MP int back into data */
+ silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen);
+ *dst_len = tmplen;
+
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_DECRYPT(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int tmplen;
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Format the data into MP int */
+ silc_mp_bin2mp(src, src_len, &mp_tmp);
+
+ /* Decrypt */
+ rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+ tmplen = (key->bits + 7) / 8;
+
+ /* Format the MP int back into data */
+ silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen);
+ *dst_len = tmplen;
+
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_SIGN(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int tmplen;
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Format the data into MP int */
+ silc_mp_bin2mp(src, src_len, &mp_tmp);
+
+ /* Sign */
+ rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+ tmplen = (key->bits + 7) / 8;
+
+ /* Format the MP int back into data */
+ silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen);
+ *dst_len = tmplen;
+
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_VERIFY(rsa)
+{
+ RsaKey *key = (RsaKey *)context;
+ int ret;
+ SilcMPInt mp_tmp, mp_tmp2;
+ SilcMPInt mp_dst;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_tmp2);
+ silc_mp_init(&mp_dst);
+
+ /* Format the signature into MP int */
+ silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
+
+ /* Verify */
+ rsa_public_operation(key, &mp_tmp2, &mp_dst);
+
+ /* Format the data into MP int */
+ silc_mp_bin2mp(data, data_len, &mp_tmp);
+
+ ret = TRUE;
+
+ /* Compare */
+ if ((silc_mp_cmp(&mp_tmp, &mp_dst)) != 0)
+ ret = FALSE;
+
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_tmp2);
+ silc_mp_uninit(&mp_dst);
+
+ return ret;
+}
+
+
+/* PKCS#1 RSA routines */
+
+SILC_PKCS_API_ENCRYPT(pkcs1)
+{
+ RsaKey *key = (RsaKey *)context;
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+ unsigned char padded[2048 + 1];
+ SilcUInt32 len = (key->bits + 7) / 8;
+
+ if (sizeof(padded) < len)
+ return FALSE;
+
+ /* Pad data */
+ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len,
+ padded, len, NULL))
+ return FALSE;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Data to MP */
+ silc_mp_bin2mp(padded, len, &mp_tmp);
+
+ /* Encrypt */
+ rsa_public_operation(key, &mp_tmp, &mp_dst);
+
+ /* MP to data */
+ silc_mp_mp2bin_noalloc(&mp_dst, dst, len);
+ *dst_len = len;
+
+ memset(padded, 0, sizeof(padded));
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_DECRYPT(pkcs1)
+{
+ RsaKey *key = (RsaKey *)context;
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+ unsigned char *padded, unpadded[2048 + 1];
+ SilcUInt32 padded_len;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Data to MP */
+ silc_mp_bin2mp(src, src_len, &mp_tmp);
+
+ /* Decrypt */
+ rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+ /* MP to data */
+ padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len);
+
+ /* Unpad data */
+ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len,
+ unpadded, sizeof(unpadded), dst_len)) {
+ memset(padded, 0, padded_len);
+ silc_free(padded);
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+ return FALSE;
+ }
+
+ /* Copy to destination */
+ memcpy(dst, unpadded, *dst_len);
+
+ memset(padded, 0, padded_len);
+ memset(unpadded, 0, sizeof(unpadded));
+ silc_free(padded);
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_SIGN(pkcs1)
+{
+ RsaKey *key = (RsaKey *)context;
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+ unsigned char padded[2048 + 1];
+ SilcUInt32 len = (key->bits + 7) / 8;
+
+ if (sizeof(padded) < len)
+ return FALSE;
+
+ /* Pad data */
+ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len,
+ padded, len, NULL))
+ return FALSE;
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Data to MP */
+ silc_mp_bin2mp(padded, len, &mp_tmp);
+
+ /* Sign */
+ rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+ /* MP to data */
+ silc_mp_mp2bin_noalloc(&mp_dst, dst, len);
+ *dst_len = len;
+
+ memset(padded, 0, sizeof(padded));
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+
+ return TRUE;
+}
+
+SILC_PKCS_API_VERIFY(pkcs1)
+{
+ RsaKey *key = (RsaKey *)context;
+ int ret = TRUE;
+ SilcMPInt mp_tmp2;
+ SilcMPInt mp_dst;
+ unsigned char *verify, unpadded[2048 + 1];
+ SilcUInt32 verify_len, len = (key->bits + 7) / 8;
+
+ silc_mp_init(&mp_tmp2);
+ silc_mp_init(&mp_dst);
+
+ /* Format the signature into MP int */
+ silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
+
+ /* Verify */
+ rsa_public_operation(key, &mp_tmp2, &mp_dst);
+
+ /* MP to data */
+ verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);
+
+ /* Unpad data */
+ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
+ unpadded, sizeof(unpadded), &len)) {
+ memset(verify, 0, verify_len);
+ silc_free(verify);
+ silc_mp_uninit(&mp_tmp2);
+ silc_mp_uninit(&mp_dst);
+ return FALSE;
+ }
+
+ /* Compare */
+ if (memcmp(data, unpadded, len))
+ ret = FALSE;
+
+ memset(verify, 0, verify_len);
+ memset(unpadded, 0, sizeof(unpadded));
+ silc_free(verify);
+ silc_mp_uninit(&mp_tmp2);
+ silc_mp_uninit(&mp_dst);
+
+ return ret;
+}
+
/* Generates RSA public and private keys. Primes p and q that are used
to compute the modulus n has to be generated before calling this. They
are then sent as argument for the function. */
-SilcBool silc_rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q,
- void **ret_public_key, void **ret_private_key)
+bool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
+ SilcMPInt *p, SilcMPInt *q)
{
- RsaPublicKey *pubkey;
- RsaPrivateKey *privkey;
SilcMPInt phi, hlp;
SilcMPInt div, lcm;
SilcMPInt pm1, qm1;
- *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
- if (!pubkey)
- return FALSE;
-
- *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey));
- if (!privkey)
- return FALSE;
-
/* Initialize variables */
- silc_mp_init(&privkey->n);
- silc_mp_init(&privkey->e);
- silc_mp_init(&privkey->d);
- silc_mp_init(&privkey->dP);
- silc_mp_init(&privkey->dQ);
- silc_mp_init(&privkey->qP);
+ silc_mp_init(&key->n);
+ silc_mp_init(&key->e);
+ silc_mp_init(&key->d);
+ silc_mp_init(&key->dP);
+ silc_mp_init(&key->dQ);
+ silc_mp_init(&key->pQ);
+ silc_mp_init(&key->qP);
silc_mp_init(&phi);
silc_mp_init(&hlp);
silc_mp_init(&div);
silc_mp_init(&qm1);
/* Set modulus length */
- privkey->bits = bits;
+ key->bits = bits;
/* Compute modulus, n = p * q */
- silc_mp_mul(&privkey->n, p, q);
+ silc_mp_mul(&key->n, p, q);
/* phi = (p - 1) * (q - 1) */
silc_mp_sub_ui(&pm1, p, 1);
/* Set e, the public exponent. We try to use same public exponent
for all keys. Also, to make encryption faster we use small
number. */
- silc_mp_set_ui(&privkey->e, 65533);
+ silc_mp_set_ui(&key->e, 65533);
retry_e:
/* See if e is relatively prime to phi. gcd == greates common divisor,
if gcd equals 1 they are relatively prime. */
- silc_mp_gcd(&hlp, &privkey->e, &phi);
+ silc_mp_gcd(&hlp, &key->e, &phi);
if ((silc_mp_cmp_ui(&hlp, 1)) > 0) {
- silc_mp_add_ui(&privkey->e, &privkey->e, 2);
+ silc_mp_add_ui(&key->e, &key->e, 2);
goto retry_e;
}
/* Find d, the private exponent, e ^ -1 mod lcm(phi). */
silc_mp_gcd(&div, &pm1, &qm1);
silc_mp_div(&lcm, &phi, &div);
- silc_mp_modinv(&privkey->d, &privkey->e, &lcm);
-
- /* Optimize d with CRT. */
- silc_mp_mod(&privkey->dP, &privkey->d, &pm1);
- silc_mp_mod(&privkey->dQ, &privkey->d, &qm1);
- silc_mp_modinv(&privkey->qP, q, p);
- silc_mp_set(&privkey->p, p);
- silc_mp_set(&privkey->q, q);
+ silc_mp_modinv(&key->d, &key->e, &lcm);
+
+ /* Optimize d with CRT. We precompute as much as possible. */
+ silc_mp_mod(&key->dP, &key->d, &pm1);
+ silc_mp_mod(&key->dQ, &key->d, &qm1);
+ silc_mp_modinv(&key->pQ, p, q);
+ silc_mp_mul(&key->pQ, p, &key->pQ);
+ silc_mp_mod(&key->pQ, &key->pQ, &key->n);
+ silc_mp_modinv(&key->qP, q, p);
+ silc_mp_mul(&key->qP, q, &key->qP);
+ silc_mp_mod(&key->qP, &key->qP, &key->n);
+ silc_mp_set(&key->p, p);
+ silc_mp_set(&key->q, q);
+ key->crt = TRUE;
silc_mp_uninit(&phi);
silc_mp_uninit(&hlp);
silc_mp_uninit(&pm1);
silc_mp_uninit(&qm1);
- /* Set public key */
- silc_mp_init(&pubkey->n);
- silc_mp_init(&pubkey->e);
- pubkey->bits = privkey->bits;
- silc_mp_set(&pubkey->n, &privkey->n);
- silc_mp_set(&pubkey->e, &privkey->e);
+ return TRUE;
+}
+
+/* Clears whole key structure. */
+bool rsa_clear_keys(RsaKey *key)
+{
+ key->bits = 0;
+ if (key->pub_set) {
+ silc_mp_uninit(&key->n);
+ silc_mp_uninit(&key->e);
+ }
+ if (key->prv_set)
+ silc_mp_uninit(&key->d);
+ if (key->prv_set && key->crt) {
+ silc_mp_uninit(&key->dP);
+ silc_mp_uninit(&key->dQ);
+ silc_mp_uninit(&key->pQ);
+ silc_mp_uninit(&key->qP);
+ silc_mp_uninit(&key->p);
+ silc_mp_uninit(&key->q);
+ }
return TRUE;
}
/* RSA public key operation */
-SilcBool silc_rsa_public_operation(RsaPublicKey *key, SilcMPInt *src,
- SilcMPInt *dst)
+bool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst)
{
/* dst = src ^ e mod n */
silc_mp_pow_mod(dst, src, &key->e, &key->n);
/* RSA private key operation */
-SilcBool silc_rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src,
- SilcMPInt *dst)
+bool rsa_private_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst)
{
- SilcMPInt tmp;
-
- silc_mp_init(&tmp);
-
- /* dst = (src ^ dP mod p) */
- silc_mp_pow_mod(dst, src, &key->dP, &key->p);
-
- /* tmp = (src ^ dQ mod q) */
- silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q);
-
- /* dst = (dst - tmp) * qP mod p */
- silc_mp_sub(dst, dst, &tmp);
- silc_mp_mul(dst, dst, &key->qP);
- silc_mp_mod(dst, dst, &key->p);
-
- /* dst = (q * dst) + tmp */
- silc_mp_mul(dst, dst, &key->q);
- silc_mp_add(dst, dst, &tmp);
-
- silc_mp_uninit(&tmp);
+ if (!key->crt) {
+ /* dst = src ^ d mod n */
+ silc_mp_pow_mod(dst, src, &key->d, &key->n);
+ } else {
+ /* CRT */
+ SilcMPInt tmp;
+
+ silc_mp_init(&tmp);
+
+ /* dst = ((src ^ dP mod p) * qP) + ((src ^ dQ mod q) * pQ) mod n */
+ silc_mp_pow_mod(dst, src, &key->dP, &key->p);
+ silc_mp_mul(dst, dst, &key->qP);
+ silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q);
+ silc_mp_mul(&tmp, &tmp, &key->pQ);
+ silc_mp_add(dst, dst, &tmp);
+ silc_mp_mod(dst, dst, &key->n);
+
+ silc_mp_uninit(&tmp);
+ }
return TRUE;
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2003 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 RSA_H
#define RSA_H
-/* RSA Public Key */
-typedef struct {
- int bits; /* bits in key */
- SilcMPInt n; /* modulus */
- SilcMPInt e; /* public exponent */
-} RsaPublicKey;
-
-/* RSA Private Key */
-typedef struct {
- int bits; /* bits in key */
- SilcMPInt n; /* modulus */
- SilcMPInt e; /* public exponent */
- SilcMPInt d; /* private exponent */
- SilcMPInt p; /* CRT, p */
- SilcMPInt q; /* CRT, q */
- SilcMPInt dP; /* CRT, d mod p - 1 */
- SilcMPInt dQ; /* CRT, d mod q - 1 */
- SilcMPInt qP; /* CRT, q ^ -1 mod p (aka u, aka qInv) */
-} RsaPrivateKey;
-
-SilcBool silc_rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q,
- void **ret_public_key, void **ret_private_key);
-SilcBool silc_rsa_public_operation(RsaPublicKey *key, SilcMPInt *src,
- SilcMPInt *dst);
-SilcBool silc_rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src,
- SilcMPInt *dst);
-
-#endif /* RSA_H */
+/*
+ * SILC PKCS API for RSA
+ */
+
+SILC_PKCS_API_INIT(rsa);
+SILC_PKCS_API_CLEAR_KEYS(rsa);
+SILC_PKCS_API_GET_PUBLIC_KEY(rsa);
+SILC_PKCS_API_GET_PRIVATE_KEY(rsa);
+SILC_PKCS_API_SET_PUBLIC_KEY(rsa);
+SILC_PKCS_API_SET_PRIVATE_KEY(rsa);
+SILC_PKCS_API_CONTEXT_LEN(rsa);
+SILC_PKCS_API_ENCRYPT(rsa);
+SILC_PKCS_API_DECRYPT(rsa);
+SILC_PKCS_API_SIGN(rsa);
+SILC_PKCS_API_VERIFY(rsa);
+
+SILC_PKCS_API_ENCRYPT(pkcs1);
+SILC_PKCS_API_DECRYPT(pkcs1);
+SILC_PKCS_API_SIGN(pkcs1);
+SILC_PKCS_API_VERIFY(pkcs1);
+
+
+#endif
--- /dev/null
+/*
+
+ rsa_internal.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2003 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 RSA_INTERNAL_H
+#define RSA_INTERNAL_H
+
+/* RSA Keys, includes both Private and Public key */
+typedef struct {
+ int bits; /* bits in key */
+ SilcMPInt n; /* modulus */
+ SilcMPInt e; /* public exponent */
+ SilcMPInt d; /* private exponent (no CRT) */
+ SilcMPInt p; /* p */
+ SilcMPInt q; /* q */
+ SilcMPInt dP; /* CRT, d mod p - 1 */
+ SilcMPInt dQ; /* CRT, d mod q - 1 */
+ SilcMPInt pQ; /* CRT, p * (p ^ -1 mod q) mod n */
+ SilcMPInt qP; /* CRT, q * (q ^ -1 mod p) mod n */
+ unsigned int pub_set : 1; /* TRUE if n and e is set */
+ unsigned int prv_set : 1; /* TRUE if d is set */
+ unsigned int crt : 1; /* TRUE if CRT is used */
+} RsaKey;
+
+bool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
+ SilcMPInt *p, SilcMPInt *q);
+bool rsa_clear_keys(RsaKey *key);
+bool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst);
+bool rsa_private_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst);
+
+#endif
100% Public Domain
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "sha1_internal.h"
#include "sha1.h"
*
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "sha256_internal.h"
#include "sha256.h"
/* Various logical functions */
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x),(n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
/* fill W[16..63] */
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
- }
+ }
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i,ki) \
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
-
-#undef RND
+
+#undef RND
/* feedback */
for (i = 0; i < 8; i++) {
if (md->curlen > block_size)
return FALSE;
- while (inlen > 0) {
+ while (inlen > 0) {
if (md->curlen == 0 && inlen >= block_size) {
if ((err = sha256_compress(md->state, (unsigned char *)in)) != TRUE)
return err;
in += block_size;
inlen -= block_size;
} else {
- n = MIN(inlen, (block_size - md->curlen));
+ n = MIN(inlen, (block_size - md->curlen));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "ciphers.h" /* Includes cipher definitions */
/* The SilcCipher context */
unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
};
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
/* Dynamically registered list of ciphers. */
SilcDList silc_cipher_list = NULL;
-#endif /* SILC_SYMBIAN */
-
-/* Macro to define cipher to cipher list */
-#define SILC_CIPHER_API_DEF(name, cipher, keylen, blocklen, ivlen, mode) \
-{ name, silc_##cipher##_set_key, silc_##cipher##_set_iv, \
- silc_##cipher##_encrypt, silc_##cipher##_decrypt, \
- silc_##cipher##_context_len, keylen, blocklen, ivlen, mode }
+#endif /* SILC_EPOC */
/* Static list of ciphers for silc_cipher_register_default(). */
const SilcCipherObject silc_default_ciphers[] =
{
- SILC_CIPHER_API_DEF("aes-256-ctr", aes_ctr, 256, 16, 16,
- SILC_CIPHER_MODE_CTR),
- SILC_CIPHER_API_DEF("aes-192-ctr", aes_ctr, 192, 16, 16,
- SILC_CIPHER_MODE_CTR),
- SILC_CIPHER_API_DEF("aes-128-ctr", aes_ctr, 128, 16, 16,
- SILC_CIPHER_MODE_CTR),
- SILC_CIPHER_API_DEF("aes-256-cbc", aes_cbc, 256, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("aes-192-cbc", aes_cbc, 192, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("aes-128-cbc", aes_cbc, 128, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("twofish-256-cbc", twofish_cbc, 256, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("twofish-192-cbc", twofish_cbc, 192, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("twofish-128-cbc", twofish_cbc, 128, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("cast-256-cbc", cast_cbc, 256, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("cast-192-cbc", cast_cbc, 192, 16, 16,
- SILC_CIPHER_MODE_CBC),
- SILC_CIPHER_API_DEF("cast-128-cbc", cast_cbc, 128, 16, 16,
- SILC_CIPHER_MODE_CBC),
+ { "aes-256-cbc", 16, 256, silc_aes_set_key,
+ silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
+ silc_aes_decrypt_cbc, silc_aes_context_len },
+ { "aes-192-cbc", 16, 192, silc_aes_set_key,
+ silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
+ silc_aes_decrypt_cbc, silc_aes_context_len },
+ { "aes-128-cbc", 16, 128, silc_aes_set_key,
+ silc_aes_set_key_with_string, silc_aes_encrypt_cbc,
+ silc_aes_decrypt_cbc, silc_aes_context_len },
+ { "twofish-256-cbc", 16, 256, silc_twofish_set_key,
+ silc_twofish_set_key_with_string,
+ silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
+ silc_twofish_context_len },
+ { "twofish-192-cbc", 16, 192, silc_twofish_set_key,
+ silc_twofish_set_key_with_string,
+ silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
+ silc_twofish_context_len },
+ { "twofish-128-cbc", 16, 128, silc_twofish_set_key,
+ silc_twofish_set_key_with_string,
+ silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc,
+ silc_twofish_context_len },
+ { "cast-256-cbc", 16, 256, silc_cast_set_key, silc_cast_set_key_with_string,
+ silc_cast_encrypt_cbc, silc_cast_decrypt_cbc,
+ silc_cast_context_len },
+ { "cast-192-cbc", 16, 192, silc_cast_set_key, silc_cast_set_key_with_string,
+ silc_cast_encrypt_cbc, silc_cast_decrypt_cbc,
+ silc_cast_context_len },
+ { "cast-128-cbc", 16, 128, silc_cast_set_key, silc_cast_set_key_with_string,
+ silc_cast_encrypt_cbc, silc_cast_decrypt_cbc,
+ silc_cast_context_len },
#ifdef SILC_DEBUG
- SILC_CIPHER_API_DEF("none", none, 0, 0, 0, 0),
+ { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
+ silc_none_encrypt_cbc, silc_none_decrypt_cbc,
+ silc_none_context_len },
#endif /* SILC_DEBUG */
- { NULL, NULL, 0, 0, 0, 0 }
+
+ { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
};
/* Register a new cipher into SILC. This is used at the initialization of
registered. Therefore, if memory has been allocated for the object sent
as argument it has to be free'd after this function returns succesfully. */
-SilcBool silc_cipher_register(const SilcCipherObject *cipher)
+bool silc_cipher_register(const SilcCipherObject *cipher)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcCipherObject *new;
SILC_LOG_DEBUG(("Registering new cipher `%s'", cipher->name));
new = silc_calloc(1, sizeof(*new));
new->name = strdup(cipher->name);
- new->key_len = cipher->key_len;
new->block_len = cipher->block_len;
- new->iv_len = cipher->iv_len;
+ new->key_len = cipher->key_len;
new->set_key = cipher->set_key;
- new->set_iv = cipher->set_iv;
+ new->set_key_with_string = cipher->set_key_with_string;
new->encrypt = cipher->encrypt;
new->decrypt = cipher->decrypt;
new->context_len = cipher->context_len;
- new->mode = cipher->mode;
/* Add to list */
if (silc_cipher_list == NULL)
silc_cipher_list = silc_dlist_init();
silc_dlist_add(silc_cipher_list, new);
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
/* Unregister a cipher from the SILC. */
-SilcBool silc_cipher_unregister(SilcCipherObject *cipher)
+bool silc_cipher_unregister(SilcCipherObject *cipher)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcCipherObject *entry;
SILC_LOG_DEBUG(("Unregistering cipher"));
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return FALSE;
}
The application may use this to register the default ciphers if specific
ciphers in any specific order is not wanted. */
-SilcBool silc_cipher_register_default(void)
+bool silc_cipher_register_default(void)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
int i;
for (i = 0; silc_default_ciphers[i].name; i++)
silc_cipher_register(&(silc_default_ciphers[i]));
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
-SilcBool silc_cipher_unregister_all(void)
+bool silc_cipher_unregister_all(void)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcCipherObject *entry;
if (!silc_cipher_list)
if (!silc_cipher_list)
break;
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
caller must set the key to the cipher after this function has returned
by calling the ciphers set_key function. */
-SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
+bool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
{
SilcCipherObject *entry = NULL;
SILC_LOG_DEBUG(("Allocating new cipher object"));
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
if (silc_cipher_list) {
silc_dlist_start(silc_cipher_list);
while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
}
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
if (entry) {
*new_cipher = silc_calloc(1, sizeof(**new_cipher));
/* Returns TRUE if cipher `name' is supported. */
-SilcBool silc_cipher_is_supported(const unsigned char *name)
+bool silc_cipher_is_supported(const unsigned char *name)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcCipherObject *entry;
if (silc_cipher_list) {
if (!strcmp(silc_default_ciphers[i].name, name))
return TRUE;
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return FALSE;
}
char *list = NULL;
int len = 0;
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
if (silc_cipher_list) {
silc_dlist_start(silc_cipher_list);
while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
len++;
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
list[len - 1] = 0;
/* Encrypts */
-SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
- unsigned char *dst, SilcUInt32 len,
- unsigned char *iv)
+bool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
+ unsigned char *dst, SilcUInt32 len,
+ unsigned char *iv)
{
+#ifdef SILC_DEBUG
+ assert((len & (cipher->cipher->block_len - 1)) == 0);
+#endif
+ if (len & (cipher->cipher->block_len - 1))
+ return FALSE;
return cipher->cipher->encrypt(cipher->context, src, dst, len,
iv ? iv : cipher->iv);
}
/* Decrypts */
-SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
- unsigned char *dst, SilcUInt32 len,
- unsigned char *iv)
+bool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
+ unsigned char *dst, SilcUInt32 len,
+ unsigned char *iv)
{
+#ifdef SILC_DEBUG
+ /* assert((len & (cipher->cipher->block_len - 1)) == 0); */
+#endif
+ if (len & (cipher->cipher->block_len - 1))
+ return FALSE;
return cipher->cipher->decrypt(cipher->context, src, dst, len,
iv ? iv : cipher->iv);
}
/* Sets the key for the cipher */
-SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
- SilcUInt32 keylen, SilcBool encryption)
+bool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
+ SilcUInt32 keylen)
{
- return cipher->cipher->set_key(cipher->context, key, keylen, encryption);
+ return cipher->cipher->set_key(cipher->context, key, keylen);
}
/* Sets the IV (initial vector) for the cipher. */
void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv)
{
- if (iv)
- memmove(&cipher->iv, iv, cipher->cipher->iv_len);
- cipher->cipher->set_iv(cipher->context, iv);
+ memset(&cipher->iv, 0, sizeof(cipher->iv));
+ memcpy(&cipher->iv, iv, cipher->cipher->block_len);
}
/* Returns the IV (initial vector) of the cipher. */
return cipher->cipher->block_len;
}
-/* Returns the IV length of the cipher. */
-
-SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher)
-{
- return cipher->cipher->iv_len;
-}
-
/* Returns the name of the cipher */
const char *silc_cipher_get_name(SilcCipher cipher)
{
return (const char *)cipher->cipher->name;
}
-
-/* Returns cipher mode */
-
-SilcCipherMode silc_cipher_get_mode(SilcCipher cipher)
-{
- return cipher->cipher->mode;
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 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
/****s* silccrypt/SilcCipherAPI/SilcCipher
*
* NAME
- *
+ *
* typedef struct { ... } SilcCipher;
*
* DESCRIPTION
/* The default SILC Cipher object to represent any cipher in SILC. */
typedef struct {
char *name;
- SilcBool (*set_key)(void *, const unsigned char *, SilcUInt32, SilcBool);
- void (*set_iv)(void *, const unsigned char *);
- SilcBool (*encrypt)(void *, const unsigned char *, unsigned char *,
- SilcUInt32, unsigned char *);
- SilcBool (*decrypt)(void *, const unsigned char *, unsigned char *,
- SilcUInt32, unsigned char *);
+ SilcUInt32 block_len;
+ SilcUInt32 key_len;
+
+ bool (*set_key)(void *, const unsigned char *, SilcUInt32);
+ bool (*set_key_with_string)(void *, const unsigned char *, SilcUInt32);
+ bool (*encrypt)(void *, const unsigned char *, unsigned char *,
+ SilcUInt32, unsigned char *);
+ bool (*decrypt)(void *, const unsigned char *, unsigned char *,
+ SilcUInt32, unsigned char *);
SilcUInt32 (*context_len)();
- unsigned int key_len : 10;
- unsigned int block_len : 8;
- unsigned int iv_len : 8;
- unsigned int mode : 6;
} SilcCipherObject;
#define SILC_CIPHER_MAX_IV_SIZE 16
/* Default cipher in the SILC protocol */
#define SILC_DEFAULT_CIPHER "aes-256-cbc"
+
/* Macros */
/* Function names in SILC Crypto modules. The name of the cipher
of the module. All SILC Crypto API compliant modules must support
these function names (use macros below to assure this). */
#define SILC_CIPHER_SIM_SET_KEY "set_key"
-#define SILC_CIPHER_SIM_ENCRYPT "encrypt"
-#define SILC_CIPHER_SIM_DECRYPT "decrypt"
+#define SILC_CIPHER_SIM_SET_KEY_WITH_STRING "set_key_with_string"
+#define SILC_CIPHER_SIM_ENCRYPT_CBC "encrypt_cbc"
+#define SILC_CIPHER_SIM_DECRYPT_CBC "decrypt_cbc"
#define SILC_CIPHER_SIM_CONTEXT_LEN "context_len"
/* These macros can be used to implement the SILC Crypto API and to avoid
errors in the API these macros should be used always. */
-#define SILC_CIPHER_API_SET_KEY(cipher) \
-SilcBool silc_##cipher##_set_key(void *context, \
- const unsigned char *key, \
- SilcUInt32 keylen, \
- SilcBool encryption)
-#define SILC_CIPHER_API_SET_IV(cipher) \
-void silc_##cipher##_set_iv(void *context, \
- const unsigned char *iv)
-#define SILC_CIPHER_API_ENCRYPT(cipher) \
-SilcBool silc_##cipher##_encrypt(void *context, \
+#define SILC_CIPHER_API_SET_KEY(cipher) \
+bool silc_##cipher##_set_key(void *context, \
+ const unsigned char *key, \
+ SilcUInt32 keylen)
+#define SILC_CIPHER_API_SET_KEY_WITH_STRING(cipher) \
+bool silc_##cipher##_set_key_with_string(void *context, \
+ const unsigned char *string, \
+ SilcUInt32 stringlen)
+#define SILC_CIPHER_API_ENCRYPT_CBC(cipher) \
+bool silc_##cipher##_encrypt_cbc(void *context, \
const unsigned char *src, \
- unsigned char *dst, \
+ unsigned char *dst, \
SilcUInt32 len, \
- unsigned char *iv)
-#define SILC_CIPHER_API_DECRYPT(cipher) \
-SilcBool silc_##cipher##_decrypt(void *context, \
- const unsigned char *src, \
+ unsigned char *iv)
+#define SILC_CIPHER_API_DECRYPT_CBC(cipher) \
+bool silc_##cipher##_decrypt_cbc(void *context, \
+ const unsigned char *src, \
unsigned char *dst, \
SilcUInt32 len, \
unsigned char *iv)
-#define SILC_CIPHER_API_CONTEXT_LEN(cipher) \
+
+
+#define SILC_CIPHER_API_CONTEXT_LEN(cipher) \
SilcUInt32 silc_##cipher##_context_len()
-/****d* silccrypt/SilcCipherAPI/SilcCipherMode
- *
- * NAME
- *
- * typedef enum { ... } SilcCipherMode;
- *
- * DESCRIPTION
- *
- * Cipher modes.
- *
- * SOURCE
- */
-typedef enum {
- SILC_CIPHER_MODE_ECB = 1, /* ECB mode */
- SILC_CIPHER_MODE_CBC = 2, /* CBC mode */
- SILC_CIPHER_MODE_CTR = 3, /* CTR mode */
- SILC_CIPHER_MODE_CFB = 4, /* CFB mode */
- SILC_CIPHER_MODE_OFB = 5, /* OFB mode */
-} SilcCipherMode;
-/***/
/* Prototypes */
*
* SYNOPSIS
*
- * SilcBool silc_cipher_register(const SilcCipherObject *cipher);
+ * bool silc_cipher_register(const SilcCipherObject *cipher);
*
* DESCRIPTION
*
* as argument it has to be free'd after this function returns succesfully.
*
***/
-SilcBool silc_cipher_register(const SilcCipherObject *cipher);
+bool silc_cipher_register(const SilcCipherObject *cipher);
/****f* silccrypt/SilcCipherAPI/silc_cipher_unregister
*
* SYNOPSIS
*
- * SilcBool silc_cipher_unregister(SilcCipherObject *cipher);
+ * bool silc_cipher_unregister(SilcCipherObject *cipher);
*
* DESCRIPTION
*
* Unregister a cipher from the SILC.
*
***/
-SilcBool silc_cipher_unregister(SilcCipherObject *cipher);
+bool silc_cipher_unregister(SilcCipherObject *cipher);
/****f* silccrypt/SilcCipherAPI/silc_cipher_register_default
*
* SYNOPSIS
*
- * SilcBool silc_cipher_register_default(void);
+ * bool silc_cipher_register_default(void);
*
* 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.
*
***/
-SilcBool silc_cipher_register_default(void);
+bool silc_cipher_register_default(void);
/****f* silccrypt/SilcCipherAPI/silc_cipher_unregister_all
*
* SYNOPSIS
*
- * SilcBool silc_cipher_unregister_all(void);
+ * bool silc_cipher_unregister_all(void);
*
* DESCRIPTION
*
* Unregisters all ciphers.
*
***/
-SilcBool silc_cipher_unregister_all(void);
+bool silc_cipher_unregister_all(void);
/****f* silccrypt/SilcCipherAPI/silc_cipher_alloc
*
* SYNOPSIS
*
- * SilcBool silc_cipher_alloc(const unsigned char *name,
- * SilcCipher *new_cipher);
+ * bool silc_cipher_alloc(const unsigned char *name,
+ * SilcCipher *new_cipher);
*
* 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.
*
- * The following ciphers are supported:
- *
- * aes-256-ctr AES-256, Counter mode
- * aes-192-ctr AES-192, Counter mode
- * aes-128-ctr AES,128, Counter mode
- * aes-256-cbc AES-256, Cipher block chaining mode
- * aes-192-cbc AES-192, Cipher block chaining mode
- * aes-128-cbc AES,128, Cipher block chaining mode
- * twofish-256-cbc Twofish-256, Cipher block chaining mode
- * twofish-192-cbc Twofish-192, Cipher block chaining mode
- * twofish-128-cbc Twofish-128, Cipher block chaining mode
- *
- * Notes about modes:
- *
- * The CTR is normal counter mode. The CTR mode does not require the
- * plaintext length to be multiple by the cipher block size. If the last
- * plaintext block is shorter the remaining bits of the key stream are
- * used next time silc_cipher_encrypt is called. If silc_cipher_set_iv
- * is called it will reset the counter for a new block (discarding any
- * remaining bits from previous key stream).
- *
- * The CBC is mode is a standard CBC mode. The plaintext length must be
- * multiple by the cipher block size. If it isn't the plaintext must be
- * padded.
- *
***/
-SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher);
+bool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher);
/****f* silccrypt/SilcCipherAPI/silc_cipher_free
*
*
* SYNOPSIS
*
- * SilcBool silc_cipher_is_supported(const unsigned char *name);
+ * bool silc_cipher_is_supported(const unsigned char *name);
*
* DESCRIPTION
*
* Returns TRUE if cipher `name' is supported.
- *
+ *
***/
-SilcBool silc_cipher_is_supported(const unsigned char *name);
+bool silc_cipher_is_supported(const unsigned char *name);
/****f* silccrypt/SilcCipherAPI/silc_cipher_get_supported
*
*
* SYNOPSIS
*
- * SilcBool silc_cipher_encrypt(SilcCipher cipher,
- * const unsigned char *src,
- * unsigned char *dst, SilcUInt32 len,
- * unsigned char *iv);
+ * bool 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);
+bool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
+ 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);
+ * bool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
+ * unsigned char *dst, SilcUInt32 len,
+ * unsigned char *iv);
*
* DESCRIPTION
*
* IV is used. The `src' and `dst' maybe same buffer.
*
***/
-SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
- unsigned char *dst, SilcUInt32 len,
- unsigned char *iv);
+bool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
+ unsigned char *dst, SilcUInt32 len,
+ unsigned char *iv);
/****f* silccrypt/SilcCipherAPI/silc_cipher_set_key
*
* SYNOPSIS
*
- * SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
- * SilcUInt32 keylen, SilcBool encryption);
+ * bool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
+ * SilcUInt32 keylen);
*
* DESCRIPTION
*
* Sets the key for the cipher. The `keylen' is the key length in
- * bits. If the `encryption' is TRUE the key is for encryption, if FALSE
- * the key is for decryption.
+ * bits.
*
***/
-SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
- SilcUInt32 keylen, SilcBool encryption);
+bool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
+ SilcUInt32 keylen);
/****f* silccrypt/SilcCipherAPI/silc_cipher_set_iv
*
*
* DESCRIPTION
*
- * Sets the IV (initial vector) for the cipher. The `iv' must be
- * the size of the block size of the cipher. If `iv' is NULL this
- * does not do anything.
- *
- * If the encryption mode is CTR (Counter mode) this also resets the
- * the counter for a new block. This is done also if `iv' is NULL.
+ * Sets the IV (initial vector) for the cipher. The `iv' must be
+ * the size of the block size of the cipher.
*
***/
void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv);
*
* DESCRIPTION
*
- * Returns the IV (initial vector) of the cipher. The returned
- * pointer must not be freed by the caller. If the caller modifies
- * the returned pointer the IV inside cipher is also modified.
- *
+ * 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);
* DESCRIPTION
*
* Returns the key length of the cipher in bits.
- *
+ *
***/
SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher);
***/
SilcUInt32 silc_cipher_get_block_len(SilcCipher cipher);
-/****f* silccrypt/SilcCipherAPI/silc_cipher_get_iv_len
- *
- * SYNOPSIS
- *
- * SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher);
- *
- * DESCRIPTION
- *
- * Returns the IV length of the cipher in bytes.
- *
- ***/
-SilcUInt32 silc_cipher_get_iv_len(SilcCipher cipher);
-
/****f* silccrypt/SilcCipherAPI/silc_cipher_get_name
*
* SYNOPSIS
***/
const char *silc_cipher_get_name(SilcCipher cipher);
-/****f* silccrypt/SilcCipherAPI/silc_cipher_get_mode
- *
- * SYNOPSIS
- *
- * SilcCipherMode silc_cipher_get_mode(SilcCipher cipher);
- *
- * DESCRIPTION
- *
- * Returns the cipher mode.
- *
- ***/
-SilcCipherMode silc_cipher_get_mode(SilcCipher cipher);
-
-#endif /* SILCCIPHER_H */
+#endif
*
* SYNOPSIS
*
- * SilcBool silc_dh_generate_private(SilcDH dh, const SilcMPInt **x);
+ * bool silc_dh_generate_private(SilcDH dh, const SilcMPInt **x);
*
* DESCRIPTION
*
* the `x' is NULL. The returned `x' must not be freed by the caller.
*
***/
-SilcBool silc_dh_generate_private(SilcDH dh, const SilcMPInt **x);
+bool silc_dh_generate_private(SilcDH dh, const SilcMPInt **x);
/****f* silccrypt/SilcDH/silc_dh_compute_public
*
* SYNOPSIS
*
- * SilcBool silc_dh_compute_public(SilcDH dh, const SilcMPInt **y);
+ * bool silc_dh_compute_public(SilcDH dh, const SilcMPInt **y);
*
* DESCRIPTION
*
* freed by the caller.
*
***/
-SilcBool silc_dh_compute_public(SilcDH dh, const SilcMPInt **y);
+bool silc_dh_compute_public(SilcDH dh, const SilcMPInt **y);
/****f* silccrypt/SilcDH/silc_dh_remote_public
*
* SYNOPSIS
*
- * SilcBool silc_dh_compute_public(SilcDH dh, SilcMPInt *y);
+ * bool silc_dh_compute_public(SilcDH dh, SilcMPInt *y);
*
* DESCRIPTION
*
* on error.
*
***/
-SilcBool silc_dh_set_remote_public(SilcDH dh, SilcMPInt *y);
+bool silc_dh_set_remote_public(SilcDH dh, SilcMPInt *y);
/****f* silccrypt/SilcDH/silc_dh_compute_key
*
* SYNOPSIS
*
- * SilcBool silc_dh_compute_key(SilcDH dh, const SilcMPInt **z);
+ * bool silc_dh_compute_key(SilcDH dh, const SilcMPInt **z);
*
* DESCRIPTION
*
* freed by the caller.
*
***/
-SilcBool silc_dh_compute_key(SilcDH dh, const SilcMPInt **z);
+bool silc_dh_compute_key(SilcDH dh, const SilcMPInt **z);
/****f* silccrypt/SilcDH/silc_dh_remote_public
*
* SYNOPSIS
*
- * SilcBool silc_dh_compute_key_data(SilcDH dh, unsigned char **z,
+ * bool silc_dh_compute_key_data(SilcDH dh, unsigned char **z,
* SilcUInt32 *z_len);
*
* DESCRIPTION
* string. The caller must free the returned binary string.
*
***/
-SilcBool silc_dh_compute_key_data(SilcDH dh, unsigned char **z,
+bool silc_dh_compute_key_data(SilcDH dh, unsigned char **z,
SilcUInt32 *z_len);
#endif
/*
- silchash.c
+ silchash.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "md5.h"
#include "sha1.h"
void *context;
};
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
/* List of dynamically registered hash functions. */
SilcDList silc_hash_list = NULL;
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
/* Default hash functions for silc_hash_register_default(). */
-const SilcHashObject silc_default_hash[] =
+const SilcHashObject silc_default_hash[] =
{
- { "sha256", "2.16.840.1.101.3.4.2.1",
- 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
+ { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
silc_sha256_transform, silc_sha256_context_len },
- { "sha1", "1.3.14.3.2.26",
- 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
+ { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
silc_sha1_transform, silc_sha1_context_len },
- { "md5", "1.2.840.113549.2.5",
- 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
+ { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
silc_md5_transform, silc_md5_context_len },
- { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+ { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
};
/* Registers a new hash function into the SILC. This function is used at
the initialization of the SILC. */
-SilcBool silc_hash_register(const SilcHashObject *hash)
+bool silc_hash_register(const SilcHashObject *hash)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHashObject *new;
SILC_LOG_DEBUG(("Registering new hash function `%s'", hash->name));
}
new = silc_calloc(1, sizeof(*new));
- if (!new)
- return FALSE;
new->name = strdup(hash->name);
- if (!new->name) {
- silc_free(new);
- return FALSE;
- }
- new->oid = strdup(hash->oid);
- if (!new->oid) {
- silc_free(new);
- return FALSE;
- }
new->hash_len = hash->hash_len;
new->block_len = hash->block_len;
new->init = hash->init;
silc_hash_list = silc_dlist_init();
silc_dlist_add(silc_hash_list, new);
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
/* Unregister a hash function from the SILC. */
-SilcBool silc_hash_unregister(SilcHashObject *hash)
+bool silc_hash_unregister(SilcHashObject *hash)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHashObject *entry;
SILC_LOG_DEBUG(("Unregistering hash function"));
if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
silc_dlist_del(silc_hash_list, entry);
silc_free(entry->name);
- silc_free(entry->oid);
silc_free(entry);
if (silc_dlist_count(silc_hash_list) == 0) {
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
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. */
-SilcBool silc_hash_register_default(void)
+bool silc_hash_register_default(void)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
int i;
for (i = 0; silc_default_hash[i].name; i++)
silc_hash_register(&(silc_default_hash[i]));
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
-SilcBool silc_hash_unregister_all(void)
+bool silc_hash_unregister_all(void)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHashObject *entry;
if (!silc_hash_list)
if (!silc_hash_list)
break;
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
/* Allocates a new SilcHash object. New object is returned into new_hash
argument. */
-SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
+bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
{
SilcHashObject *entry = NULL;
+
+ SILC_LOG_DEBUG(("Allocating new hash object"));
- SILC_LOG_DEBUG(("Allocating new hash %s", name));
-
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
if (silc_hash_list) {
silc_dlist_start(silc_hash_list);
while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
}
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
if (entry) {
*new_hash = silc_calloc(1, sizeof(**new_hash));
- if (!(*new_hash))
- return FALSE;
(*new_hash)->hash = entry;
(*new_hash)->context = silc_calloc(1, entry->context_len());
- if (!(*new_hash)->context) {
- silc_free(*new_hash);
- return FALSE;
- }
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* Allocate hash by OID string */
-
-SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
-{
- SilcHashObject *entry = NULL;
-
- SILC_LOG_DEBUG(("Allocating new hash %s", oid));
-
-#ifndef SILC_SYMBIAN
- if (silc_hash_list) {
- silc_dlist_start(silc_hash_list);
- while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
- if (!strcmp(entry->oid, oid))
- break;
- }
- }
-#else
- {
- /* On EPOC which don't have globals we check our constant hash list. */
- int i;
- for (i = 0; silc_default_hash[i].oid; i++) {
- if (!strcmp(silc_default_hash[i].oid, oid)) {
- entry = (SilcHashObject *)&(silc_default_hash[i]);
- break;
- }
- }
- }
-#endif /* SILC_SYMBIAN */
-
- if (entry) {
- *new_hash = silc_calloc(1, sizeof(**new_hash));
- if (!(*new_hash))
- return FALSE;
- (*new_hash)->hash = entry;
- (*new_hash)->context = silc_calloc(1, entry->context_len());
- if (!(*new_hash)->context) {
- silc_free(*new_hash);
- return FALSE;
- }
return TRUE;
}
return hash->hash->name;
}
-/* Returns hash OID string */
-
-const char *silc_hash_get_oid(SilcHash hash)
-{
- return hash->hash->oid;
-}
-
/* Returns TRUE if hash algorithm `name' is supported. */
-SilcBool silc_hash_is_supported(const unsigned char *name)
+bool silc_hash_is_supported(const unsigned char *name)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHashObject *entry;
if (silc_hash_list) {
if (!strcmp(silc_default_hash[i].name, name))
return TRUE;
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return FALSE;
}
char *list = NULL;
int len = 0;
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
if (silc_hash_list) {
silc_dlist_start(silc_hash_list);
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++;
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++;
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
list[len - 1] = 0;
/* 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);
SilcUInt32 data_len)
{
SilcHash new_hash = NULL;
- unsigned char h[32];
+ unsigned char h[SILC_HASH_MAXLEN];
char *ret;
if (!hash) {
- if (!silc_hash_alloc("sha1", &new_hash))
- return NULL;
+ silc_hash_alloc("sha1", &new_hash);
hash = new_hash;
}
{
SilcHash new_hash = NULL;
char *babbleprint;
- unsigned char hval[32];
+ unsigned char hval[SILC_HASH_MAXLEN];
unsigned int a, b, c, d, e, check;
int i, k, out_len;
if (!hash) {
- if (!silc_hash_alloc("sha1", &new_hash))
- return NULL;
+ silc_hash_alloc("sha1", &new_hash);
hash = new_hash;
}
/* Encode babbleprint */
out_len = (((hash->hash->hash_len + 1) / 2) + 1) * 6;
babbleprint = silc_calloc(out_len, sizeof(*babbleprint));
- if (!babbleprint) {
- silc_hash_free(new_hash);
- return NULL;
- }
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];
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;
/*
- silchash.h
+ silchash.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 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
/****s* silccrypt/SilcHashAPI/SilcHash
*
* NAME
- *
+ *
* typedef struct SilcHashStruct *SilcHash;
*
* DESCRIPTION
/****s* silccrypt/SilcHashAPI/SilcHashObject
*
* NAME
- *
+ *
* typedef struct { ... } SilcHashObject;
*
* DESCRIPTION
***/
typedef struct {
char *name;
- char *oid;
- SilcUInt16 hash_len;
- SilcUInt16 block_len;
+ SilcUInt32 hash_len;
+ SilcUInt32 block_len;
void (*init)(void *);
void (*update)(void *, const unsigned char *, SilcUInt32);
*
* SYNOPSIS
*
- * SilcBool silc_hash_register(const SilcHashObject *hash);
+ * bool silc_hash_register(const SilcHashObject *hash);
*
* DESCRIPTION
*
* that are builtin the sources. Returns FALSE on error.
*
***/
-SilcBool silc_hash_register(const SilcHashObject *hash);
+bool silc_hash_register(const SilcHashObject *hash);
/****f* silccrypt/SilcHashAPI/silc_hash_unregister
*
* SYNOPSIS
*
- * SilcBool silc_hash_unregister(SilcHashObject *hash);
+ * bool silc_hash_unregister(SilcHashObject *hash);
*
* DESCRIPTION
*
* FALSE on error.
*
***/
-SilcBool silc_hash_unregister(SilcHashObject *hash);
+bool silc_hash_unregister(SilcHashObject *hash);
/****f* silccrypt/SilcHashAPI/silc_hash_register_default
*
* SYNOPSIS
*
- * SilcBool silc_hash_register_default(void);
+ * bool silc_hash_register_default(void);
*
* DESCRIPTION
*
* which case this function should not be used).
*
***/
-SilcBool silc_hash_register_default(void);
+bool silc_hash_register_default(void);
/****f* silccrypt/SilcHashAPI/silc_hash_unregister_all
*
* SYNOPSIS
*
- * SilcBool silc_hash_unregister_all(void);
+ * bool silc_hash_unregister_all(void);
*
* DESCRIPTION
*
* Unregisters all registered hash functions.
*
***/
-SilcBool silc_hash_unregister_all(void);
+bool silc_hash_unregister_all(void);
/****f* silccrypt/SilcHashAPI/silc_hash_alloc
*
* SYNOPSIS
*
- * SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
+ * bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
*
* DESCRIPTION
*
* returns FALSE if such hash function does not exist.
*
***/
-SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
-
-/****f* silccrypt/SilcHashAPI/silc_hash_alloc_by_oid
- *
- * SYNOPSIS
- *
- * SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash);
- *
- * DESCRIPTION
- *
- * Same as silc_hash_alloc but allocates the hash algorithm by the
- * hash algorithm OID string indicated by `oid'. Returns FALSE if such
- * hash function does not exist.
- *
- ***/
-SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash);
+bool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
/****f* silccrypt/SilcHashAPI/silc_hash_free
*
*
* SYNOPSIS
*
- * SilcBool silc_hash_is_supported(const unsigned char *name);
+ * bool silc_hash_is_supported(const unsigned char *name);
*
* DESCRIPTION
*
* Returns TRUE if the hash function indicated by the `name' exists.
*
***/
-SilcBool silc_hash_is_supported(const unsigned char *name);
+bool silc_hash_is_supported(const unsigned char *name);
/****f* silccrypt/SilcHashAPI/silc_hash_get_supported
*
***/
const char *silc_hash_get_name(SilcHash hash);
-/****f* silccrypt/SilcHashAPI/silc_hash_get_oid
- *
- * SYNOPSIS
- *
- * const char *silc_hash_get_name(SilcHash hash);
- *
- * DESCRIPTION
- *
- * Returns the hash OID string. Returns NULL if the hash doesn't have
- * OID string. Use strlen() to get the OID string length.
- *
- ***/
-const char *silc_hash_get_oid(SilcHash hash);
-
/****f* silccrypt/SilcHashAPI/silc_hash_make
*
* SYNOPSIS
* put them into a buffer and compute the digest from the buffer by
* calling the silc_hash_make, or you can use the silc_hash_init,
* silc_hash_update and silc_hash_final to do the digest. This function
- * prepares the allocated hash function context for this kind of digest
+ * prepares the allocated hash function context for this kind of digest
* computation. To add the data to be used in the digest computation
* call the silc_hash_update function.
*
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2006 Pekka Riikonen
+ Copyright (C) 1999 - 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* HMAC context */
struct SilcHmacStruct {
unsigned int allocated_hash : 1; /* TRUE if the hash was allocated */
};
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
/* List of dynamically registered HMACs. */
SilcDList silc_hmac_list = NULL;
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
/* Default hmacs for silc_hmac_register_default(). */
const SilcHmacObject silc_default_hmacs[] =
/* Registers a new HMAC into the SILC. This function is used at the
initialization of the SILC. */
-SilcBool silc_hmac_register(const SilcHmacObject *hmac)
+bool silc_hmac_register(const SilcHmacObject *hmac)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHmacObject *new;
SILC_LOG_DEBUG(("Registering new HMAC `%s'", hmac->name));
}
new = silc_calloc(1, sizeof(*new));
- if (!new)
- return FALSE;
new->name = strdup(hmac->name);
new->len = hmac->len;
silc_hmac_list = silc_dlist_init();
silc_dlist_add(silc_hmac_list, new);
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
/* Unregister a HMAC from the SILC. */
-SilcBool silc_hmac_unregister(SilcHmacObject *hmac)
+bool silc_hmac_unregister(SilcHmacObject *hmac)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHmacObject *entry;
SILC_LOG_DEBUG(("Unregistering HMAC"));
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return FALSE;
}
The application may use this to register the default hmacs if
specific hmacs in any specific order is not wanted. */
-SilcBool silc_hmac_register_default(void)
+bool silc_hmac_register_default(void)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
int i;
for (i = 0; silc_default_hmacs[i].name; i++)
silc_hmac_register(&(silc_default_hmacs[i]));
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
-SilcBool silc_hmac_unregister_all(void)
+bool silc_hmac_unregister_all(void)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHmacObject *entry;
if (!silc_hmac_list)
if (!silc_hmac_list)
break;
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
of the HMAC. If it is NULL then the hash function is allocated and
the name of the hash algorithm is derived from the `name'. */
-SilcBool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac)
+bool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac)
{
SILC_LOG_DEBUG(("Allocating new HMAC"));
/* Allocate the new object */
*new_hmac = silc_calloc(1, sizeof(**new_hmac));
- if (!(*new_hmac))
- return FALSE;
if (!hash) {
char *tmp = strdup(name), *hname;
(*new_hmac)->hash = hash;
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
if (silc_hmac_list) {
SilcHmacObject *entry;
silc_dlist_start(silc_hmac_list);
}
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
silc_free(*new_hmac);
*new_hmac = NULL;
/* Returns TRUE if HMAC `name' is supported. */
-SilcBool silc_hmac_is_supported(const char *name)
+bool silc_hmac_is_supported(const char *name)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcHmacObject *entry;
if (!name)
if (!strcmp(silc_default_hmacs[i].name, name))
return TRUE;
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return FALSE;
}
char *list = NULL;
int len = 0;
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
if (silc_hmac_list) {
silc_dlist_start(silc_hmac_list);
while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
len++;
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
list[len - 1] = 0;
memset(hmac->key, 0, hmac->key_len);
silc_free(hmac->key);
}
- hmac->key = silc_malloc(key_len);
- if (!hmac->key)
- return;
+ hmac->key = silc_calloc(key_len, sizeof(unsigned char));
hmac->key_len = key_len;
memcpy(hmac->key, key, key_len);
}
-/* Return HMAC key */
-
-const unsigned char *silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len)
-{
- if (key_len)
- *key_len = hmac->key_len;
- return (const unsigned char *)hmac->key;
-}
-
/* Create the HMAC. This is thee make_hmac function pointer. This
uses the internal key set with silc_hmac_set_key. */
/*
- silchmac.h
+ silchmac.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2006 Pekka Riikonen
+ Copyright (C) 1999 - 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
*
* This is the interface for HMAC, or the keyed hash values, that are
* used for packet and message authentication. These routines uses
- * already implemented hash functions from the SilcHashAPI. These
+ * already implemented hash functions from the SilcHashAPI. These
* routines were created according to RFC 2104.
*
***/
/****s* silccrypt/SilcHMACAPI/SilcHmac
*
* NAME
- *
+ *
* typedef struct SilcHmacStruct *SilcHmac;
*
* DESCRIPTION
/****s* silccrypt/SilcHMACAPI/SilcHmacObject
*
* NAME
- *
+ *
* typedef struct { ... } SilcHmacObject;
*
* DESCRIPTION
*
* SYNOPSIS
*
- * SilcBool silc_hmac_register(const SilcHmacObject *hmac);
+ * bool silc_hmac_register(const SilcHmacObject *hmac);
*
* DESCRIPTION
*
* that are builtin the sources. Returns FALSE on error.
*
***/
-SilcBool silc_hmac_register(const SilcHmacObject *hmac);
+bool silc_hmac_register(const SilcHmacObject *hmac);
/****f* silccrypt/SilcHMACAPI/silc_hmac_unregister
*
* SYNOPSIS
*
- * SilcBool silc_hmac_unregister(SilcHmacObject *hmac);
+ * bool silc_hmac_unregister(SilcHmacObject *hmac);
*
* DESCRIPTION
*
* error.
*
***/
-SilcBool silc_hmac_unregister(SilcHmacObject *hmac);
+bool silc_hmac_unregister(SilcHmacObject *hmac);
/****f* silccrypt/SilcHMACAPI/silc_hmac_register_default
*
* SYNOPSIS
*
- * SilcBool silc_hmac_register_default(void);
+ * bool silc_hmac_register_default(void);
*
* DESCRIPTION
*
* used).
*
***/
-SilcBool silc_hmac_register_default(void);
+bool silc_hmac_register_default(void);
/****f* silccrypt/SilcHMACAPI/silc_hmac_unregister_all
*
* SYNOPSIS
*
- * SilcBool silc_hmac_unregister_all(void);
+ * bool silc_hmac_unregister_all(void);
*
* DESCRIPTION
*
* Unregisters all registered HMACs.
*
***/
-SilcBool silc_hmac_unregister_all(void);
+bool silc_hmac_unregister_all(void);
/****f* silccrypt/SilcHMACAPI/silc_hmac_alloc
*
* SYNOPSIS
*
- * SilcBool silc_hmac_alloc(const char *name, SilcHash hash,
+ * bool silc_hmac_alloc(const char *name, SilcHash hash,
* SilcHmac *new_hmac);
*
* DESCRIPTION
* FALSE if such HMAC does not exist.
*
***/
-SilcBool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac);
+bool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac);
/****f* silccrypt/SilcHMACAPI/silc_hmac_free
*
*
* SYNOPSIS
*
- * SilcBool silc_hmac_is_supported(const char *name);
+ * bool silc_hmac_is_supported(const char *name);
*
* DESCRIPTION
*
* Returns TRUE if the HMAC indicated by the `name' exists.
*
***/
-SilcBool silc_hmac_is_supported(const char *name);
+bool silc_hmac_is_supported(const char *name);
/****f* silccrypt/SilcHMACAPI/silc_hmac_get_supported
*
void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
SilcUInt32 key_len);
-/****f* silccrypt/SilcHMACAPI/silc_hmac_get_key
- *
- * SYNOPSIS
- *
- * const unsigned char *
- * silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len);
- *
- * DESCRIPTION
- *
- * Returns the key data from the `hmac' set with silc_hamc_set_key.
- * The caller must not free the returned pointer.
- *
- ***/
-const unsigned char *silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len);
-
/****f* silccrypt/SilcHMACAPI/silc_hmac_make
*
* SYNOPSIS
* DESCRIPTION
*
* Computes a MAC from a data buffer indicated by the `data' of the
- * length of `data_len'. The returned MAC is copied into the
+ * length of `data_len'. The returned MAC is copied into the
* `return_hash' pointer which must be at least the size of the
* value silc_hmac_len returns. The returned length is still
* returned to `return_len'.
* SYNOPSIS
*
* void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
- * SilcUInt32 data_len,
+ * SilcUInt32 data_len,
* unsigned char *key, SilcUInt32 key_len,
* unsigned char *return_hash,
* SilcUInt32 *return_len);
*
***/
void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
- SilcUInt32 data_len,
+ SilcUInt32 data_len,
unsigned char *key, SilcUInt32 key_len,
unsigned char *return_hash,
SilcUInt32 *return_len);
*
* SYNOPSIS
*
- * void silc_hmac_make_truncated(SilcHmac hmac,
- * unsigned char *data,
+ * void silc_hmac_make_truncated(SilcHmac hmac,
+ * unsigned char *data,
* SilcUInt32 data_len,
* SilcUInt32 truncated_len,
* unsigned char *return_hash);
* truncations.
*
***/
-void silc_hmac_make_truncated(SilcHmac hmac,
- unsigned char *data,
+void silc_hmac_make_truncated(SilcHmac hmac,
+ unsigned char *data,
SilcUInt32 data_len,
SilcUInt32 truncated_len,
unsigned char *return_hash);
* put them into a buffer and compute the MAC from the buffer by
* calling the silc_hmac_make, or you can use the silc_hmac_init,
* silc_hmac_update and silc_hmac_final to do the MAC. This function
- * prepares the allocated HMAC context for this kind of MAC
+ * prepares the allocated HMAC context for this kind of MAC
* computation. The caller must have been called the function
* silc_hmac_set_key before calling this function. To add the
* data to be used in the MAC computation call the silc_hmac_update
* DESCRIPTION
*
* This function is used to produce the final MAC from the data
- * that has been added to the HMAC context by calling the
+ * that has been added to the HMAC context by calling the
* silc_hmac_update function. The MAC is copied in to the
* `return_hash' pointer which must be at least the size that
* the silc_hmac_len returns. The length of the MAC is still
+++ /dev/null
-/*
-
- silcpk.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2007 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 "silcpk_i.h"
-
-/****************************** Key generation *******************************/
-
-/* Generate new SILC key pair. */
-
-SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
- SilcUInt32 bits_key_len,
- const char *identifier,
- SilcRng rng,
- SilcPublicKey *ret_public_key,
- SilcPrivateKey *ret_private_key)
-{
- SilcSILCPublicKey pubkey;
- SilcSILCPrivateKey privkey;
- const SilcPKCSAlgorithm *alg;
- const SilcPKCSObject *pkcs;
- SilcUInt32 version;
-
- SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
- algorithm, bits_key_len));
-
- if (!rng)
- return FALSE;
-
- pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
- if (!pkcs)
- return FALSE;
-
- /* Allocate SILC public key */
- pubkey = silc_calloc(1, sizeof(*pubkey));
- if (!pubkey)
- return FALSE;
-
- /* Decode identifier */
- if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
- return FALSE;
-
- if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
- version = 2;
- else
- version = 1;
-
- /* Allocate algorithm */
- alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
- "pkcs1"));
- if (!alg) {
- silc_free(pubkey);
- return FALSE;
- }
- pubkey->pkcs = alg;
-
- /* Allocate SILC private key */
- privkey = silc_calloc(1, sizeof(*privkey));
- if (!privkey) {
- silc_free(pubkey);
- return FALSE;
- }
- privkey->pkcs = alg;
-
- /* Allocate public key */
- *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
- if (!(*ret_public_key)) {
- silc_free(pubkey);
- silc_free(privkey);
- return FALSE;
- }
- (*ret_public_key)->pkcs = pkcs;
- (*ret_public_key)->public_key = pubkey;
-
- /* Allocate private key */
- *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
- if (!(*ret_private_key)) {
- silc_free(pubkey);
- silc_free(privkey);
- silc_free(*ret_public_key);
- return FALSE;
- }
- (*ret_private_key)->pkcs = pkcs;
- (*ret_private_key)->private_key = privkey;
-
- /* Generate the algorithm key pair */
- if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
- &privkey->private_key)) {
- silc_free(pubkey);
- silc_free(privkey);
- silc_free(*ret_public_key);
- silc_free(*ret_private_key);
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/**************************** Utility functions ******************************/
-
-/* Decodes the provided `identifier' */
-
-SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
- SilcPublicKeyIdentifier ident)
-{
- char *cp, *item;
- int len;
-
- /* Protocol says that at least UN and HN must be provided as identifier */
- if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
- SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
- "identifiers"));
- return FALSE;
- }
-
- cp = (char *)identifier;
- while (cp) {
- len = strcspn(cp, ",");
- if (len < 1) {
- cp = NULL;
- break;
- }
- if (len - 1 >= 0 && cp[len - 1] == '\\') {
- while (cp) {
- if (len + 1 > strlen(cp)) {
- cp = NULL;
- break;
- }
- cp += len + 1;
- len = strcspn(cp, ",") + len;
- if (len < 1) {
- cp = NULL;
- break;
- }
- if (len - 1 >= 0 && cp[len - 1] != '\\')
- break;
- }
- }
-
- if (!cp)
- break;
-
- item = silc_calloc(len + 1, sizeof(char));
- if (!item)
- return FALSE;
- if (len > strlen(cp))
- break;
- memcpy(item, cp, len);
-
- if (strstr(item, "UN="))
- ident->username = strdup(item + strcspn(cp, "=") + 1);
- else if (strstr(item, "HN="))
- ident->host = strdup(item + strcspn(cp, "=") + 1);
- else if (strstr(item, "RN="))
- ident->realname = strdup(item + strcspn(cp, "=") + 1);
- else if (strstr(item, "E="))
- ident->email = strdup(item + strcspn(cp, "=") + 1);
- else if (strstr(item, "O="))
- ident->org = strdup(item + strcspn(cp, "=") + 1);
- else if (strstr(item, "C="))
- ident->country = strdup(item + strcspn(cp, "=") + 1);
- else if (strstr(item, "V="))
- ident->version = strdup(item + strcspn(cp, "=") + 1);
-
- cp += len;
- if (strlen(cp) < 1)
- cp = NULL;
- else
- cp += 1;
-
- if (item)
- silc_free(item);
- }
-
- return TRUE;
-}
-
-/* Encodes and returns SILC public key identifier. If some of the
- arguments is NULL those are not encoded into the identifier string.
- Protocol says that at least username and host must be provided. */
-
-char *silc_pkcs_silc_encode_identifier(char *username, char *host,
- char *realname, char *email,
- char *org, char *country,
- char *version)
-{
- SilcBufferStruct buf;
- char *identifier;
-
- if (!username || !host)
- return NULL;
- if (strlen(username) < 3 || strlen(host) < 3)
- return NULL;
-
- memset(&buf, 0, sizeof(buf));
-
- if (username)
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING("UN="),
- SILC_STR_UI32_STRING(username),
- SILC_STR_END);
-
- if (host)
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING(", "),
- SILC_STR_UI32_STRING("HN="),
- SILC_STR_UI32_STRING(host),
- SILC_STR_END);
-
- if (realname)
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING(", "),
- SILC_STR_UI32_STRING("RN="),
- SILC_STR_UI32_STRING(realname),
- SILC_STR_END);
-
- if (email)
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING(", "),
- SILC_STR_UI32_STRING("E="),
- SILC_STR_UI32_STRING(email),
- SILC_STR_END);
-
- if (org)
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING(", "),
- SILC_STR_UI32_STRING("O="),
- SILC_STR_UI32_STRING(org),
- SILC_STR_END);
-
- if (country)
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING(", "),
- SILC_STR_UI32_STRING("C="),
- SILC_STR_UI32_STRING(country),
- SILC_STR_END);
-
- if (version) {
- if (strlen(version) > 1 || !isdigit(version[0])) {
- silc_buffer_purge(&buf);
- return NULL;
- }
- silc_buffer_format(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI32_STRING(", "),
- SILC_STR_UI32_STRING("V="),
- SILC_STR_UI32_STRING(version),
- SILC_STR_END);
- }
-
- silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
-
- identifier = silc_buffer_steal(&buf, NULL);
- return identifier;
-}
-
-/* Return SILC public key version */
-
-int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
-{
- SilcSILCPublicKey silc_pubkey;
-
- if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
- return -1;
-
- silc_pubkey = public_key->public_key;
-
- /* If version identifire is not present it is version 1. */
- if (!silc_pubkey->identifier.version)
- return 1;
-
- return atoi(silc_pubkey->identifier.version);
-}
-
-/*************************** Public key routines *****************************/
-
-/* Returns PKCS algorithm context */
-
-const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
-{
- SilcSILCPublicKey silc_pubkey = public_key;
- return silc_pubkey->pkcs;
-}
-
-/* Imports SILC protocol style public key from SILC public key file */
-
-SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
- SilcUInt32 filedata_len,
- SilcPKCSFileEncoding encoding,
- void **ret_public_key)
-{
- SilcUInt32 i, len;
- unsigned char *data = NULL;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing SILC public key file"));
-
- if (!ret_public_key)
- return FALSE;
-
- /* Check start of file and remove header from the data. */
- len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
- if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))
- return FALSE;
- for (i = 0; i < len; i++) {
- if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
- return FALSE;
- filedata++;
- }
- filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
- strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
-
- switch (encoding) {
- case SILC_PKCS_FILE_BIN:
- break;
-
- case SILC_PKCS_FILE_BASE64:
- data = silc_base64_decode(filedata, filedata_len, &filedata_len);
- if (!data)
- return FALSE;
- filedata = data;
- break;
- }
-
- ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
- ret_public_key);
- silc_free(data);
-
- return ret ? TRUE : FALSE;
-}
-
-/* Imports SILC protocol style public key */
-
-int silc_pkcs_silc_import_public_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_public_key)
-{
- const SilcPKCSAlgorithm *pkcs;
- SilcBufferStruct buf, alg_key;
- SilcSILCPublicKey silc_pubkey = NULL;
- SilcAsn1 asn1 = NULL;
- SilcUInt32 totlen, keydata_len;
- SilcUInt16 pkcs_len, identifier_len;
- unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing SILC public key"));
-
- if (!ret_public_key)
- return 0;
-
- silc_buffer_set(&buf, key, key_len);
-
- /* Get length */
- ret = silc_buffer_unformat(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI_INT(&totlen),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- /* Backwards compatibility */
- if (totlen == key_len)
- totlen -= 4;
-
- if (totlen + 4 != key_len)
- goto err;
-
- /* Get algorithm name and identifier */
- ret =
- silc_buffer_unformat(&buf,
- SILC_STR_ADVANCE,
- SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
- SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- if (pkcs_len < 1 || identifier_len < 3 ||
- pkcs_len + identifier_len > totlen)
- goto err;
-
- /* Get key data */
- keydata_len = silc_buffer_len(&buf);
- ret = silc_buffer_unformat(&buf,
- SILC_STR_DATA(&key_data, keydata_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- /* Allocate SILC public key context */
- silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
- if (!silc_pubkey)
- goto err;
-
- /* Decode SILC identifier */
- if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
- goto err;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- goto err;
-
- SILC_LOG_DEBUG(("Public key version %s",
- (!silc_pubkey->identifier.version ? " 1" :
- silc_pubkey->identifier.version)));
-
- if (!strcmp(pkcs_name, "rsa")) {
- /* Parse the SILC RSA public key */
- SilcUInt32 e_len, n_len;
- SilcMPInt n, e;
-
- /* Get PKCS object. Different PKCS #1 scheme is used with different
- versions. */
- if (!silc_pubkey->identifier.version ||
- atoi(silc_pubkey->identifier.version) <= 1) {
- /* Version 1 */
- pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
- } else {
- /* Version 2 and newer */
- pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
- }
- if (!pkcs) {
- SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
- goto err;
- }
- silc_pubkey->pkcs = pkcs;
-
- if (keydata_len < 4)
- goto err;
- SILC_GET32_MSB(e_len, key_data);
- if (!e_len || e_len + 4 > keydata_len)
- goto err;
- silc_mp_init(&e);
- silc_mp_bin2mp(key_data + 4, e_len, &e);
- if (keydata_len < 4 + e_len + 4) {
- silc_mp_uninit(&e);
- goto err;
- }
- SILC_GET32_MSB(n_len, key_data + 4 + e_len);
- if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
- silc_mp_uninit(&e);
- goto err;
- }
- silc_mp_init(&n);
- silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
-
- /* Encode to PKCS #1 format */
- memset(&alg_key, 0, sizeof(alg_key));
- if (!silc_asn1_encode(asn1, &alg_key,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_INT(&n),
- SILC_ASN1_INT(&e),
- SILC_ASN1_END, SILC_ASN1_END)) {
- silc_mp_uninit(&e);
- silc_mp_uninit(&n);
- goto err;
- }
-
- silc_mp_uninit(&e);
- silc_mp_uninit(&n);
-
- } else if (!strcmp(pkcs_name, "dsa")) {
- SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
- goto err;
-
- } else {
- SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
- goto err;
- }
-
- /* Import PKCS algorithm public key */
- if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
- &silc_pubkey->public_key))
- goto err;
-
- silc_free(pkcs_name);
- silc_free(ident);
- silc_asn1_free(asn1);
-
- *ret_public_key = silc_pubkey;
-
- return key_len;
-
- err:
- silc_free(pkcs_name);
- silc_free(ident);
- silc_free(silc_pubkey);
- if (asn1)
- silc_asn1_free(asn1);
- return 0;
-}
-
-/* Exports public key as SILC protocol style public key file */
-
-unsigned char *
-silc_pkcs_silc_export_public_key_file(void *public_key,
- SilcPKCSFileEncoding encoding,
- SilcUInt32 *ret_len)
-{
- SilcBuffer buf;
- unsigned char *key, *data;
- SilcUInt32 key_len;
-
- SILC_LOG_DEBUG(("Encoding SILC public key file"));
-
- /* Export key */
- key = silc_pkcs_silc_export_public_key(public_key, &key_len);
- if (!key)
- return NULL;
-
- switch (encoding) {
- case SILC_PKCS_FILE_BIN:
- break;
-
- case SILC_PKCS_FILE_BASE64:
- data = silc_base64_encode_file(key, key_len);
- if (!data)
- return NULL;
- silc_free(key);
- key = data;
- key_len = strlen(data);
- break;
- }
-
- /* Encode SILC public key file */
- buf = silc_buffer_alloc_size(key_len +
- (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
- strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
- if (!buf) {
- silc_free(key);
- return NULL;
- }
-
- if (silc_buffer_format(buf,
- SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
- SILC_STR_UI_XNSTRING(key, key_len),
- SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
- SILC_STR_END) < 0) {
- silc_buffer_free(buf);
- silc_free(key);
- return NULL;
- }
-
- silc_free(key);
- key = silc_buffer_steal(buf, ret_len);
- silc_buffer_free(buf);
-
- return key;
-}
-
-/* Exports public key as SILC protocol style public key */
-
-unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
- SilcUInt32 *ret_len)
-{
- SilcSILCPublicKey silc_pubkey = public_key;
- const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
- SilcBufferStruct alg_key;
- SilcBuffer buf = NULL;
- SilcAsn1 asn1 = NULL;
- unsigned char *pk = NULL, *key = NULL, *ret;
- SilcUInt32 pk_len, key_len, totlen;
- char *identifier;
-
- SILC_LOG_DEBUG(("Encoding SILC public key"));
-
- /* Export PKCS algorithm public key */
- if (pkcs->export_public_key)
- pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
- if (!pk)
- return NULL;
- silc_buffer_set(&alg_key, pk, pk_len);
-
- /* Encode identifier */
- identifier =
- silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
- silc_pubkey->identifier.host,
- silc_pubkey->identifier.realname,
- silc_pubkey->identifier.email,
- silc_pubkey->identifier.org,
- silc_pubkey->identifier.country,
- silc_pubkey->identifier.version);
- if (!identifier)
- goto err;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- goto err;
-
- if (!strcmp(pkcs->name, "rsa")) {
- /* Parse the PKCS #1 public key */
- SilcMPInt n, e;
- SilcUInt32 n_len, e_len;
- unsigned char *nb, *eb;
-
- memset(&n, 0, sizeof(n));
- memset(&e, 0, sizeof(e));
- if (!silc_asn1_decode(asn1, &alg_key,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_INT(&n),
- SILC_ASN1_INT(&e),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- /* Encode to SILC RSA public key */
- eb = silc_mp_mp2bin(&e, 0, &e_len);
- if (!eb)
- goto err;
- nb = silc_mp_mp2bin(&n, 0, &n_len);
- if (!nb)
- goto err;
- key_len = e_len + 4 + n_len + 4;
- key = silc_calloc(key_len, sizeof(*key));
- if (!key)
- goto err;
-
- /* Put e length and e */
- SILC_PUT32_MSB(e_len, key);
- memcpy(key + 4, eb, e_len);
-
- /* Put n length and n. */
- SILC_PUT32_MSB(n_len, key + 4 + e_len);
- memcpy(key + 4 + e_len + 4, nb, n_len);
-
- silc_free(nb);
- silc_free(eb);
-
- } else if (!strcmp(pkcs->name, "dsa")) {
- SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
- goto err;
-
- } else {
- SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
- goto err;
- }
-
- /* Encode SILC Public Key */
- totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
- buf = silc_buffer_alloc_size(totlen + 4);
- if (!buf)
- goto err;
- if (silc_buffer_format(buf,
- SILC_STR_UI_INT(totlen),
- SILC_STR_UI_SHORT(strlen(pkcs->name)),
- SILC_STR_UI32_STRING(pkcs->name),
- SILC_STR_UI_SHORT(strlen(identifier)),
- SILC_STR_UI32_STRING(identifier),
- SILC_STR_UI_XNSTRING(key, key_len),
- SILC_STR_END) < 0)
- goto err;
-
- ret = silc_buffer_steal(buf, ret_len);
- silc_buffer_free(buf);
- silc_free(key);
- silc_free(identifier);
- silc_buffer_purge(&alg_key);
- silc_asn1_free(asn1);
-
- return ret;
-
- err:
- silc_free(identifier);
- silc_free(pk);
- silc_free(key);
- if (buf)
- silc_buffer_free(buf);
- if (asn1)
- silc_asn1_free(asn1);
- return NULL;
-}
-
-/* Return key length */
-
-SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
-{
- SilcSILCPublicKey silc_pubkey = public_key;
- return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
-}
-
-/* Copy public key */
-
-void *silc_pkcs_silc_public_key_copy(void *public_key)
-{
- SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
-
- new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
- if (!new_pubkey)
- return NULL;
- new_pubkey->pkcs = silc_pubkey->pkcs;
-
- new_pubkey->public_key =
- silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
- if (!new_pubkey->public_key) {
- silc_free(new_pubkey);
- return NULL;
- }
-
- return new_pubkey;
-}
-
-/* Compares public keys */
-
-SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
-{
- SilcSILCPublicKey k1 = key1, k2 = key2;
-
- if (strcmp(k1->pkcs->name, k2->pkcs->name))
- return FALSE;
-
- if ((k1->identifier.username && !k2->identifier.username) ||
- (!k1->identifier.username && k2->identifier.username) ||
- (k1->identifier.username && k2->identifier.username &&
- strcmp(k1->identifier.username, k2->identifier.username)))
- return FALSE;
-
- if ((k1->identifier.host && !k2->identifier.host) ||
- (!k1->identifier.host && k2->identifier.host) ||
- (k1->identifier.host && k2->identifier.host &&
- strcmp(k1->identifier.host, k2->identifier.host)))
- return FALSE;
-
- if ((k1->identifier.realname && !k2->identifier.realname) ||
- (!k1->identifier.realname && k2->identifier.realname) ||
- (k1->identifier.realname && k2->identifier.realname &&
- strcmp(k1->identifier.realname, k2->identifier.realname)))
- return FALSE;
-
- if ((k1->identifier.email && !k2->identifier.email) ||
- (!k1->identifier.email && k2->identifier.email) ||
- (k1->identifier.email && k2->identifier.email &&
- strcmp(k1->identifier.email, k2->identifier.email)))
- return FALSE;
-
- if ((k1->identifier.org && !k2->identifier.org) ||
- (!k1->identifier.org && k2->identifier.org) ||
- (k1->identifier.org && k2->identifier.org &&
- strcmp(k1->identifier.org, k2->identifier.org)))
- return FALSE;
-
- if ((k1->identifier.country && !k2->identifier.country) ||
- (!k1->identifier.country && k2->identifier.country) ||
- (k1->identifier.country && k2->identifier.country &&
- strcmp(k1->identifier.country, k2->identifier.country)))
- return FALSE;
-
- if ((k1->identifier.version && !k2->identifier.version) ||
- (!k1->identifier.version && k2->identifier.version) ||
- (k1->identifier.version && k2->identifier.version &&
- strcmp(k1->identifier.version, k2->identifier.version)))
- return FALSE;
-
- return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
-}
-
-/* Frees public key */
-
-void silc_pkcs_silc_public_key_free(void *public_key)
-{
- SilcSILCPublicKey silc_pubkey = public_key;
-
- silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
-
- silc_free(silc_pubkey->identifier.username);
- silc_free(silc_pubkey->identifier.host);
- silc_free(silc_pubkey->identifier.realname);
- silc_free(silc_pubkey->identifier.email);
- silc_free(silc_pubkey->identifier.org);
- silc_free(silc_pubkey->identifier.country);
- silc_free(silc_pubkey->identifier.version);
- silc_free(silc_pubkey);
-}
-
-
-/*************************** Private key routines ****************************/
-
-/* Private key file magic */
-#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
-
-/* Imports SILC implementation style private key file */
-
-SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
- SilcUInt32 filedata_len,
- const char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- void **ret_private_key)
-{
- SilcCipher aes;
- SilcHash sha1;
- SilcHmac sha1hmac;
- SilcUInt32 blocklen;
- unsigned char tmp[32], keymat[64], *data = NULL;
- SilcUInt32 i, len, magic, mac_len;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing SILC private key file"));
-
- /* Check start of file and remove header from the data. */
- len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
- if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
- return FALSE;
- for (i = 0; i < len; i++) {
- if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
- return FALSE;
- filedata++;
- }
-
- len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
- strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
-
- switch (encoding) {
- case SILC_PKCS_FILE_BIN:
- break;
-
- case SILC_PKCS_FILE_BASE64:
- data = silc_base64_decode(filedata, filedata_len, &len);
- if (!data)
- return FALSE;
- filedata = data;
- break;
- }
-
- memset(tmp, 0, sizeof(tmp));
- memset(keymat, 0, sizeof(keymat));
-
- /* Check file magic */
- SILC_GET32_MSB(magic, filedata);
- if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
- SILC_LOG_DEBUG(("Private key does not have correct magic"));
- return FALSE;
- }
-
- /* Allocate the AES cipher */
- if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
- SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
- return FALSE;
- }
- blocklen = silc_cipher_get_block_len(aes);
- if (blocklen * 2 > sizeof(tmp)) {
- silc_cipher_free(aes);
- return FALSE;
- }
-
- /* Allocate SHA1 hash */
- if (!silc_hash_alloc("sha1", &sha1)) {
- SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
- silc_cipher_free(aes);
- return FALSE;
- }
-
- /* Allocate HMAC */
- if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
- SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
- silc_hash_free(sha1);
- silc_cipher_free(aes);
- return FALSE;
- }
-
- /* Derive the decryption key from the provided key material. The key
- is 256 bits length, and derived by taking hash of the data, then
- re-hashing the data and the previous digest, and using the first and
- second digest as the key. */
- silc_hash_init(sha1);
- silc_hash_update(sha1, passphrase, passphrase_len);
- silc_hash_final(sha1, keymat);
- silc_hash_init(sha1);
- silc_hash_update(sha1, passphrase, passphrase_len);
- silc_hash_update(sha1, keymat, 16);
- silc_hash_final(sha1, keymat + 16);
-
- /* Set the key to the cipher */
- silc_cipher_set_key(aes, keymat, 256, FALSE);
-
- /* First, verify the MAC of the private key data */
- mac_len = silc_hmac_len(sha1hmac);
- silc_hmac_init_with_key(sha1hmac, keymat, 16);
- silc_hmac_update(sha1hmac, filedata, len - mac_len);
- silc_hmac_final(sha1hmac, tmp, NULL);
- if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
- SILC_LOG_DEBUG(("Integrity check for private key failed"));
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(sha1);
- silc_cipher_free(aes);
- return FALSE;
- }
- filedata += 4;
- len -= 4;
-
- /* Decrypt the private key buffer */
- silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
- SILC_GET32_MSB(i, filedata);
- if (i > len) {
- SILC_LOG_DEBUG(("Bad private key length in buffer!"));
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(sha1);
- silc_cipher_free(aes);
- return FALSE;
- }
- filedata += 4;
- len = i;
-
- /* Cleanup */
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(sha1);
- silc_cipher_free(aes);
-
- /* Import the private key */
- ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
-
- silc_free(data);
-
- return ret ? TRUE : FALSE;
-}
-
-/* Private key version */
-#define SILC_PRIVATE_KEY_VERSION_1 0x82171273
-#define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
-
-/* Imports SILC implementation style private key */
-
-int silc_pkcs_silc_import_private_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_private_key)
-{
- SilcBufferStruct buf;
- const SilcPKCSAlgorithm *pkcs;
- SilcBufferStruct alg_key;
- SilcSILCPrivateKey silc_privkey = NULL;
- SilcAsn1 asn1 = NULL;
- SilcUInt16 pkcs_len;
- SilcUInt32 keydata_len;
- unsigned char *pkcs_name = NULL, *key_data;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing SILC private key"));
-
- if (!ret_private_key)
- return 0;
-
- silc_buffer_set(&buf, key, key_len);
-
- /* Get algorithm name and identifier */
- ret =
- silc_buffer_unformat(&buf,
- SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
- SILC_STR_END);
- if (ret == -1) {
- SILC_LOG_DEBUG(("Cannot decode private key buffer"));
- goto err;
- }
-
- if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
- SILC_LOG_DEBUG(("Malformed private key buffer"));
- goto err;
- }
-
- /* Get key data. We assume that rest of the buffer is key data. */
- silc_buffer_pull(&buf, 2 + pkcs_len);
- keydata_len = silc_buffer_len(&buf);
- ret = silc_buffer_unformat(&buf,
- SILC_STR_UI_XNSTRING(&key_data, keydata_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- /* Allocate SILC private key context */
- silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
- if (!silc_privkey)
- goto err;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- goto err;
-
- if (!strcmp(pkcs_name, "rsa")) {
- /* Parse the RSA SILC private key */
- SilcBufferStruct k;
- SilcMPInt n, e, d, dp, dq, qp, p, q;
- unsigned char *tmp;
- SilcUInt32 len, ver;
-
- if (keydata_len < 4)
- goto err;
- silc_buffer_set(&k, key_data, keydata_len);
-
- /* Get version. Key without the version is old style private key
- and we need to do some computation to get it to correct format. */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&ver),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
-
- if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
- ver != SILC_PRIVATE_KEY_VERSION_2) {
- len = ver;
- ver = 0;
- } else {
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- }
-
- /* Get PKCS object. Different PKCS #1 scheme is used with different
- versions. */
- if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
- /* Version 0 and 1 */
- pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
- } else {
- /* Version 2 and newer */
- pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
- }
- if (!pkcs) {
- SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
- goto err;
- }
- silc_privkey->pkcs = pkcs;
-
- SILC_LOG_DEBUG(("Private key version %s",
- (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
- ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
-
- /* Get e */
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&e);
- silc_mp_bin2mp(tmp, len, &e);
- silc_buffer_pull(&k, len);
-
- /* Get n */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&n);
- silc_mp_bin2mp(tmp, len, &n);
- silc_buffer_pull(&k, len);
-
- /* Get d */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&d);
- silc_mp_bin2mp(tmp, len, &d);
- silc_buffer_pull(&k, len);
-
- /* Get dP */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&dp);
- silc_mp_bin2mp(tmp, len, &dp);
- silc_buffer_pull(&k, len);
-
- /* Get dQ */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&dq);
- silc_mp_bin2mp(tmp, len, &dq);
- silc_buffer_pull(&k, len);
-
- if (ver == 0) {
- /* Old version */
-
- /* Get pQ len */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_len(&k) < len)
- goto err;
- silc_buffer_pull(&k, len);
-
- /* Get qP len */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_len(&k) < len)
- goto err;
- silc_buffer_pull(&k, len);
- } else {
- /* New version */
-
- /* Get qP */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&qp);
- silc_mp_bin2mp(tmp, len, &qp);
- silc_buffer_pull(&k, len);
- }
-
- /* Get p */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&p);
- silc_mp_bin2mp(tmp, len, &p);
- silc_buffer_pull(&k, len);
-
- /* Get q */
- if (silc_buffer_unformat(&k,
- SILC_STR_UI_INT(&len),
- SILC_STR_END) < 0)
- goto err;
- silc_buffer_pull(&k, 4);
- if (silc_buffer_unformat(&k,
- SILC_STR_DATA(&tmp, len),
- SILC_STR_END) < 0)
- goto err;
- silc_mp_init(&q);
- silc_mp_bin2mp(tmp, len, &q);
- silc_buffer_pull(&k, len);
-
- if (ver == 0) {
- /* Old version. Compute to new version */
- SILC_LOG_DEBUG(("Old version private key"));
- silc_mp_init(&qp);
- silc_mp_modinv(&qp, &q, &p);
- }
-
- /* Encode to PKCS #1 format */
- memset(&alg_key, 0, sizeof(alg_key));
- if (!silc_asn1_encode(asn1, &alg_key,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SHORT_INT(0),
- SILC_ASN1_INT(&n),
- SILC_ASN1_INT(&e),
- SILC_ASN1_INT(&d),
- SILC_ASN1_INT(&p),
- SILC_ASN1_INT(&q),
- SILC_ASN1_INT(&dp),
- SILC_ASN1_INT(&dq),
- SILC_ASN1_INT(&qp),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- silc_mp_uninit(&n);
- silc_mp_uninit(&e);
- silc_mp_uninit(&e);
- silc_mp_uninit(&d);
- silc_mp_uninit(&p);
- silc_mp_uninit(&q);
- silc_mp_uninit(&dp);
- silc_mp_uninit(&dq);
- silc_mp_uninit(&qp);
-
- } else if (!strcmp(pkcs_name, "dsa")) {
- SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
- goto err;
-
- } else {
- SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
- goto err;
- }
-
- /* Import PKCS algorithm private key */
- if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
- &silc_privkey->private_key))
- goto err;
-
- silc_free(pkcs_name);
- silc_asn1_free(asn1);
-
- *ret_private_key = silc_privkey;
-
- return key_len;
-
- err:
- silc_free(pkcs_name);
- silc_free(silc_privkey);
- if (asn1)
- silc_asn1_free(asn1);
- return 0;
-}
-
-/* Exports private key as SILC implementation style private key file */
-
-unsigned char *
-silc_pkcs_silc_export_private_key_file(void *private_key,
- const char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- SilcRng rng,
- SilcUInt32 *ret_len)
-{
- SilcCipher aes;
- SilcHash sha1;
- SilcHmac sha1hmac;
- SilcBuffer buf, enc;
- SilcUInt32 len, blocklen, padlen, key_len;
- unsigned char *key, *data;
- unsigned char tmp[32], keymat[64];
- int i;
-
- SILC_LOG_DEBUG(("Encoding SILC private key file"));
-
- /* Export the private key */
- key = silc_pkcs_silc_export_private_key(private_key, &key_len);
- if (!key)
- return NULL;
-
- memset(tmp, 0, sizeof(tmp));
- memset(keymat, 0, sizeof(keymat));
-
- /* Allocate the AES cipher */
- if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
- SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
- silc_free(key);
- return NULL;
- }
- blocklen = silc_cipher_get_block_len(aes);
- if (blocklen * 2 > sizeof(tmp)) {
- silc_cipher_free(aes);
- silc_free(key);
- return NULL;
- }
-
- /* Allocate SHA1 hash */
- if (!silc_hash_alloc("sha1", &sha1)) {
- SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
- silc_cipher_free(aes);
- return NULL;
- }
-
- /* Allocate HMAC */
- if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
- SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
- silc_hash_free(sha1);
- silc_cipher_free(aes);
- return NULL;
- }
-
- /* Derive the encryption key from the provided key material. The key
- is 256 bits length, and derived by taking hash of the data, then
- re-hashing the data and the previous digest, and using the first and
- second digest as the key. */
- silc_hash_init(sha1);
- silc_hash_update(sha1, passphrase, passphrase_len);
- silc_hash_final(sha1, keymat);
- silc_hash_init(sha1);
- silc_hash_update(sha1, passphrase, passphrase_len);
- silc_hash_update(sha1, keymat, 16);
- silc_hash_final(sha1, keymat + 16);
-
- /* Set the key to the cipher */
- silc_cipher_set_key(aes, keymat, 256, TRUE);
-
- /* Encode the buffer to be encrypted. Add padding to it too, at least
- block size of the cipher. */
-
- /* Allocate buffer for encryption */
- len = silc_hmac_len(sha1hmac);
- padlen = 16 + (16 - ((key_len + 4) % blocklen));
- enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
- if (!enc) {
- silc_hmac_free(sha1hmac);
- silc_hash_free(sha1);
- silc_cipher_free(aes);
- return FALSE;
- }
-
- /* Generate padding */
- for (i = 0; i < padlen; i++)
- tmp[i] = silc_rng_get_byte_fast(rng);
-
- /* Put magic number */
- SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
- silc_buffer_pull(enc, 4);
-
- /* Encode the buffer */
- silc_buffer_format(enc,
- SILC_STR_UI_INT(key_len),
- SILC_STR_UI_XNSTRING(key, key_len),
- SILC_STR_UI_XNSTRING(tmp, padlen),
- SILC_STR_END);
- silc_free(key);
-
- /* Encrypt. */
- silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
- silc_cipher_get_iv(aes));
-
- silc_buffer_push(enc, 4);
-
- /* Compute HMAC over the encrypted data and append the MAC to data.
- The key is the first digest of the original key material. */
- key_len = silc_buffer_len(enc) - len;
- silc_hmac_init_with_key(sha1hmac, keymat, 16);
- silc_hmac_update(sha1hmac, enc->data, key_len);
- silc_buffer_pull(enc, key_len);
- silc_hmac_final(sha1hmac, enc->data, NULL);
- silc_buffer_push(enc, key_len);
-
- /* Cleanup */
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(sha1);
- silc_cipher_free(aes);
-
- switch (encoding) {
- case SILC_PKCS_FILE_BIN:
- break;
-
- case SILC_PKCS_FILE_BASE64:
- data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
- if (!data) {
- silc_buffer_clear(enc);
- silc_buffer_free(enc);
- return NULL;
- }
- silc_free(silc_buffer_steal(enc, NULL));
- silc_buffer_set(enc, data, strlen(data));
- break;
- }
-
- key = enc->data;
- key_len = silc_buffer_len(enc);
-
- /* Encode the data and save to file */
- len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
- strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
- buf = silc_buffer_alloc_size(len);
- if (!buf) {
- silc_buffer_free(enc);
- return NULL;
- }
- silc_buffer_format(buf,
- SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
- SILC_STR_UI_XNSTRING(key, key_len),
- SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
- SILC_STR_END);
-
- silc_buffer_free(enc);
- data = silc_buffer_steal(buf, ret_len);
- silc_buffer_free(buf);
-
- return data;
-}
-
-/* Exports private key as SILC implementation style private key */
-
-unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
- SilcUInt32 *ret_len)
-{
- SilcSILCPrivateKey silc_privkey = private_key;
- const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
- SilcBufferStruct alg_key;
- SilcBuffer buf = NULL;
- SilcAsn1 asn1 = NULL;
- unsigned char *prv = NULL, *key = NULL, *ret;
- SilcUInt32 prv_len, key_len, totlen;
-
- SILC_LOG_DEBUG(("Encoding SILC private key"));
-
- /* Export PKCS algorithm private key */
- if (pkcs->export_private_key)
- prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
- if (!prv)
- return NULL;
- silc_buffer_set(&alg_key, prv, prv_len);
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- goto err;
-
- if (!strcmp(pkcs->name, "rsa")) {
- /* Parse the PKCS #1 private key */
- SilcMPInt n, e, d, dp, dq, qp, p, q;
- SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
- qp_len, p_len, q_len, len = 0;
- unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
-
- if (!silc_asn1_decode(asn1, &alg_key,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_INT(NULL),
- SILC_ASN1_INT(&n),
- SILC_ASN1_INT(&e),
- SILC_ASN1_INT(&d),
- SILC_ASN1_INT(&p),
- SILC_ASN1_INT(&q),
- SILC_ASN1_INT(&dp),
- SILC_ASN1_INT(&dq),
- SILC_ASN1_INT(&qp),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- /* Encode to SILC RSA private key */
- eb = silc_mp_mp2bin(&e, 0, &e_len);
- nb = silc_mp_mp2bin(&n, 0, &n_len);
- db = silc_mp_mp2bin(&d, 0, &d_len);
- dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
- dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
- qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
- pb = silc_mp_mp2bin(&p, 0, &p_len);
- qb = silc_mp_mp2bin(&q, 0, &q_len);
- len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
- dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
-
- buf = silc_buffer_alloc_size(len);
- if (!buf)
- goto err;
- if (silc_buffer_format(buf,
- SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
- SILC_STR_UI_INT(e_len),
- SILC_STR_UI_XNSTRING(eb, e_len),
- SILC_STR_UI_INT(n_len),
- SILC_STR_UI_XNSTRING(nb, n_len),
- SILC_STR_UI_INT(d_len),
- SILC_STR_UI_XNSTRING(db, d_len),
- SILC_STR_UI_INT(dp_len),
- SILC_STR_UI_XNSTRING(dpb, dp_len),
- SILC_STR_UI_INT(dq_len),
- SILC_STR_UI_XNSTRING(dqb, dq_len),
- SILC_STR_UI_INT(qp_len),
- SILC_STR_UI_XNSTRING(qpb, qp_len),
- SILC_STR_UI_INT(p_len),
- SILC_STR_UI_XNSTRING(pb, p_len),
- SILC_STR_UI_INT(q_len),
- SILC_STR_UI_XNSTRING(qb, q_len),
- SILC_STR_END) < 0)
- goto err;
-
- key = silc_buffer_steal(buf, &key_len);
- silc_buffer_free(buf);
- silc_free(nb);
- silc_free(eb);
- silc_free(db);
- silc_free(dpb);
- silc_free(dqb);
- silc_free(qpb);
- silc_free(pb);
- silc_free(qb);
-
- } else if (!strcmp(pkcs->name, "dsa")) {
- SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
- goto err;
-
- } else {
- SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
- goto err;
- }
-
- /* Encode SILC private key */
- totlen = 2 + strlen(pkcs->name) + key_len;
- buf = silc_buffer_alloc_size(totlen);
- if (!buf)
- goto err;
- if (silc_buffer_format(buf,
- SILC_STR_UI_SHORT(strlen(pkcs->name)),
- SILC_STR_UI32_STRING(pkcs->name),
- SILC_STR_UI_XNSTRING(key, key_len),
- SILC_STR_END) < 0)
- goto err;
-
- ret = silc_buffer_steal(buf, ret_len);
- silc_buffer_free(buf);
- silc_free(prv);
- silc_free(key);
- silc_asn1_free(asn1);
-
- return ret;
-
- err:
- silc_free(prv);
- silc_free(key);
- if (buf)
- silc_buffer_free(buf);
- return NULL;
-}
-
-/* Return key length */
-
-SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
-{
- SilcSILCPrivateKey silc_privkey = private_key;
- return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
-}
-
-/* Frees private key */
-
-void silc_pkcs_silc_private_key_free(void *private_key)
-{
- SilcSILCPrivateKey silc_privkey = private_key;
-
- silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
-
- silc_free(silc_privkey);
-}
-
-
-/***************************** PKCS operations ******************************/
-
-/* Encrypts as specified in SILC protocol specification */
-
-SilcBool silc_pkcs_silc_encrypt(void *public_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len,
- SilcRng rng)
-{
- SilcSILCPublicKey silc_pubkey = public_key;
-
- if (!silc_pubkey->pkcs->encrypt)
- return FALSE;
-
- return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
- src, src_len,
- dst, dst_size, ret_dst_len, rng);
-}
-
-/* Decrypts as specified in SILC protocol specification */
-
-SilcBool silc_pkcs_silc_decrypt(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len)
-{
- SilcSILCPrivateKey silc_privkey = private_key;
-
- if (!silc_privkey->pkcs->decrypt)
- return FALSE;
-
- return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
- src, src_len,
- dst, dst_size, ret_dst_len);
-}
-
-/* Signs as specified in SILC protocol specification */
-
-SilcBool silc_pkcs_silc_sign(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash)
-{
- SilcSILCPrivateKey silc_privkey = private_key;
-
- if (!silc_privkey->pkcs->sign)
- return FALSE;
-
- return silc_privkey->pkcs->sign(silc_privkey->private_key,
- src, src_len,
- signature, signature_size,
- ret_signature_len, compute_hash, hash);
-}
-
-/* Verifies as specified in SILC protocol specification */
-
-SilcBool silc_pkcs_silc_verify(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash)
-{
- SilcSILCPublicKey silc_pubkey = public_key;
-
- if (!silc_pubkey->pkcs->verify)
- return FALSE;
-
- return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
- signature, signature_len,
- data, data_len, hash);
-}
+++ /dev/null
-/*
-
- silcpk.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2007 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* silccrypt/SILC Public Key Interface
- *
- * DESCRIPTION
- *
- * This interface implements the SILC protocol style public key, as defined
- * by the SILC protocol specification.
- *
- ***/
-
-#ifndef SILCPK_H
-#define SILCPK_H
-
-/****s* silccrypt/SilcPubkeyAPI/SilcPublicKeyIdentifier
- *
- * NAME
- *
- * typedef struct { ... } *SilcPublicKeyIdentifier,
- * SilcPublicKeyIdentifierStruct;
- *
- * DESCRIPTION
- *
- * This structure contains the SILC Public Key identifier. Note that
- * some of the fields may be NULL.
- *
- * SOURCE
- */
-typedef struct {
- char *username;
- char *host;
- char *realname;
- char *email;
- char *org;
- char *country;
- char *version;
-} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
-/***/
-
-/****s* silccrypt/SilcPubkeyAPI/SilcSILCPublicKey
- *
- * NAME
- *
- * typedef struct { ... } *SilcSILCPublicKey;
- *
- * DESCRIPTION
- *
- * This structure defines the SILC protocol style public key. User
- * doesn't have to access this structure usually, except when access to
- * the identifier is required. The silc_pkcs_get_context for the
- * PKCS type SILC_PKCS_SILC returns this context.
- *
- * SOURCE
- */
-typedef struct {
- SilcPublicKeyIdentifierStruct identifier;
- const SilcPKCSAlgorithm *pkcs; /* PKCS algorithm */
- void *public_key; /* PKCS algorithm specific public key */
-} *SilcSILCPublicKey;
-/***/
-
-/****s* silccrypt/SilcPubkeyAPI/SilcSILCPrivateKey
- *
- * NAME
- *
- * typedef struct { ... } *SilcSILCPrivateKey;
- *
- * DESCRIPTION
- *
- * This structure defines the SILC protocol implementation specific
- * private key. This structure isn't usually needed by the user.
- *
- * SOURCE
- */
-typedef struct {
- const SilcPKCSAlgorithm *pkcs; /* PKCS algorithm */
- void *private_key; /* PKCS algorithm specific private key */
-} *SilcSILCPrivateKey;
-/***/
-
-/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_generate_key
- *
- * SYNOPSIS
- *
- * SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
- * SilcUInt32 bits_key_len,
- * const char *identifier,
- * SilcRng rng,
- * SilcPublicKey *ret_public_key,
- * SilcPrivateKey *ret_private_key)
- *
- * DESCRIPTION
- *
- * Generate a new SILC key pair of the algorithm type `algorithm' with
- * the key length in bits of `bits_key_len'. The `scheme' may be NULL.
- * Returns FALSE if key generation failed.
- *
- * EXAMPLE
- *
- * // Generate RSA key pair with 2048 bit key length, using PKCS #1
- * // no OID scheme.
- * silc_pkcs_silc_generate_key("rsa", 2048, rng, &public_key, &private_key);
- *
- ***/
-SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
- SilcUInt32 bits_key_len,
- const char *identifier,
- SilcRng rng,
- SilcPublicKey *ret_public_key,
- SilcPrivateKey *ret_private_key);
-
-/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_encode_identifier
- *
- * SYNOPSIS
- *
- * char *silc_pkcs_silc_encode_identifier(char *username, char *host,
- * char *realname, char *email,
- * char *org, char *country,
- * char *version);
- *
- * DESCRIPTION
- *
- * Encodes and returns SILC public key identifier. If some of the
- * arguments are NULL those are not encoded into the identifier string.
- * Protocol says that at least username and host must be provided.
- * Caller must free the returned identifier string.
- *
- ***/
-char *silc_pkcs_silc_encode_identifier(char *username, char *host,
- char *realname, char *email,
- char *org, char *country,
- char *version);
-
-/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier
- *
- * SYNOPSIS
- *
- * SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
- * SilcPublicKeyIdentifier ident);
- *
- * DESCRIPTION
- *
- * Decodes SILC protocol public key identifier `identifier' into the
- * the `ident' structure. Returns FALSE if the identifier is not valid
- * identifier string.
- *
- ***/
-SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
- SilcPublicKeyIdentifier ident);
-
-/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_public_key_version
- *
- * SYNOPSIS
- *
- * int silc_pkcs_silc_public_key_version(SilcPublicKey public_key);
- *
- * DESCRIPTION
- *
- * Returns the verison of the SILC Public Key indicated by `public_key'.
- * Returns -1 if the `public_key' is not a SILC Public Key and the
- * version number otherwise.
- *
- ***/
-int silc_pkcs_silc_public_key_version(SilcPublicKey public_key);
-
-#endif /* SILCPK_H */
+++ /dev/null
-/*
-
- silcpk_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005, 2007 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 SILCPK_I_H
-#define SILCPK_I_H
-
-/* Public and private key file headers */
-#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
-#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
-#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
-#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
-
-const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key);
-SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
- SilcUInt32 filedata_len,
- SilcPKCSFileEncoding encoding,
- void **ret_public_key);
-int silc_pkcs_silc_import_public_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_public_key);
-unsigned char *
-silc_pkcs_silc_export_public_key_file(void *public_key,
- SilcPKCSFileEncoding encoding,
- SilcUInt32 *ret_len);
-unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
- SilcUInt32 *ret_len);
-SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key);
-void *silc_pkcs_silc_public_key_copy(void *public_key);
-SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2);
-void silc_pkcs_silc_public_key_free(void *public_key);
-SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
- SilcUInt32 filedata_len,
- const char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- void **ret_private_key);
-int silc_pkcs_silc_import_private_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_private_key);
-unsigned char *
-silc_pkcs_silc_export_private_key_file(void *private_key,
- const char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- SilcRng rng,
- SilcUInt32 *ret_len);
-unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
- SilcUInt32 *ret_len);
-SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key);
-void silc_pkcs_silc_private_key_free(void *private_key);
-SilcBool silc_pkcs_silc_encrypt(void *public_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len,
- SilcRng rng);
-SilcBool silc_pkcs_silc_decrypt(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len);
-SilcBool silc_pkcs_silc_sign(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash);
-SilcBool silc_pkcs_silc_verify(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash);
-
-#endif /* SILCPK_I_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2003 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
*/
/* $Id$ */
-#include "silc.h"
-#include "silcpk_i.h"
-#include "silcpkcs1_i.h"
+#include "silcincludes.h"
-#ifndef SILC_SYMBIAN
+#include "rsa.h"
+
+/* The main SILC PKCS structure. */
+struct SilcPKCSStruct {
+ void *context; /* Algorithm internal context */
+ SilcPKCSObject *pkcs; /* Algorithm implementation */
+ SilcUInt32 key_len; /* Key length in bits */
+};
+
+#ifndef SILC_EPOC
/* Dynamically registered list of PKCS. */
SilcDList silc_pkcs_list = NULL;
-SilcDList silc_pkcs_alg_list = NULL;
#define SILC_PKCS_LIST silc_pkcs_list
-#define SILC_PKCS_ALG_LIST silc_pkcs_alg_list
#else
#define SILC_PKCS_LIST TRUE
-#define SILC_PKCS_ALG_LIST TRUE
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
/* Static list of PKCS for silc_pkcs_register_default(). */
const SilcPKCSObject silc_default_pkcs[] =
{
- /* SILC PKCS */
- {
- SILC_PKCS_SILC,
- silc_pkcs_silc_get_algorithm,
- silc_pkcs_silc_import_public_key_file,
- silc_pkcs_silc_import_public_key,
- silc_pkcs_silc_export_public_key_file,
- silc_pkcs_silc_export_public_key,
- silc_pkcs_silc_public_key_bitlen,
- silc_pkcs_silc_public_key_copy,
- silc_pkcs_silc_public_key_compare,
- silc_pkcs_silc_public_key_free,
- silc_pkcs_silc_import_private_key_file,
- silc_pkcs_silc_import_private_key,
- silc_pkcs_silc_export_private_key_file,
- silc_pkcs_silc_export_private_key,
- silc_pkcs_silc_private_key_bitlen,
- silc_pkcs_silc_private_key_free,
- silc_pkcs_silc_encrypt,
- silc_pkcs_silc_decrypt,
- silc_pkcs_silc_sign,
- silc_pkcs_silc_verify,
- },
-
- {
- 0, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL
- }
+ /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
+ { "rsa",
+ silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
+ silc_rsa_get_private_key, silc_rsa_set_public_key,
+ silc_rsa_set_private_key, silc_rsa_context_len,
+ silc_pkcs1_encrypt, silc_pkcs1_decrypt,
+ silc_pkcs1_sign, silc_pkcs1_verify },
+
+ /* Raw RSA operations */
+ { "rsa-raw",
+ silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
+ silc_rsa_get_private_key, silc_rsa_set_public_key,
+ silc_rsa_set_private_key, silc_rsa_context_len,
+ silc_rsa_encrypt, silc_rsa_decrypt,
+ silc_rsa_sign, silc_rsa_verify },
+
+ { NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL }
};
-/* Builtin PKCS algorithms */
-const SilcPKCSAlgorithm silc_default_pkcs_alg[] =
-{
- /* PKCS #1, Version 1.5 without hash OIDs */
- {
- "rsa",
- "pkcs1-no-oid",
- "sha1,md5",
- silc_pkcs1_generate_key,
- silc_pkcs1_import_public_key,
- silc_pkcs1_export_public_key,
- silc_pkcs1_public_key_bitlen,
- silc_pkcs1_public_key_copy,
- silc_pkcs1_public_key_compare,
- silc_pkcs1_public_key_free,
- silc_pkcs1_import_private_key,
- silc_pkcs1_export_private_key,
- silc_pkcs1_private_key_bitlen,
- silc_pkcs1_private_key_free,
- silc_pkcs1_encrypt,
- silc_pkcs1_decrypt,
- silc_pkcs1_sign_no_oid,
- silc_pkcs1_verify_no_oid
- },
-
- /* PKCS #1, Version 1.5 */
- {
- "rsa",
- "pkcs1",
- "sha1,md5",
- silc_pkcs1_generate_key,
- silc_pkcs1_import_public_key,
- silc_pkcs1_export_public_key,
- silc_pkcs1_public_key_bitlen,
- silc_pkcs1_public_key_copy,
- silc_pkcs1_public_key_compare,
- silc_pkcs1_public_key_free,
- silc_pkcs1_import_private_key,
- silc_pkcs1_export_private_key,
- silc_pkcs1_private_key_bitlen,
- silc_pkcs1_private_key_free,
- silc_pkcs1_encrypt,
- silc_pkcs1_decrypt,
- silc_pkcs1_sign,
- silc_pkcs1_verify
- },
+/* Register a new PKCS into SILC. This is used at the initialization of
+ the SILC. */
- {
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL
- }
-};
-
-/* Register a new PKCS into SILC. */
-
-SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs)
+bool silc_pkcs_register(const SilcPKCSObject *pkcs)
{
-#ifndef SILC_SYMBIAN
- SilcPKCSObject *newpkcs;
+#ifndef SILC_EPOC
+ SilcPKCSObject *new;
- SILC_LOG_DEBUG(("Registering new PKCS"));
+ SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
/* Check if exists already */
if (silc_pkcs_list) {
SilcPKCSObject *entry;
silc_dlist_start(silc_pkcs_list);
while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
- if (entry->type == pkcs->type)
+ if (!strcmp(entry->name, pkcs->name))
return FALSE;
}
}
- newpkcs = silc_calloc(1, sizeof(*newpkcs));
- if (!newpkcs)
- return FALSE;
- *newpkcs = *pkcs;
+ new = silc_calloc(1, sizeof(*new));
+ new->name = strdup(pkcs->name);
+ new->init = pkcs->init;
+ new->clear_keys = pkcs->clear_keys;
+ new->get_public_key = pkcs->get_public_key;
+ new->get_private_key = pkcs->get_private_key;
+ new->set_public_key = pkcs->set_public_key;
+ new->set_private_key = pkcs->set_private_key;
+ new->context_len = pkcs->context_len;
+ new->encrypt = pkcs->encrypt;
+ new->decrypt = pkcs->decrypt;
+ new->sign = pkcs->sign;
+ new->verify = pkcs->verify;
/* Add to list */
if (silc_pkcs_list == NULL)
silc_pkcs_list = silc_dlist_init();
- silc_dlist_add(silc_pkcs_list, newpkcs);
+ silc_dlist_add(silc_pkcs_list, new);
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return TRUE;
}
/* Unregister a PKCS from the SILC. */
-SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs)
+bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcPKCSObject *entry;
SILC_LOG_DEBUG(("Unregistering PKCS"));
while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
silc_dlist_del(silc_pkcs_list, entry);
+ silc_free(entry->name);
silc_free(entry);
if (silc_dlist_count(silc_pkcs_list) == 0) {
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
return FALSE;
}
-/* Register algorithm */
+/* Function that registers all the default PKCS (all builtin PKCS).
+ The application may use this to register the default PKCS if specific
+ PKCS in any specific order is not wanted. */
-SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs)
+bool silc_pkcs_register_default(void)
{
-#ifndef SILC_SYMBIAN
- SilcPKCSAlgorithm *newalg;
+#ifndef SILC_EPOC
+ int i;
- SILC_LOG_DEBUG(("Registering new PKCS algorithm %s",
- pkcs->name));
+ for (i = 0; silc_default_pkcs[i].name; i++)
+ silc_pkcs_register(&(silc_default_pkcs[i]));
- /* Check if exists already */
- if (silc_pkcs_alg_list) {
- SilcPKCSAlgorithm *entry;
- silc_dlist_start(silc_pkcs_alg_list);
- while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
- if (!strcmp(entry->name, pkcs->name) &&
- entry->scheme && pkcs->scheme &&
- !strcmp(entry->scheme, pkcs->scheme))
- return FALSE;
- }
- }
+#endif /* SILC_EPOC */
+ return TRUE;
+}
- newalg = silc_calloc(1, sizeof(*newalg));
- if (!newalg)
- return FALSE;
+bool silc_pkcs_unregister_all(void)
+{
+#ifndef SILC_EPOC
+ SilcPKCSObject *entry;
- *newalg = *pkcs;
- newalg->name = strdup(pkcs->name);
- if (!newalg->name)
- return FALSE;
- if (pkcs->scheme) {
- newalg->scheme = strdup(pkcs->scheme);
- if (!newalg->scheme)
- return FALSE;
- }
- newalg->hash = strdup(pkcs->hash);
- if (!newalg->hash)
+ if (!silc_pkcs_list)
return FALSE;
- /* Add to list */
- if (silc_pkcs_alg_list == NULL)
- silc_pkcs_alg_list = silc_dlist_init();
- silc_dlist_add(silc_pkcs_alg_list, newalg);
-
-#endif /* SILC_SYMBIAN */
+ silc_dlist_start(silc_pkcs_list);
+ while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
+ silc_pkcs_unregister(entry);
+ if (!silc_pkcs_list)
+ break;
+ }
+#endif /* SILC_EPOC */
return TRUE;
}
-/* Unregister algorithm */
+/* Allocates a new SilcPKCS object. The new allocated object is returned
+ to the 'new_pkcs' argument. */
-SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs)
+bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
{
-#ifndef SILC_SYMBIAN
- SilcPKCSAlgorithm*entry;
+ SilcPKCSObject *entry = NULL;
- SILC_LOG_DEBUG(("Unregistering PKCS algorithm"));
+ SILC_LOG_DEBUG(("Allocating new PKCS object"));
- if (!silc_pkcs_alg_list)
- return FALSE;
-
- silc_dlist_start(silc_pkcs_alg_list);
- while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
- if (pkcs == SILC_ALL_PKCS_ALG || entry == pkcs) {
- silc_dlist_del(silc_pkcs_alg_list, entry);
- silc_free(entry->name);
- silc_free(entry->scheme);
- silc_free(entry->hash);
- silc_free(entry);
-
- if (silc_dlist_count(silc_pkcs_alg_list) == 0) {
- silc_dlist_uninit(silc_pkcs_alg_list);
- silc_pkcs_alg_list = NULL;
+#ifndef SILC_EPOC
+ if (silc_pkcs_list) {
+ silc_dlist_start(silc_pkcs_list);
+ while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
+ if (!strcmp(entry->name, name))
+ break;
+ }
+ }
+#else
+ {
+ /* On EPOC which don't have globals we check our constant hash list. */
+ int i;
+ for (i = 0; silc_default_pkcs[i].name; i++) {
+ if (!strcmp(silc_default_pkcs[i].name, name)) {
+ entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
+ break;
}
-
- return TRUE;
}
}
+#endif /* SILC_EPOC */
+
+ if (entry) {
+ *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
+ (*new_pkcs)->pkcs = entry;
+ (*new_pkcs)->context = silc_calloc(1, entry->context_len());
+ return TRUE;
+ }
-#endif /* SILC_SYMBIAN */
return FALSE;
}
-/* Function that registers all the default PKCS and PKCS algorithms. */
+/* Free's the PKCS object */
-SilcBool silc_pkcs_register_default(void)
+void silc_pkcs_free(SilcPKCS pkcs)
{
-#ifndef SILC_SYMBIAN
- int i;
-
- for (i = 0; silc_default_pkcs[i].type; i++)
- silc_pkcs_register(&(silc_default_pkcs[i]));
-
- for (i = 0; silc_default_pkcs_alg[i].name; i++)
- silc_pkcs_algorithm_register(&(silc_default_pkcs_alg[i]));
-
-#endif /* SILC_SYMBIAN */
- return TRUE;
+ if (pkcs) {
+ pkcs->pkcs->clear_keys(pkcs->context);
+ silc_free(pkcs->context);
+ }
+ silc_free(pkcs);
}
-SilcBool silc_pkcs_unregister_all(void)
+/* Return TRUE if PKCS algorithm `name' is supported. */
+
+bool silc_pkcs_is_supported(const unsigned char *name)
{
-#ifndef SILC_SYMBIAN
+#ifndef SILC_EPOC
SilcPKCSObject *entry;
- SilcPKCSAlgorithm *alg;
if (silc_pkcs_list) {
silc_dlist_start(silc_pkcs_list);
while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
- silc_pkcs_unregister(entry);
- if (!silc_pkcs_list)
- break;
+ if (!strcmp(entry->name, name))
+ return TRUE;
}
}
-
- if (silc_pkcs_alg_list) {
- silc_dlist_start(silc_pkcs_alg_list);
- while ((alg = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
- silc_pkcs_algorithm_unregister(alg);
- if (!silc_pkcs_alg_list)
- break;
- }
+#else
+ {
+ int i;
+ for (i = 0; silc_default_pkcs[i].name; i++)
+ if (!strcmp(silc_default_pkcs[i].name, name))
+ return TRUE;
}
-
-#endif /* SILC_SYMBIAN */
- return TRUE;
+#endif /* SILC_EPOC */
+ return FALSE;
}
/* Returns comma separated list of supported PKCS algorithms */
char *silc_pkcs_get_supported(void)
{
- SilcPKCSAlgorithm *entry;
+ SilcPKCSObject *entry;
char *list = NULL;
int len = 0;
-#ifndef SILC_SYMBIAN
- if (silc_pkcs_alg_list) {
- silc_dlist_start(silc_pkcs_alg_list);
- while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
+#ifndef SILC_EPOC
+ if (silc_pkcs_list) {
+ silc_dlist_start(silc_pkcs_list);
+ while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
len += strlen(entry->name);
list = silc_realloc(list, len + 1);
- if (!list)
- return NULL;
memcpy(list + (len - strlen(entry->name)),
entry->name, strlen(entry->name));
#else
{
int i;
- for (i = 0; silc_default_pkcs_alg[i].name; i++) {
- entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
+ for (i = 0; silc_default_pkcs[i].name; i++) {
+ entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
len += strlen(entry->name);
list = silc_realloc(list, len + 1);
- if (!list)
- return NULL;
memcpy(list + (len - strlen(entry->name)),
entry->name, strlen(entry->name));
len++;
}
}
-#endif /* SILC_SYMBIAN */
+#endif /* SILC_EPOC */
list[len - 1] = 0;
return list;
}
-/* Finds PKCS object */
+/* Generate new key pair into the `pkcs' context. */
-const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
+bool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
+ SilcRng rng)
{
- SilcPKCSObject *entry;
+ bool ret = pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
+ if (ret)
+ pkcs->key_len = bits_key_len;
+ return ret;
+}
-#ifndef SILC_SYMBIAN
- if (silc_pkcs_list) {
- silc_dlist_start(silc_pkcs_list);
- while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
- if (entry->type == type)
- return (const SilcPKCSObject *)entry;
- }
- }
-#else
- {
- int i;
- for (i = 0; silc_default_pkcs[i].type; i++) {
- entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
- if (entry->type == type)
- return (const SilcPKCSObject *)entry;
- }
- }
-#endif /* SILC_SYMBIAN */
+/* Returns the length of the key */
- return NULL;
+SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
+{
+ return pkcs->key_len;
}
-/* Finds PKCS algorithms object */
-
-const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
- const char *scheme)
+const char *silc_pkcs_get_name(SilcPKCS pkcs)
{
- SilcPKCSAlgorithm *entry;
+ return pkcs->pkcs->name;
+}
-#ifndef SILC_SYMBIAN
- if (silc_pkcs_alg_list) {
- silc_dlist_start(silc_pkcs_alg_list);
- while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
- if (!strcmp(entry->name, algorithm) &&
- (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
- return (const SilcPKCSAlgorithm *)entry;
- }
- }
-#else
- {
- int i;
- for (i = 0; silc_default_pkcs_alg[i].name; i++) {
- entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
- if (!strcmp(entry->name, algorithm) &&
- (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
- return (const SilcPKCSAlgorithm *)entry;
- }
- }
-#endif /* SILC_SYMBIAN */
+/* Returns SILC style public key */
- return NULL;
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
+{
+ return pkcs->pkcs->get_public_key(pkcs->context, len);
}
-/* Returns PKCS context */
+/* Returns SILC style private key */
-const SilcPKCSObject *silc_pkcs_get_pkcs(void *key)
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
{
- SilcPublicKey public_key = key;
- return public_key->pkcs;
+ return pkcs->pkcs->get_private_key(pkcs->context, len);
}
-/* Returns PKCS algorithm context */
+/* Sets public key from SilcPublicKey. */
-const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key)
+SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
{
- SilcPublicKey public_key = key;
- return public_key->pkcs->get_algorithm(public_key->public_key);
+ pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
+ public_key->pk_len);
+ return pkcs->key_len;
}
-/* Return algorithm name */
+/* Sets public key from data. */
-const char *silc_pkcs_get_name(void *key)
+SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
+ SilcUInt32 pk_len)
{
- const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(key);
- return pkcs->name;
+ pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
+ return pkcs->key_len;
}
-/* Returns PKCS type */
+/* Sets private key from SilcPrivateKey. */
-SilcPKCSType silc_pkcs_get_type(void *key)
+SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
{
- SilcPublicKey public_key = key;
- return public_key->pkcs->type;
+ SilcUInt32 key_len;
+ key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
+ private_key->prv_len);
+ if (!pkcs->key_len)
+ pkcs->key_len = key_len;
+ return pkcs->key_len;
}
-/* Allocates new public key from the key data */
+/* Sets private key from data. */
-SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
- unsigned char *key,
- SilcUInt32 key_len,
- SilcPublicKey *ret_public_key)
+SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
+ SilcUInt32 prv_len)
{
- const SilcPKCSObject *pkcs;
- SilcPublicKey public_key;
+ SilcUInt32 key_len;
+ key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
+ if (!pkcs->key_len)
+ pkcs->key_len = key_len;
+ return pkcs->key_len;
+}
- if (!ret_public_key)
- return FALSE;
+/* Encrypts */
- /* Allocate public key context */
- public_key = silc_calloc(1, sizeof(*public_key));
- if (!public_key)
- return FALSE;
+bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len)
+{
+ return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
+}
- public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
- if (!public_key->pkcs) {
- silc_free(public_key);
- return FALSE;
- }
+/* Decrypts */
- /* Import the PKCS public key */
- if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
- silc_free(public_key);
- return FALSE;
- }
+bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len)
+{
+ return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
+}
- *ret_public_key = public_key;
+/* Generates signature */
- return TRUE;
+bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len)
+{
+ return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
}
-/* Frees the public key */
+/* Verifies signature */
-void silc_pkcs_public_key_free(SilcPublicKey public_key)
+bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
+ SilcUInt32 signature_len, unsigned char *data,
+ SilcUInt32 data_len)
{
- public_key->pkcs->public_key_free(public_key->public_key);
- silc_free(public_key);
+ return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
+ data, data_len);
}
-/* Exports public key */
+/* Generates signature with hash. The hash is signed. */
-unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
- SilcUInt32 *ret_len)
+bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
+ unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len)
{
- return public_key->pkcs->export_public_key(public_key->public_key,
- ret_len);
+ unsigned char hashr[SILC_HASH_MAXLEN];
+ SilcUInt32 hash_len;
+ int ret;
+
+ silc_hash_make(hash, src, src_len, hashr);
+ hash_len = silc_hash_len(hash);
+
+ SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
+
+ ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
+ memset(hashr, 0, sizeof(hashr));
+
+ return ret;
}
-/* Return key length */
+/* Verifies signature with hash. The `data' is hashed and verified against
+ the `signature'. */
-SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
+bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
+ unsigned char *signature,
+ SilcUInt32 signature_len,
+ unsigned char *data,
+ SilcUInt32 data_len)
{
- return public_key->pkcs->public_key_bitlen(public_key->public_key);
+ unsigned char hashr[SILC_HASH_MAXLEN];
+ SilcUInt32 hash_len;
+ int ret;
+
+ silc_hash_make(hash, data, data_len, hashr);
+ hash_len = silc_hash_len(hash);
+
+ SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
+
+ ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
+ hashr, hash_len);
+ memset(hashr, 0, sizeof(hashr));
+
+ return ret;
}
-/* Returns internal PKCS public key context */
+/* Encodes and returns SILC public key identifier. If some of the
+ arguments is NULL those are not encoded into the identifier string.
+ Protocol says that at least username and host must be provided. */
-void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
+char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
+ char *email, char *org, char *country)
{
- if (public_key->pkcs->type != type)
- return FALSE;
- return public_key->public_key;
+ SilcBuffer buf;
+ char *identifier;
+ SilcUInt32 len, tlen = 0;
+
+ if (!username || !host)
+ return NULL;
+
+ len = (username ? strlen(username) : 0) +
+ (host ? strlen(host) : 0) +
+ (realname ? strlen(realname) : 0) +
+ (email ? strlen(email) : 0) +
+ (org ? strlen(org) : 0) +
+ (country ? strlen(country) : 0);
+
+ if (len < 3)
+ return NULL;
+
+ len += 3 + 5 + 5 + 4 + 4 + 4;
+ buf = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(buf, len);
+
+ if (username) {
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING("UN="),
+ SILC_STR_UI32_STRING(username),
+ SILC_STR_END);
+ silc_buffer_pull(buf, 3 + strlen(username));
+ tlen = 3 + strlen(username);
+ }
+
+ if (host) {
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(", "),
+ SILC_STR_UI32_STRING("HN="),
+ SILC_STR_UI32_STRING(host),
+ SILC_STR_END);
+ silc_buffer_pull(buf, 5 + strlen(host));
+ tlen += 5 + strlen(host);
+ }
+
+ if (realname) {
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(", "),
+ SILC_STR_UI32_STRING("RN="),
+ SILC_STR_UI32_STRING(realname),
+ SILC_STR_END);
+ silc_buffer_pull(buf, 5 + strlen(realname));
+ tlen += 5 + strlen(realname);
+ }
+
+ if (email) {
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(", "),
+ SILC_STR_UI32_STRING("E="),
+ SILC_STR_UI32_STRING(email),
+ SILC_STR_END);
+ silc_buffer_pull(buf, 4 + strlen(email));
+ tlen += 4 + strlen(email);
+ }
+
+ if (org) {
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(", "),
+ SILC_STR_UI32_STRING("O="),
+ SILC_STR_UI32_STRING(org),
+ SILC_STR_END);
+ silc_buffer_pull(buf, 4 + strlen(org));
+ tlen += 4 + strlen(org);
+ }
+
+ if (country) {
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(", "),
+ SILC_STR_UI32_STRING("C="),
+ SILC_STR_UI32_STRING(country),
+ SILC_STR_END);
+ silc_buffer_pull(buf, 4 + strlen(country));
+ tlen += 4 + strlen(country);
+ }
+
+ silc_buffer_push(buf, buf->data - buf->head);
+ identifier = silc_calloc(tlen + 1, sizeof(*identifier));
+ memcpy(identifier, buf->data, tlen);
+ silc_buffer_free(buf);
+
+ return identifier;
}
+/* Decodes the provided `identifier' and returns allocated context for
+ the identifier. */
-/* Allocates new private key from key data */
+SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
+{
+ SilcPublicKeyIdentifier ident;
+ char *cp, *item;
+ int len;
+
+ ident = silc_calloc(1, sizeof(*ident));
+
+ cp = identifier;
+ while (cp) {
+ len = strcspn(cp, ",");
+ if (len < 1) {
+ cp = NULL;
+ break;
+ }
+ if (len - 1 >= 0 && cp[len - 1] == '\\') {
+ while (cp) {
+ if (len + 1 > strlen(cp)) {
+ cp = NULL;
+ break;
+ }
+ cp += len + 1;
+ len = strcspn(cp, ",") + len;
+ if (len < 1) {
+ cp = NULL;
+ break;
+ }
+ if (len - 1 >= 0 && cp[len - 1] != '\\')
+ break;
+ }
+ }
-SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
- unsigned char *key,
- SilcUInt32 key_len,
- SilcPrivateKey *ret_private_key)
+ if (!cp)
+ break;
+
+ item = silc_calloc(len + 1, sizeof(char));
+ if (len > strlen(cp))
+ break;
+ memcpy(item, cp, len);
+
+ if (strstr(item, "UN="))
+ ident->username = strdup(item + strcspn(cp, "=") + 1);
+ else if (strstr(item, "HN="))
+ ident->host = strdup(item + strcspn(cp, "=") + 1);
+ else if (strstr(item, "RN="))
+ ident->realname = strdup(item + strcspn(cp, "=") + 1);
+ else if (strstr(item, "E="))
+ ident->email = strdup(item + strcspn(cp, "=") + 1);
+ else if (strstr(item, "O="))
+ ident->org = strdup(item + strcspn(cp, "=") + 1);
+ else if (strstr(item, "C="))
+ ident->country = strdup(item + strcspn(cp, "=") + 1);
+
+ cp += len;
+ if (strlen(cp) < 1)
+ cp = NULL;
+ else
+ cp += 1;
+
+ if (item)
+ silc_free(item);
+ }
+
+ return ident;
+}
+
+/* Free's decoded public key identifier context. Call this to free the
+ context returned by the silc_pkcs_decode_identifier. */
+
+void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
{
- const SilcPKCSObject *pkcs;
- SilcPrivateKey private_key;
+ silc_free(identifier->username);
+ silc_free(identifier->host);
+ silc_free(identifier->realname);
+ silc_free(identifier->email);
+ silc_free(identifier->org);
+ silc_free(identifier->country);
+ silc_free(identifier);
+}
- if (!ret_private_key)
- return FALSE;
+/* Allocates SILC style public key formed from sent arguments. All data
+ is duplicated. */
- /* Allocate private key context */
- private_key = silc_calloc(1, sizeof(*private_key));
- if (!private_key)
- return FALSE;
+SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
+ const char *identifier,
+ const unsigned char *pk,
+ SilcUInt32 pk_len)
+{
+ SilcPublicKey public_key;
+ char *tmp = NULL;
- private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
- if (!private_key->pkcs) {
- silc_free(private_key);
- return FALSE;
+ public_key = silc_calloc(1, sizeof(*public_key));
+ public_key->name = strdup(name);
+ public_key->pk_len = pk_len;
+ public_key->pk = silc_memdup(pk, pk_len);
+ public_key->pk_type = SILC_SKE_PK_TYPE_SILC;
+
+ if (!silc_utf8_valid(identifier, strlen(identifier))) {
+ int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
+ tmp = silc_calloc(len + 1, sizeof(*tmp));
+ silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
+ identifier = tmp;
}
- /* Import the PKCS private key */
- if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) {
- silc_free(private_key);
- return FALSE;
- }
+ public_key->identifier = strdup(identifier);
+ public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
+ silc_free(tmp);
- *ret_private_key = private_key;
+ return public_key;
+}
- return TRUE;
+/* Free's public key */
+
+void silc_pkcs_public_key_free(SilcPublicKey public_key)
+{
+ if (public_key) {
+ silc_free(public_key->name);
+ silc_free(public_key->identifier);
+ silc_free(public_key->pk);
+ silc_free(public_key);
+ }
}
-/* Return key length */
+/* Allocates SILC private key formed from sent arguments. All data is
+ duplicated. */
-SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
+SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
+ const unsigned char *prv,
+ SilcUInt32 prv_len)
{
- return private_key->pkcs->private_key_bitlen(private_key->private_key);
+ SilcPrivateKey private_key;
+
+ private_key = silc_calloc(1, sizeof(*private_key));
+ private_key->name = strdup(name);
+ private_key->prv_len = prv_len;
+ private_key->prv = silc_memdup(prv, prv_len);
+
+ return private_key;
}
-/* Frees the private key */
+/* Free's private key */
void silc_pkcs_private_key_free(SilcPrivateKey private_key)
{
- private_key->pkcs->private_key_free(private_key->private_key);
- silc_free(private_key);
+ if (private_key) {
+ silc_free(private_key->name);
+ if (private_key->prv) {
+ memset(private_key->prv, 0, private_key->prv_len);
+ silc_free(private_key->prv);
+ }
+ silc_free(private_key);
+ }
}
-/* Encrypts */
+/* Encodes SILC style public key from SilcPublicKey. Returns the encoded
+ data. */
-SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
- unsigned char *src, SilcUInt32 src_len,
- unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len, SilcRng rng)
+unsigned char *
+silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
{
- return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
- dst, dst_size, dst_len, rng);
+ return silc_pkcs_public_key_data_encode(public_key->pk,
+ public_key->pk_len,
+ public_key->name,
+ public_key->identifier, len);
}
-/* Decrypts */
+/* Encodes SILC style public key. Returns the encoded data. */
-SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
- unsigned char *src, SilcUInt32 src_len,
- unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len)
+unsigned char *
+silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
+ char *pkcs, char *identifier,
+ SilcUInt32 *len)
{
- return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
- dst, dst_size, dst_len);
+ SilcBuffer buf;
+ unsigned char *ret;
+ SilcUInt32 totlen;
+
+ totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
+ buf = silc_buffer_alloc_size(totlen + 4);
+ if (!buf)
+ return NULL;
+
+ silc_buffer_format(buf,
+ SILC_STR_UI_INT(totlen),
+ SILC_STR_UI_SHORT(strlen(pkcs)),
+ SILC_STR_UI32_STRING(pkcs),
+ SILC_STR_UI_SHORT(strlen(identifier)),
+ SILC_STR_UI32_STRING(identifier),
+ SILC_STR_UI_XNSTRING(pk, pk_len),
+ SILC_STR_END);
+
+ ret = silc_buffer_steal(buf, len);
+ silc_buffer_free(buf);
+ return ret;
}
-/* Generates signature */
+/* Decodes SILC style public key. Returns TRUE if the decoding was
+ successful. Allocates new public key as well. */
-SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
- unsigned char *src, SilcUInt32 src_len,
- unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len, SilcBool compute_hash,
- SilcHash hash)
+bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
+ SilcPublicKey *public_key)
{
- return private_key->pkcs->sign(private_key->private_key, src, src_len,
- dst, dst_size, dst_len, compute_hash, hash);
+ SilcBufferStruct buf;
+ SilcPKCS alg;
+ SilcUInt16 pkcs_len, identifier_len;
+ SilcUInt32 totlen, key_len;
+ unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
+ int ret;
+
+ silc_buffer_set(&buf, data, data_len);
+
+ /* Get length */
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&totlen),
+ SILC_STR_END);
+ if (ret == -1)
+ return FALSE;
+
+#if 1 /* Backwards support, remove! */
+ if (totlen == data_len)
+ totlen -= 4;
+#endif
+
+ if (totlen + 4 != data_len)
+ return FALSE;
+
+ /* Get algorithm name and identifier */
+ silc_buffer_pull(&buf, 4);
+ ret =
+ silc_buffer_unformat(&buf,
+ SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
+ SILC_STR_END);
+ if (ret == -1)
+ goto err;
+
+ if (pkcs_len < 1 || identifier_len < 3 ||
+ pkcs_len + identifier_len > totlen)
+ goto err;
+
+ /* See if we support this algorithm (check only if PKCS are registered) */
+ if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
+ SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
+ goto err;
+ }
+
+ /* Protocol says that at least UN and HN must be provided as identifier,
+ check for these. */
+ if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
+ SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
+ "identifiers"));
+ goto err;
+ }
+
+ /* Get key data. We assume that rest of the buffer is key data. */
+ silc_buffer_pull(&buf, 2 + pkcs_len + 2 + identifier_len);
+ key_len = buf.len;
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
+ SILC_STR_END);
+ if (ret == -1)
+ goto err;
+
+ /* Try to set the key. If this fails the key must be malformed. This
+ code assumes that the PKCS routine checks the format of the key.
+ (check only if PKCS are registered) */
+ if (SILC_PKCS_LIST) {
+ silc_pkcs_alloc(pkcs_name, &alg);
+ if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
+ goto err;
+ silc_pkcs_free(alg);
+ }
+
+ if (public_key) {
+ *public_key = silc_calloc(1, sizeof(**public_key));
+ (*public_key)->len = totlen;
+ (*public_key)->name = pkcs_name;
+ (*public_key)->identifier = ident;
+ (*public_key)->pk = key_data;
+ (*public_key)->pk_len = key_len;
+ (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
+ }
+
+ return TRUE;
+
+ err:
+ silc_free(pkcs_name);
+ silc_free(ident);
+ silc_free(key_data);
+ return FALSE;
}
-/* Verifies signature */
+/* Encodes Public Key Payload for transmitting public keys and certificates. */
+
+SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key)
+{
+ SilcBuffer buffer;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+
+ if (!public_key)
+ return NULL;
+
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+ if (!pk)
+ return NULL;
+
+ buffer = silc_buffer_alloc_size(4 + pk_len);
+ if (!buffer) {
+ silc_free(pk);
+ return NULL;
+ }
+
+ silc_buffer_format(buffer,
+ SILC_STR_UI_SHORT(pk_len),
+ SILC_STR_UI_SHORT(public_key->pk_type),
+ SILC_STR_UI_XNSTRING(pk, pk_len),
+ SILC_STR_END);
+
+ silc_free(pk);
+ return buffer;
+}
+
+/* Decode Public Key Payload and decodes the public key inside it to
+ to `payload'. */
-SilcBool silc_pkcs_verify(SilcPublicKey public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len, SilcHash hash)
+bool silc_pkcs_public_key_payload_decode(unsigned char *data,
+ SilcUInt32 data_len,
+ SilcPublicKey *public_key)
{
- return public_key->pkcs->verify(public_key->public_key, signature,
- signature_len, data, data_len, hash);
+ SilcBufferStruct buf;
+ SilcUInt16 pk_len, pk_type;
+ unsigned char *pk;
+ int ret;
+
+ if (!public_key)
+ return FALSE;
+
+ silc_buffer_set(&buf, data, data_len);
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_SHORT(&pk_len),
+ SILC_STR_UI_SHORT(&pk_type),
+ SILC_STR_END);
+ if (ret < 0 || pk_len > data_len - 4)
+ return FALSE;
+
+ /* For now we support only SILC public keys */
+ if (pk_type != SILC_SKE_PK_TYPE_SILC)
+ return FALSE;
+
+ silc_buffer_pull(&buf, 4);
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_XNSTRING(&pk, pk_len),
+ SILC_STR_END);
+ silc_buffer_push(&buf, 4);
+ if (ret < 0)
+ return FALSE;
+
+ if (!silc_pkcs_public_key_decode(pk, pk_len, public_key))
+ return FALSE;
+ (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
+
+ return TRUE;
}
/* Compares two public keys and returns TRUE if they are same key, and
FALSE if they are not same. */
-SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
+bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
{
- if (key1->pkcs->type != key2->pkcs->type)
- return FALSE;
+ if (key1 == key2)
+ return TRUE;
+
+ if (key1->len == key2->len &&
+ key1->name && key2->name && key1->identifier && key2->identifier &&
+ !strcmp(key1->name, key2->name) &&
+ !strcmp(key1->identifier, key2->identifier) &&
+ !memcmp(key1->pk, key2->pk, key1->pk_len) &&
+ key1->pk_len == key2->pk_len)
+ return TRUE;
- return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
+ return FALSE;
}
/* Copies the public key indicated by `public_key' and returns new allocated
if (!key)
return NULL;
- key->pkcs = public_key->pkcs;
- key->public_key = public_key->pkcs->public_key_copy(public_key->public_key);
- if (!key->public_key) {
- silc_free(key);
- return NULL;
- }
+ key->len = public_key->len;
+ key->name = silc_memdup(public_key->name, strlen(public_key->name));
+ key->identifier = silc_memdup(public_key->identifier,
+ strlen(public_key->identifier));
+ key->pk = silc_memdup(public_key->pk, public_key->pk_len);
+ key->pk_len = public_key->pk_len;
+ key->pk_type = public_key->pk_type;
return key;
}
-/* Loads any kind of public key */
+/* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
-SilcBool silc_pkcs_load_public_key(const char *filename,
- SilcPublicKey *ret_public_key)
+unsigned char *
+silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
{
- unsigned char *data;
- SilcUInt32 data_len;
- SilcPublicKey public_key;
- SilcPKCSType type;
+ return silc_pkcs_private_key_data_encode(private_key->prv,
+ private_key->prv_len,
+ private_key->name, len);
+}
- SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
+/* Encodes SILC private key. Returns the encoded data. */
- if (!ret_public_key)
- return FALSE;
+unsigned char *
+silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
+ char *pkcs, SilcUInt32 *len)
+{
+ SilcBuffer buf;
+ unsigned char *ret;
+ SilcUInt32 totlen;
- data = silc_file_readfile(filename, &data_len);
- if (!data)
- return FALSE;
+ totlen = 2 + strlen(pkcs) + prv_len;
+ buf = silc_buffer_alloc_size(totlen);
+ if (!buf)
+ return NULL;
- /* Allocate public key context */
- *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
- if (!public_key) {
- silc_free(data);
- return FALSE;
+ silc_buffer_format(buf,
+ SILC_STR_UI_SHORT(strlen(pkcs)),
+ SILC_STR_UI32_STRING(pkcs),
+ SILC_STR_UI_XNSTRING(prv, prv_len),
+ SILC_STR_END);
+
+ ret = silc_buffer_steal(buf, len);
+ silc_buffer_free(buf);
+ return ret;
+}
+
+/* Decodes SILC style private key. Returns TRUE if the decoding was
+ successful. Allocates new private key as well. */
+
+bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
+ SilcPrivateKey *private_key)
+{
+ SilcBufferStruct buf;
+ SilcPKCS alg;
+ SilcUInt16 pkcs_len;
+ SilcUInt32 key_len;
+ unsigned char *pkcs_name = NULL, *key_data = NULL;
+ int ret;
+
+ silc_buffer_set(&buf, data, data_len);
+
+ /* Get algorithm name and identifier */
+ ret =
+ silc_buffer_unformat(&buf,
+ SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+ SILC_STR_END);
+ if (ret == -1) {
+ SILC_LOG_DEBUG(("Cannot decode private key buffer"));
+ goto err;
}
- /* Try loading all types until one succeeds. */
- for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
- public_key->pkcs = silc_pkcs_find_pkcs(type);
- if (!public_key->pkcs)
- continue;
+ if (pkcs_len < 1 || pkcs_len > buf.truelen) {
+ SILC_LOG_DEBUG(("Malformed private key buffer"));
+ goto err;
+ }
- if (public_key->pkcs->import_public_key_file(data, data_len,
- SILC_PKCS_FILE_BASE64,
- &public_key->public_key)) {
- silc_free(data);
- return TRUE;
- }
+ /* See if we support this algorithm (check only if PKCS are registered). */
+ if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
+ SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
+ goto err;
+ }
- if (public_key->pkcs->import_public_key_file(data, data_len,
- SILC_PKCS_FILE_BIN,
- &public_key->public_key)) {
- silc_free(data);
- return TRUE;
+ /* Get key data. We assume that rest of the buffer is key data. */
+ silc_buffer_pull(&buf, 2 + pkcs_len);
+ key_len = buf.len;
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
+ SILC_STR_END);
+ if (ret == -1)
+ goto err;
+
+ /* Try to set the key. If this fails the key must be malformed. This
+ code assumes that the PKCS routine checks the format of the key.
+ (check only if PKCS are registered) */
+ if (SILC_PKCS_LIST) {
+ silc_pkcs_alloc(pkcs_name, &alg);
+ if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
+ SILC_LOG_DEBUG(("Could not set private key data"));
+ goto err;
}
+ silc_pkcs_free(alg);
}
- silc_free(data);
- silc_free(public_key);
+ if (private_key) {
+ *private_key = silc_calloc(1, sizeof(**private_key));
+ (*private_key)->name = pkcs_name;
+ (*private_key)->prv = key_data;
+ (*private_key)->prv_len = key_len;
+ }
+
+ return TRUE;
+
+ err:
+ silc_free(pkcs_name);
+ silc_free(key_data);
return FALSE;
}
-/* Saves public key into a file */
+/* Internal routine to save public key */
-SilcBool silc_pkcs_save_public_key(const char *filename,
- SilcPublicKey public_key,
- SilcPKCSFileEncoding encoding)
+static bool silc_pkcs_save_public_key_internal(const char *filename,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ SilcUInt32 encoding)
{
- unsigned char *data;
- SilcUInt32 data_len;
+ SilcBuffer buf;
+ SilcUInt32 len;
+ unsigned char *tmp = NULL;
+
+ switch(encoding) {
+ case SILC_PKCS_FILE_BIN:
+ break;
+ case SILC_PKCS_FILE_PEM:
+ tmp = data = silc_pem_encode_file(data, data_len);
+ data_len = strlen(data);
+ break;
+ }
- /* Export the public key file */
- data = public_key->pkcs->export_public_key_file(public_key->public_key,
- encoding, &data_len);
- if (!data)
+ len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+ strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+ buf = silc_buffer_alloc_size(len);
+ if (!buf) {
+ silc_free(tmp);
return FALSE;
+ }
+
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
+ SILC_STR_END);
- /* Write to file */
- if (silc_file_writefile(filename, data, data_len)) {
- silc_free(data);
+ /* Save into file */
+ if (silc_file_writefile(filename, buf->data, buf->len)) {
+ silc_free(tmp);
+ silc_buffer_free(buf);
return FALSE;
}
- silc_free(data);
+ silc_free(tmp);
+ silc_buffer_free(buf);
return TRUE;
}
-/* Loads any kind of private key */
+/* Saves public key into file */
-SilcBool silc_pkcs_load_private_key(const char *filename,
- const unsigned char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPrivateKey *ret_private_key)
+bool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
+ SilcUInt32 encoding)
{
unsigned char *data;
SilcUInt32 data_len;
- SilcPrivateKey private_key;
- SilcPKCSType type;
+ bool ret;
+
+ data = silc_pkcs_public_key_encode(public_key, &data_len);
+ ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
+ encoding);
+ silc_free(data);
+ return ret;
+}
- SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
+/* Saves public key into file */
- if (!ret_private_key)
+bool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
+ SilcUInt32 data_len, SilcUInt32 encoding)
+{
+ return silc_pkcs_save_public_key_internal(filename, data, data_len,
+ encoding);
+}
+
+#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
+
+/* Internal routine to save private key. */
+
+static bool silc_pkcs_save_private_key_internal(const char *filename,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ unsigned char *key,
+ SilcUInt32 key_len,
+ SilcUInt32 encoding)
+{
+ SilcCipher aes;
+ SilcHash sha1;
+ SilcHmac sha1hmac;
+ SilcBuffer buf, enc;
+ SilcUInt32 len, blocklen, padlen;
+ unsigned char tmp[32], keymat[64];
+ int i;
+
+ memset(tmp, 0, sizeof(tmp));
+ memset(keymat, 0, sizeof(keymat));
+
+ /* Allocate the AES cipher */
+ if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
+ SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
+ return FALSE;
+ }
+ blocklen = silc_cipher_get_block_len(aes);
+ if (blocklen * 2 > sizeof(tmp))
return FALSE;
- data = silc_file_readfile(filename, &data_len);
- if (!data)
+ /* Allocate SHA1 hash */
+ if (!silc_hash_alloc("sha1", &sha1)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
+ silc_cipher_free(aes);
return FALSE;
+ }
- /* Allocate private key context */
- *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
- if (!private_key) {
- silc_free(data);
+ /* Allocate HMAC */
+ if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
return FALSE;
}
- /* Try loading all types until one succeeds. */
- for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
- private_key->pkcs = silc_pkcs_find_pkcs(type);
- if (!private_key->pkcs)
- continue;
+ /* Derive the encryption key from the provided key material. The key
+ is 256 bits length, and derived by taking hash of the data, then
+ re-hashing the data and the previous digest, and using the first and
+ second digest as the key. */
+ silc_hash_init(sha1);
+ silc_hash_update(sha1, key, key_len);
+ silc_hash_final(sha1, keymat);
+ silc_hash_init(sha1);
+ silc_hash_update(sha1, key, key_len);
+ silc_hash_update(sha1, keymat, 16);
+ silc_hash_final(sha1, keymat + 16);
+
+ /* Set the key to the cipher */
+ silc_cipher_set_key(aes, keymat, 256);
+
+ /* Encode the buffer to be encrypted. Add padding to it too, at least
+ block size of the cipher. */
+
+ /* Allocate buffer for encryption */
+ len = silc_hmac_len(sha1hmac);
+ padlen = 16 + (16 - ((data_len + 4) % blocklen));
+ enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len);
+ if (!enc) {
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
+ return FALSE;
+ }
- if (private_key->pkcs->import_private_key_file(
- data, data_len,
- passphrase,
- passphrase_len,
- SILC_PKCS_FILE_BIN,
- &private_key->private_key)) {
- silc_free(data);
- return TRUE;
- }
+ /* Generate padding */
+ for (i = 0; i < padlen; i++)
+ tmp[i] = silc_rng_global_get_byte_fast();
+
+ /* Put magic number */
+ SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
+ silc_buffer_pull(enc, 4);
+
+ /* Encode the buffer */
+ silc_buffer_format(enc,
+ SILC_STR_UI_INT(data_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI_XNSTRING(tmp, padlen),
+ SILC_STR_END);
+
+ /* Encrypt. */
+ silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
+ silc_cipher_get_iv(aes));
+
+ silc_buffer_push(enc, 4);
+
+ /* Compute HMAC over the encrypted data and append the MAC to data.
+ The key is the first digest of the original key material. */
+ data_len = enc->len - len;
+ silc_hmac_init_with_key(sha1hmac, keymat, 16);
+ silc_hmac_update(sha1hmac, enc->data, data_len);
+ silc_buffer_pull(enc, data_len);
+ silc_hmac_final(sha1hmac, enc->data, NULL);
+ silc_buffer_push(enc, data_len);
+
+ /* Cleanup */
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
+
+ data = enc->data;
+ data_len = enc->len;
+
+ switch (encoding) {
+ case SILC_PKCS_FILE_BIN:
+ break;
+ case SILC_PKCS_FILE_PEM:
+ data = silc_pem_encode_file(data, data_len);
+ data_len = strlen(data);
+ break;
+ }
- if (private_key->pkcs->import_private_key_file(
- data, data_len,
- passphrase,
- passphrase_len,
- SILC_PKCS_FILE_BASE64,
- &private_key->private_key)) {
- silc_free(data);
- return TRUE;
- }
+ /* Encode the data and save to file */
+ len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+ strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+ buf = silc_buffer_alloc_size(len);
+ silc_buffer_format(buf,
+ SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
+ SILC_STR_END);
+
+ /* Save into a file */
+ if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_buffer_clear(enc);
+ silc_buffer_free(enc);
+ return FALSE;
}
- silc_free(data);
- silc_free(private_key);
- return FALSE;
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_buffer_clear(enc);
+ silc_buffer_free(enc);
+ return TRUE;
}
-/* Saves private key into a file */
+/* Saves private key into file. */
-SilcBool silc_pkcs_save_private_key(const char *filename,
- SilcPrivateKey private_key,
- const unsigned char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- SilcRng rng)
+bool silc_pkcs_save_private_key(const char *filename,
+ SilcPrivateKey private_key,
+ unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
+ SilcUInt32 encoding)
{
unsigned char *data;
SilcUInt32 data_len;
+ bool ret;
+
+ data = silc_pkcs_private_key_encode(private_key, &data_len);
+ ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
+ passphrase, passphrase_len,
+ encoding);
+ memset(data, 0, data_len);
+ silc_free(data);
+ return ret;
+}
+
+/* Loads public key from file and allocates new public key. Returns TRUE
+ if loading was successful. */
- /* Export the private key file */
- data = private_key->pkcs->export_private_key_file(private_key->private_key,
- passphrase,
- passphrase_len,
- encoding, rng, &data_len);
+bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
+ SilcUInt32 encoding)
+{
+ unsigned char *cp, *old, *data, byte;
+ SilcUInt32 i, data_len, len;
+
+ SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
+ encoding == SILC_PKCS_FILE_PEM ? "Base64" :
+ encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
+
+ old = data = silc_file_readfile(filename, &data_len);
if (!data)
return FALSE;
- /* Write to file */
- if (silc_file_writefile(filename, data, data_len)) {
- silc_free(data);
+ /* Check start of file and remove header from the data. */
+ len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
+ cp = data;
+ for (i = 0; i < len; i++) {
+ byte = cp[0];
+ cp++;
+ if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ }
+ data = cp;
+
+ /* Decode public key */
+ if (public_key) {
+ len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+ strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+
+ switch(encoding) {
+ case SILC_PKCS_FILE_BIN:
+ break;
+ case SILC_PKCS_FILE_PEM:
+ data = silc_pem_decode(data, len, &len);
+ memset(old, 0, data_len);
+ silc_free(old);
+ old = data;
+ data_len = len;
+ break;
+ }
+
+ if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ }
+
+ memset(old, 0, data_len);
+ silc_free(old);
+ return TRUE;
+}
+
+/* Load private key from file and allocates new private key. Returns TRUE
+ if loading was successful. */
+
+bool silc_pkcs_load_private_key(const char *filename,
+ SilcPrivateKey *private_key,
+ unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
+ SilcUInt32 encoding)
+{
+ SilcCipher aes;
+ SilcHash sha1;
+ SilcHmac sha1hmac;
+ SilcUInt32 blocklen;
+ unsigned char tmp[32], keymat[64];
+ unsigned char *cp, *old, *data, byte;
+ SilcUInt32 i, data_len, len, magic, mac_len;
+
+ SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
+ encoding == SILC_PKCS_FILE_PEM ? "Base64" :
+ encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
+
+ old = data = silc_file_readfile(filename, &data_len);
+ if (!data)
return FALSE;
+
+ /* Check start of file and remove header from the data. */
+ len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
+ cp = data;
+ for (i = 0; i < len; i++) {
+ byte = cp[0];
+ cp++;
+ if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ }
+ data = cp;
+
+ /* Decode private key */
+ len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+ strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+
+ switch(encoding) {
+ case SILC_PKCS_FILE_BIN:
+ break;
+ case SILC_PKCS_FILE_PEM:
+ data = silc_pem_decode(data, len, &len);
+ if (!data) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ break;
}
- silc_free(data);
+ memset(tmp, 0, sizeof(tmp));
+ memset(keymat, 0, sizeof(keymat));
+
+ /* Private key files without the specific magic number are assumed
+ to be the old-style private keys that are not encrypted. */
+ SILC_GET32_MSB(magic, data);
+ if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
+ SILC_LOG_DEBUG(("Private key does not have correct magic!"));
+
+ /* Now decode the actual private key */
+ if (!silc_pkcs_private_key_decode(data, len, private_key)) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ memset(old, 0, data_len);
+ silc_free(old);
+ return TRUE;
+ }
+
+ /* Allocate the AES cipher */
+ if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
+ SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ blocklen = silc_cipher_get_block_len(aes);
+ if (blocklen * 2 > sizeof(tmp)) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ /* Allocate SHA1 hash */
+ if (!silc_hash_alloc("sha1", &sha1)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ /* Allocate HMAC */
+ if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ /* Derive the decryption key from the provided key material. The key
+ is 256 bits length, and derived by taking hash of the data, then
+ re-hashing the data and the previous digest, and using the first and
+ second digest as the key. */
+ silc_hash_init(sha1);
+ silc_hash_update(sha1, passphrase, passphrase_len);
+ silc_hash_final(sha1, keymat);
+ silc_hash_init(sha1);
+ silc_hash_update(sha1, passphrase, passphrase_len);
+ silc_hash_update(sha1, keymat, 16);
+ silc_hash_final(sha1, keymat + 16);
+
+ /* Set the key to the cipher */
+ silc_cipher_set_key(aes, keymat, 256);
+
+ /* First, verify the MAC of the private key data */
+ mac_len = silc_hmac_len(sha1hmac);
+ silc_hmac_init_with_key(sha1hmac, keymat, 16);
+ silc_hmac_update(sha1hmac, data, len - mac_len);
+ silc_hmac_final(sha1hmac, tmp, NULL);
+ if (memcmp(tmp, data + (len - mac_len), mac_len)) {
+ SILC_LOG_DEBUG(("Integrity check for private key failed"));
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ data += 4;
+ len -= 4;
+
+ /* Decrypt the private key buffer */
+ silc_cipher_decrypt(aes, data, data, len - mac_len, NULL);
+ SILC_GET32_MSB(i, data);
+ if (i > len) {
+ SILC_LOG_DEBUG(("Bad private key length in buffer!"));
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ data += 4;
+ len = i;
+
+ /* Cleanup */
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(sha1);
+ silc_cipher_free(aes);
+
+ /* Now decode the actual private key */
+ if (!silc_pkcs_private_key_decode(data, len, private_key)) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ memset(old, 0, data_len);
+ silc_free(old);
return TRUE;
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2003 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 SILCPKCS_H
+#define SILCPKCS_H
+
/****h* silccrypt/SILC PKCS Interface
*
* DESCRIPTION
*
- * SILC PKCS API provides generic interface for performing various
- * public key cryptography related operations with different types of
- * public and private keys. Support for loading and saving of different
- * types of public key and private keys are also provided.
+ * This is the interface for public key cryptosystems, and various
+ * utility functions related to public keys and private keys. This
+ * interface also defines the actual PKCS objects, public keys and
+ * private keys. The interface is generic PKCS interface, which has
+ * capability of supporting any kind of public key algorithm. This
+ * interface also implements the SILC Public Key and routines for
+ * encoding and decoding SILC Public Key (as defined by the SILC
+ * protocol specification). Interface or encrypting, decrypting,
+ * producing digital signatures and verifying digital signatures are
+ * also defined in this header.
*
***/
-#ifndef SILCPKCS_H
-#define SILCPKCS_H
-
-/* Forward declarations */
-typedef struct SilcPKCSObjectStruct SilcPKCSObject;
-
-/****d* silccrypt/SilcPKCSAPI/SilcPKCSType
+/****s* silccrypt/SilcPKCSAPI/SilcPKCS
*
* NAME
*
- * typedef enum { ... } SilcPKCSType;
+ * typedef struct SilcPKCSStruct *SilcPKCS;
*
* DESCRIPTION
*
- * Supported public key cryptosystem types.
+ * This context is the actual PKCS context and is allocated
+ * by silc_pkcs_alloc and given as argument usually to all
+ * silc_pkcs_* functions. It is freed by the silc_pkcs_free
+ * function.
*
- * SOURCE
- */
-typedef enum {
- SILC_PKCS_SILC = 1, /* SILC PKCS */
- SILC_PKCS_SSH2 = 2, /* SSH2 PKCS (not supported) */
- SILC_PKCS_X509V3 = 3, /* X.509v3 PKCS (not supported) */
- SILC_PKCS_OPENPGP = 4, /* OpenPGP PKCS (not supported) */
- SILC_PKCS_SPKI = 5, /* SPKI PKCS (not supported) */
-} SilcPKCSType;
-/***/
+ ***/
+typedef struct SilcPKCSStruct *SilcPKCS;
+
+/* The default SILC PKCS (Public Key Cryptosystem) object to represent
+ any PKCS in SILC. */
+typedef struct SilcPKCSObjectStruct {
+ char *name;
+ int (*init)(void *, SilcUInt32, SilcRng);
+ void (*clear_keys)(void *);
+ unsigned char *(*get_public_key)(void *, SilcUInt32 *);
+ unsigned char *(*get_private_key)(void *, SilcUInt32 *);
+ SilcUInt32 (*set_public_key)(void *, unsigned char *, SilcUInt32);
+ SilcUInt32 (*set_private_key)(void *, unsigned char *, SilcUInt32);
+ SilcUInt32 (*context_len)();
+ int (*encrypt)(void *, unsigned char *, SilcUInt32,
+ unsigned char *, SilcUInt32 *);
+ int (*decrypt)(void *, unsigned char *, SilcUInt32,
+ unsigned char *, SilcUInt32 *);
+ int (*sign)(void *, unsigned char *, SilcUInt32,
+ unsigned char *, SilcUInt32 *);
+ int (*verify)(void *, unsigned char *, SilcUInt32,
+ unsigned char *, SilcUInt32);
+} SilcPKCSObject;
/****s* silccrypt/SilcPKCSAPI/SilcPublicKey
*
* NAME
*
- * typedef struct { ... } *SilcPublicKey;
+ * typedef struct { ... } *SilcPublicKey, SilcPublicKeyStruct;
*
* DESCRIPTION
*
- * This context represents any kind of PKCS public key. It can be
- * allocated by silc_pkcs_public_key_alloc and is freed by the
- * silc_pkcs_public_key_free. The PKCS specific public key context
- * can be retrieved by calling silc_pkcs_get_context.
+ * SILC style public key object. Public key is read from file to this
+ * object. Public keys received from network must be in this format as
+ * well. The format is defined by the SILC protocol specification.
+ * This object is allocated by silc_pkcs_public_key_alloc and freed
+ * by silc_pkcs_public_key_free. The object is given as argument to
+ * all silc_pkcs_public_key_* functions.
*
* SOURCE
*/
typedef struct {
- const SilcPKCSObject *pkcs; /* PKCS */
- void *public_key; /* PKCS specific public key */
-} *SilcPublicKey;
+ SilcUInt16 pk_type; /* Public key type (SilcSKEPKType) */
+ SilcUInt32 len;
+ char *name;
+ char *identifier;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+} *SilcPublicKey, SilcPublicKeyStruct;
/***/
-/****s* silccrypt/SilcPKCSAPI/SilcPrivateKey
+/****s* silccrypt/SilcPKCSAPI/SilcPublicKeyIdentifier
*
* NAME
*
- * typedef struct { ... } *SilcPrivateKey;
+ * typedef struct { ... } *SilcPublicKeyIdentifier,
+ * SilcPublicKeyIdentifierStruct;
*
* DESCRIPTION
*
- * This context represents any kind of PKCS private key.
+ * Decoded SILC Public Key identifier. Note that some of the fields
+ * may be NULL. This context is allocated by the function
+ * silc_pkcs_decode_identifier and freed by silc_pkcs_free_identifier.
+ * The identifier in SilcPublicKey is the `identifier' field, which
+ * can be given as argument to silc_pkcs_decode_identifier.
*
* SOURCE
*/
typedef struct {
- const SilcPKCSObject *pkcs; /* PKCS */
- void *private_key; /* PKCS specific private key */
-} *SilcPrivateKey;
+ char *username;
+ char *host;
+ char *realname;
+ char *email;
+ char *org;
+ char *country;
+} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
/***/
-/****d* silccrypt/SilcPKCSAPI/SilcPKCSFileEncoding
+/****s* silccrypt/SilcPKCSAPI/SilcPrivateKey
*
* NAME
*
- * typedef enum { ... } SilcPKCSType
+ * typedef struct { ... } *SilcPrivateKey, SilcPrivateKeyStruct;
*
* DESCRIPTION
*
- * Public and private key file encoding types.
+ * SILC style private key object. Public key is read from file to this
+ * object. This object is allocated by silc_pkcs_private_key_alloc and
+ * freed by silc_pkcs_private_key_free. The object is given as argument
+ * to all silc_pkcs_private_key_* functions.
*
- * SOURCE
- */
-typedef enum {
- SILC_PKCS_FILE_BIN, /* Binary encoding */
- SILC_PKCS_FILE_BASE64 /* Base64 encoding */
-} SilcPKCSFileEncoding;
-/***/
-
-/* The PKCS Algorithm object to represent any PKCS algorithm. */
+ ***/
typedef struct {
- /* Algorithm name and scheme */
char *name;
- char *scheme;
-
- /* Supported hash functions, comma separated list */
- char *hash;
-
- /* Generate new key pair. Returns PKCS algorithm specific public key
- and private key contexts. */
- SilcBool (*generate_key)(SilcUInt32 keylen,
- SilcRng rng,
- void **ret_public_key,
- void **ret_private_key);
-
- /* Public key routines. */
- int (*import_public_key)(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_public_key);
- unsigned char *(*export_public_key)(void *public_key,
- SilcUInt32 *ret_len);
- SilcUInt32 (*public_key_bitlen)(void *public_key);
- void *(*public_key_copy)(void *public_key);
- SilcBool (*public_key_compare)(void *key1, void *key2);
- void (*public_key_free)(void *public_key);
-
- /* Private key routines */
- int (*import_private_key)(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_private_key);
- unsigned char *(*export_private_key)(void *private_key,
- SilcUInt32 *ret_len);
- SilcUInt32 (*private_key_bitlen)(void *public_key);
- void (*private_key_free)(void *private_key);
-
- /* Encrypt and decrypt operations */
- SilcBool (*encrypt)(void *public_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len,
- SilcRng rng);
- SilcBool (*decrypt)(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len);
-
- /* Signature and verification operations */
- SilcBool (*sign)(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash);
- SilcBool (*verify)(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash);
-} SilcPKCSAlgorithm;
-
-/* The PKCS (Public Key Cryptosystem) object to represent any PKCS. */
-struct SilcPKCSObjectStruct {
- /* PKCS type */
- SilcPKCSType type;
-
- /* Public key routines */
-
- /* Returns PKCS algorithm context from public key */
- const SilcPKCSAlgorithm *(*get_algorithm)(void *public_key);
-
- /* Imports from public key file */
- SilcBool (*import_public_key_file)(unsigned char *filedata,
- SilcUInt32 filedata_len,
- SilcPKCSFileEncoding encoding,
- void **ret_public_key);
-
- /* Imports from public key binary data. Returns the amount of bytes
- imported from `key' or 0 on error. */
- int (*import_public_key)(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_public_key);
-
- /* Exports public key to file */
- unsigned char *(*export_public_key_file)(void *public_key,
- SilcPKCSFileEncoding encoding,
- SilcUInt32 *ret_len);
-
- /* Export public key as binary data */
- unsigned char *(*export_public_key)(void *public_key,
- SilcUInt32 *ret_len);
-
- /* Returns key length in bits */
- SilcUInt32 (*public_key_bitlen)(void *public_key);
-
- /* Copy public key */
- void *(*public_key_copy)(void *public_key);
-
- /* Compares public keys */
- SilcBool (*public_key_compare)(void *key1, void *key2);
-
- /* Free public key */
- void (*public_key_free)(void *public_key);
-
- /* Private key routines */
-
- /* Imports from private key file */
- SilcBool (*import_private_key_file)(unsigned char *filedata,
- SilcUInt32 filedata_len,
- const char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- void **ret_private_key);
-
- /* Imports from private key binary data. Returns the amount of bytes
- imported from `key' or 0 on error. */
- int (*import_private_key)(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_private_key);
-
- /* Exports private key to file */
- unsigned char *(*export_private_key_file)(void *private_key,
- const char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- SilcRng rng,
- SilcUInt32 *ret_len);
-
- /* Export private key as binary data */
- unsigned char *(*export_private_key)(void *private_key,
- SilcUInt32 *ret_len);
-
- /* Returns key length in bits */
- SilcUInt32 (*private_key_bitlen)(void *private_key);
-
- /* Free private key */
- void (*private_key_free)(void *private_key);
-
- /* Encrypt and decrypt operations */
- SilcBool (*encrypt)(void *public_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len,
- SilcRng rng);
- SilcBool (*decrypt)(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len);
-
- /* Signature and verification operations */
- SilcBool (*sign)(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash);
- SilcBool (*verify)(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash);
-};
-
-/* Marks for all PKCS in. This can be used in silc_pkcs_unregister to
- unregister all PKCS at once. */
+ unsigned char *prv;
+ SilcUInt32 prv_len;
+} *SilcPrivateKey, SilcPrivateKeyStruct;
+
+/* Public and private key file headers */
+#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
+
+/* Public and private key file encoding types */
+#define SILC_PKCS_FILE_BIN 0
+#define SILC_PKCS_FILE_PEM 1
+
+/* Marks for all PKCS in silc. This can be used in silc_pkcs_unregister
+ to unregister all PKCS at once. */
#define SILC_ALL_PKCS ((SilcPKCSObject *)1)
-#define SILC_ALL_PKCS_ALG ((SilcPKCSAlgorithm *)1)
-/* Static lists of PKCS and PKCS algorithms. */
+/* Static list of PKCS for silc_pkcs_register_default(). */
extern DLLAPI const SilcPKCSObject silc_default_pkcs[];
-extern DLLAPI const SilcPKCSAlgorithm silc_default_pkcs_alg[];
+
+/* Default PKXS in the SILC protocol */
+#define SILC_DEFAULT_PKCS "rsa"
+
+/* Macros */
+
+/* Macros used to implement the SILC PKCS API */
+
+/* XXX: This needs slight redesigning. These needs to be made even
+ more generic. I don't like that the actual prime generation is done
+ in PKCS_API_INIT. The primes used in key generation should be sent
+ as argument to the init function. By doing this we would achieve
+ that PKCS could be used as SIM's. The only requirement would be
+ that they are compiled against GMP (well, actually even that would
+ not be a requirement, but the most generic case anyway). The new init
+ would look something like this:
+
+ #define SILC_PKCS_API_INIT(pkcs) \
+ inline int silc_##pkcs##_init(void *context, SilcUInt32 keylen, \
+ void *p1, void *p2)
+
+ Now we wouldn't have to send the SilcRng object since the primes are
+ provided as arguments. To send them as void * they could actually be
+ used as in anyway for real (MP_INT (SilcMPInt) or even something else
+ (the pointer could be kludged to be something else in the module))
+ (Plus, the SilcRng object management in prime generation would be
+ simpler and better what it is now (in silcprimegen.c, that is)).
+*/
+
+#define SILC_PKCS_API_INIT(pkcs) \
+int silc_##pkcs##_init(void *context, SilcUInt32 keylen, \
+ SilcRng rng)
+#define SILC_PKCS_API_CLEAR_KEYS(pkcs) \
+void silc_##pkcs##_clear_keys(void *context)
+#define SILC_PKCS_API_GET_PUBLIC_KEY(pkcs) \
+unsigned char *silc_##pkcs##_get_public_key(void *context, \
+ SilcUInt32 *ret_len)
+#define SILC_PKCS_API_GET_PRIVATE_KEY(pkcs) \
+unsigned char *silc_##pkcs##_get_private_key(void *context, \
+ SilcUInt32 *ret_len)
+#define SILC_PKCS_API_SET_PUBLIC_KEY(pkcs) \
+SilcUInt32 silc_##pkcs##_set_public_key(void *context, unsigned char *key_data, \
+ SilcUInt32 key_len)
+#define SILC_PKCS_API_SET_PRIVATE_KEY(pkcs) \
+SilcUInt32 silc_##pkcs##_set_private_key(void *context, unsigned char *key_data, \
+ SilcUInt32 key_len)
+#define SILC_PKCS_API_CONTEXT_LEN(pkcs) \
+SilcUInt32 silc_##pkcs##_context_len()
+#define SILC_PKCS_API_ENCRYPT(pkcs) \
+int silc_##pkcs##_encrypt(void *context, \
+ unsigned char *src, \
+ SilcUInt32 src_len, \
+ unsigned char *dst, \
+ SilcUInt32 *dst_len)
+#define SILC_PKCS_API_DECRYPT(pkcs) \
+int silc_##pkcs##_decrypt(void *context, \
+ unsigned char *src, \
+ SilcUInt32 src_len, \
+ unsigned char *dst, \
+ SilcUInt32 *dst_len)
+#define SILC_PKCS_API_SIGN(pkcs) \
+int silc_##pkcs##_sign(void *context, \
+ unsigned char *src, \
+ SilcUInt32 src_len, \
+ unsigned char *dst, \
+ SilcUInt32 *dst_len)
+#define SILC_PKCS_API_VERIFY(pkcs) \
+int silc_##pkcs##_verify(void *context, \
+ unsigned char *signature, \
+ SilcUInt32 signature_len, \
+ unsigned char *data, \
+ SilcUInt32 data_len)
/* Prototypes */
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs);
+ * bool silc_pkcs_register(const SilcPKCSObject *pkcs);
*
* DESCRIPTION
*
* builtin the sources. Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs);
+bool silc_pkcs_register(const SilcPKCSObject *pkcs);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs);
+ * bool silc_pkcs_unregister(SilcPKCSObject *pkcs);
*
* DESCRIPTION
*
* Unregister a PKCS from the SILC. Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs);
+bool silc_pkcs_unregister(SilcPKCSObject *pkcs);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_algorithm_register
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_register_default
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs);
+ * bool silc_pkcs_register_default(void);
*
* DESCRIPTION
*
- * Registers a new PKCS Algorithm into the SILC. This function is used
- * at the initialization of the SILC. All registered PKCS algorithms
- * should be unregistered with silc_pkcs_unregister.
+ * Registers all the default PKCS (all builtin PKCS). The application may
+ * use this to register the default PKCS if specific PKCS in any specific
+ * order is not wanted. Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs);
+bool silc_pkcs_register_default(void);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_algorithm_unregister
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister_all
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs);
+ * bool silc_pkcs_unregister_all(void);
*
* DESCRIPTION
*
- * Unregister a PKCS from the SILC. Returns FALSE on error.
+ * Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs);
+bool silc_pkcs_unregister_all(void);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_register_default
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_alloc
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_register_default(void);
+ * bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs);
*
* DESCRIPTION
*
- * Registers all the default PKCS (all builtin PKCS) and PKCS algorithms.
- * The application may use this to register the default PKCS if specific
- * PKCS in any specific order is not wanted. Returns FALSE on error.
+ * Allocates a new SilcPKCS object. The new allocated object is returned
+ * to the 'new_pkcs' argument. Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_register_default(void);
+bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister_all
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_free
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_unregister_all(void);
+ * void silc_pkcs_free(SilcPKCS pkcs);
*
* DESCRIPTION
*
- * Unregister all PKCS and PKCS algorithms. Returns FALSE on error.
+ * Frees the PKCS object.
*
***/
-SilcBool silc_pkcs_unregister_all(void);
+void silc_pkcs_free(SilcPKCS pkcs);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_is_supported
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_is_supported(const unsigned char *name);
+ *
+ * DESCRIPTION
+ *
+ * Returns TRUE if PKCS algorithm `name' is supported.
+ *
+ ***/
+bool silc_pkcs_is_supported(const unsigned char *name);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_supported
*
***/
char *silc_pkcs_get_supported(void);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_find_pkcs
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_generate_key
*
* SYNOPSIS
*
- * const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPKCSType type);
+ * bool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
+ * SilcRng rng);
*
* DESCRIPTION
*
- * Finds PKCS context by the PKCS type.
+ * Generate new key pair into the `pkcs' context. Returns FALSE on error.
+ * If the `rng' is NULL global SILC RNG will be used.
*
***/
-const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type);
+bool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
+ SilcRng rng);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_find_algorithm
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_key_len
*
* SYNOPSIS
*
- * const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
- * const char *scheme);
+ * SilcUInt32 silc_pkcs_get_key_len(SilcPKCS self);
*
* DESCRIPTION
*
- * Finds PKCS algorithm context by the algorithm name `algorithm' and
- * the algorithm scheme `scheme'. The `scheme' may be NULL.
+ * Returns the length of the key in bits.
*
***/
-const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
- const char *scheme);
+SilcUInt32 silc_pkcs_get_key_len(SilcPKCS self);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_pkcs
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_name
*
* SYNOPSIS
*
- * const SilcPKCSObject *silc_pkcs_get_pkcs(void *key);
+ * const char *silc_pkcs_get_name(SilcPKCS pkcs);
*
* DESCRIPTION
*
- * Returns the PKCS object from `key', which may be SilcPublicKey or
- * SilcPrivateKey pointer.
+ * Returns PKCS name.
*
***/
-const SilcPKCSObject *silc_pkcs_get_pkcs(void *key);
+const char *silc_pkcs_get_name(SilcPKCS pkcs);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_algorithm
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_public_key
*
* SYNOPSIS
*
- * const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key);
+ * unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len);
*
* DESCRIPTION
*
- * Returns the PKCS algorithm object from `key', which may be SilcPublicKey
- * or SilcPrivateKey pointer.
+ * Returns SILC style public key for the PKCS. Note that this is not
+ * the SILC Public Key, but the raw public key data from the PKCS.
+ * The caller must free the returned data.
*
***/
-const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(void *key);
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_name
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_private_key
*
* SYNOPSIS
*
- * const char *silc_pkcs_get_name(void *key);
+ * unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs,
+ * SilcUInt32 *len);
*
* DESCRIPTION
*
- * Returns PKCS algorithm name from the `key', which may be SilcPublicKey
- * or SilcPrivateKey pointer.
+ * Returns SILC style private key. Note that this is not SilcPrivateKey
+ * but the raw private key bits from the PKCS. The caller must free the
+ * returned data and SHOULD zero the memory area before freeing.
*
***/
-const char *silc_pkcs_get_name(void *key);
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_type
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_set
*
* SYNOPSIS
*
- * SilcPKCSType silc_pkcs_get_type(void *key);
+ * SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs,
+ * SilcPublicKey public_key);
*
* DESCRIPTION
*
- * Returns PKCS type from the `key', which may be SilcPublicKey or
- * SilcPrivateKey pointer.
+ * Sets public key from SilcPublicKey. Returns the length of the key in
+ * bits.
*
***/
-SilcPKCSType silc_pkcs_get_type(void *key);
+SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_context
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_data_set
*
* SYNOPSIS
*
- * void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key);
+ * SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs,
+ * unsigned char *pk,
+ * SilcUInt32 pk_len);
*
* DESCRIPTION
*
- * Returns the internal PKCS `type' specific public key context from the
- * `public_key'. The caller needs to explicitly type cast it to correct
- * type. Returns NULL on error.
+ * Sets public key from data. Returns the length of the key.
*
- * For SILC_PKCS_SILC the returned context is SilcSILCPublicKey.
+ ***/
+SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
+ SilcUInt32 pk_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_set
+ *
+ * SYNOPSIS
+ *
+ * SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs,
+ * SilcPrivateKey private_key);
+ *
+ * DESCRIPTION
+ *
+ * Sets private key from SilcPrivateKey. Returns the length of the key
+ * in bits.
+ *
+ ***/
+SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs,
+ SilcPrivateKey private_key);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_data_set
+ *
+ * SYNOPSIS
+ *
+ * SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs,
+ * unsigned char *prv,
+ * SilcUInt32 prv_len);
+ *
+ * DESCRIPTION
+ *
+ * Sets private key from data. Returns the length of the key.
+ *
+ ***/
+SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
+ SilcUInt32 prv_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encrypt
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src,
+ * SilcUInt32 src_len, unsigned char *dst,
+ * SilcUInt32 *dst_len);
+ *
+ * DESCRIPTION
+ *
+ * Encrypts. Returns FALSE on error.
+ *
+ ***/
+bool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src,
+ * SilcUInt32 src_len, unsigned char *dst,
+ * SilcUInt32 *dst_len);
+ *
+ * DESCRIPTION
+ *
+ * Decrypts. Returns FALSE on error.
*
***/
-void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key);
+bool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src,
+ * SilcUInt32 src_len, unsigned char *dst,
+ * SilcUInt32 *dst_len);
+ *
+ * DESCRIPTION
+ *
+ * Generates signature. Returns FALSE on error.
+ *
+ ***/
+bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
+ * SilcUInt32 signature_len, unsigned char *data,
+ * SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ * Verifies signature. Returns FALSE on error. The 'signature' is
+ * verified against the 'data'.
+ *
+ ***/
+bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
+ SilcUInt32 signature_len, unsigned char *data,
+ SilcUInt32 data_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign_with_hash
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
+ * unsigned char *src, SilcUInt32 src_len,
+ * unsigned char *dst, SilcUInt32 *dst_len);
+ *
+ * DESCRIPTION
+ *
+ * Generates signature with hash. The hash is signed. Returns FALSE on
+ * error.
+ *
+ ***/
+bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
+ unsigned char *src, SilcUInt32 src_len,
+ unsigned char *dst, SilcUInt32 *dst_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify_with_hash
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
+ * unsigned char *signature,
+ * SilcUInt32 signature_len,
+ * unsigned char *data,
+ * SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ * Verifies signature with hash. The `data' is hashed and verified against
+ * the `signature'. Returns FALSE on error.
+ *
+ ***/
+bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
+ unsigned char *signature,
+ SilcUInt32 signature_len,
+ unsigned char *data,
+ SilcUInt32 data_len);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encode_identifier
+ *
+ * SYNOPSIS
+ *
+ * char *silc_pkcs_encode_identifier(char *username, char *host,
+ * char *realname, char *email,
+ * char *org, char *country);
+ *
+ * DESCRIPTION
+ *
+ * Encodes and returns SILC public key identifier. If some of the
+ * arguments is NULL those are not encoded into the identifier string.
+ * Protocol says that at least username and host must be provided.
+ *
+ ***/
+char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
+ char *email, char *org, char *country);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decode_identifier
+ *
+ * SYNOPSIS
+ *
+ * SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier);
+ *
+ * DESCRIPTION
+ *
+ * Decodes the provided `identifier' and returns allocated context for
+ * the identifier.
+ *
+ ***/
+SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_free_identifier
+ *
+ * SYNOPSIS
+ *
+ * void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier);
+ *
+ * DESCRIPTION
+ *
+ * Frees decoded public key identifier context. Call this to free the
+ * context returned by the silc_pkcs_decode_identifier.
+ *
+ ***/
+void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_alloc
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
- * unsigned char *key,
- * SilcUInt32 key_len
- * SilcPublicKey *ret_public_key);
+ * SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
+ * const char *identifier,
+ * const unsigned char *pk,
+ * SilcUInt32 pk_len);
*
* DESCRIPTION
*
- * Allocates SilcPublicKey of the type of `type' from the key data
- * `key' of length of `key_len' bytes. Returns FALSE if the `key'
- * is malformed or unsupported public key type. This function can be
- * used to create public key from any kind of PKCS public keys that
- * the implementation supports.
+ * Allocates SILC style public key formed from sent arguments. The
+ * 'name' is the algorithm (PKCS) name, the 'identifier' is the public
+ * key identifier generated with silc_pkcs_encode_identifier, and the
+ * 'pk' and 'pk_len' are the raw public key data returned for example
+ * by silc_pkcs_get_public_key.
*
***/
-SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
- unsigned char *key,
- SilcUInt32 key_len,
- SilcPublicKey *ret_public_key);
+SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
+ const char *identifier,
+ const unsigned char *pk,
+ SilcUInt32 pk_len);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_free
*
*
* DESCRIPTION
*
- * Frees the public key.
+ * Frees public key and all data in it.
*
***/
void silc_pkcs_public_key_free(SilcPublicKey public_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_export
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_alloc
*
* SYNOPSIS
*
- * unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
- * SilcUInt32 *ret_len);
+ * SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
+ * const unsigned char *prv,
+ * SilcUInt32 prv_len);
*
* DESCRIPTION
*
- * Encodes the `public_key' into a binary format and returns it. Returns
- * NULL on error. Caller must free the returned buffer.
+ * Allocates SILC private key formed from sent arguments. The 'name'
+ * is the algorithm name, and the 'prv' and 'prv_len' are the raw
+ * private key bits returned by silc_pkcs_get_private_key.
*
***/
-unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
- SilcUInt32 *ret_len);
+SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
+ const unsigned char *prv,
+ SilcUInt32 prv_len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_get_len
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_free
*
* SYNOPSIS
*
- * SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key);
+ * void silc_pkcs_private_key_free(SilcPrivateKey private_key);
*
* DESCRIPTION
*
- * Returns the key length in bits from the public key.
+ * Frees private key and all data in it. The private key is zeroed
+ * before it is freed.
*
***/
-SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key);
+void silc_pkcs_private_key_free(SilcPrivateKey private_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_encode
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1,
- * SilcPublicKey key2);
+ * unsigned char *
+ * silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len);
*
* DESCRIPTION
*
- * Compares two public keys and returns TRUE if they are same key, and
- * FALSE if they are not same.
+ * Encodes SILC style public key from SilcPublicKey. Returns the encoded
+ * data.
*
***/
-SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2);
+unsigned char *
+silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_copy
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_data_encode
*
* SYNOPSIS
*
- * SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
+ * unsigned char *
+ * silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
+ * char *pkcs, char *identifier,
+ * SilcUInt32 *len);
*
* DESCRIPTION
*
- * Copies the public key indicated by `public_key' and returns new
- * allocated public key which is indentical to the `public_key'.
+ * Encodes SILC style public key. Returns the encoded data.
*
***/
-SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
+unsigned char *
+silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
+ char *pkcs, char *identifier,
+ SilcUInt32 *len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_alloc
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_decode
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
- * unsigned char *key,
- * SilcUInt32 key_len,
- * SilcPrivateKey *ret_private_key);
+ * bool silc_pkcs_public_key_decode(unsigned char *data,
+ * SilcUInt32 data_len,
+ * SilcPublicKey *public_key);
*
* DESCRIPTION
*
- * Allocates SilcPrivateKey of the type of `type' from the key data
- * `key' of length of `key_len' bytes. Returns FALSE if the `key'
- * is malformed or unsupported private key type.
+ * Decodes SILC style public key. Returns TRUE if the decoding was
+ * successful. Allocates new public key as well.
*
***/
-SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
- unsigned char *key,
- SilcUInt32 key_len,
- SilcPrivateKey *ret_private_key);
+bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
+ SilcPublicKey *public_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_get_len
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_payload_encode
*
* SYNOPSIS
*
- * SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key);
+ * bool silc_pkcs_public_key_payload_encode(SilcPublicKey public_key);
*
* DESCRIPTION
*
- * Returns the key length in bits from the private key.
+ * Encodes the Public Key Payload from the public key indicated by
+ * `public_key' of type of `pk_type'. The type is SilcSKEPKType.
+ * Returns the encoded payload buffer.
*
***/
-SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key);
+SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_free
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_payload_decode
*
* SYNOPSIS
*
- * void silc_pkcs_private_key_free(SilcPrivateKey private_key;
+ * bool silc_pkcs_public_key_payload_decode(unsigned char *data,
+ * SilcUInt32 data_len,
+ * SilcPublicKey *public_key);
*
* DESCRIPTION
*
- * Frees the private key.
+ * Decodes Public Key Payload from `data' of `data_len' bytes in length
+ * data buffer into `public_key' pointer. Returns FALSE if the payload
+ * cannot be decoded.
*
***/
-void silc_pkcs_private_key_free(SilcPrivateKey private_key);
+bool silc_pkcs_public_key_payload_decode(unsigned char *data,
+ SilcUInt32 data_len,
+ SilcPublicKey *public_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encrypt
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
- * unsigned char *src, SilcUInt32 src_len,
- * unsigned char *dst, SilcUInt32 dst_size,
- * SilcUInt32 *dst_len);
+ * bool silc_pkcs_public_key_compare(SilcPublicKey key1,
+ * SilcPublicKey key2);
*
* DESCRIPTION
*
- * Encrypts with the public key. Returns FALSE on error.
+ * Compares two public keys and returns TRUE if they are same key, and
+ * FALSE if they are not same.
*
***/
-SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
- unsigned char *src, SilcUInt32 src_len,
- unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len, SilcRng rng);
+bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_copy
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
- * unsigned char *src, SilcUInt32 src_len,
- * unsigned char *dst, SilcUInt32 dst_size,
- * SilcUInt32 *dst_len);
+ * SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
*
* DESCRIPTION
*
- * Decrypts with the private key. Returns FALSE on error.
+ * Copies the public key indicated by `public_key' and returns new allocated
+ * public key which is indentical to the `public_key'.
*
***/
-SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
- unsigned char *src, SilcUInt32 src_len,
- unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len);
+SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_encode
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
- * unsigned char *src, SilcUInt32 src_len,
- * unsigned char *dst, SilcUInt32 dst_size,
- * SilcUInt32 *dst_len, SilcBool compute_hash,
- * SilcHash hash);
+ * unsigned char *
+ * silc_pkcs_private_key_encode(SilcPrivateKey private_key,
+ * SilcUInt32 *len);
*
* DESCRIPTION
*
- * Generates signature with the private key. Returns FALSE on error.
- * If `compute_hash' is TRUE the `hash' will be used to compute a
- * digest over the `src'. The `hash' must always be valid.
+ * Encodes SILC private key from SilcPrivateKey. Returns the encoded data.
*
***/
-SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
- unsigned char *src, SilcUInt32 src_len,
- unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len, SilcBool compute_hash,
- SilcHash hash);
+unsigned char *
+silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_data_encode
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_verify(SilcPublicKey public_key,
- * unsigned char *signature,
- * SilcUInt32 signature_len,
- * unsigned char *data,
- * SilcUInt32 data_len, SilcHash hash);
+ * unsigned char *
+ * silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
+ * char *pkcs, SilcUInt32 *len);
*
* DESCRIPTION
*
- * Verifies signature. Returns FALSE on error. The 'signature' is
- * verified against the 'data'. If the `hash' is non-NULL then the `data'
- * will hashed before verification. If the `hash' is NULL, then the
- * hash algorithm to be used is retrieved from the signature. If it
- * isn't present in the signature the verification is done as is without
- * hashing.
+ * Encodes SILC private key. Returns the encoded data.
*
***/
-SilcBool silc_pkcs_verify(SilcPublicKey public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len, SilcHash hash);
+unsigned char *
+silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
+ char *pkcs, SilcUInt32 *len);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_decode
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_load_public_key(const char *filename,
- * SilcPublicKey *ret_public_key);
+ * bool silc_pkcs_private_key_decode(unsigned char *data,
+ * SilcUInt32 data_len,
+ * SilcPrivateKey *private_key);
*
* DESCRIPTION
*
- * Loads public key from file and allocates new public key. Returns TRUE
- * if loading was successful.
+ * Decodes SILC style private key. Returns TRUE if the decoding was
+ * successful. Allocates new private key as well.
*
***/
-SilcBool silc_pkcs_load_public_key(const char *filename,
- SilcPublicKey *ret_public_key);
+bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
+ SilcPrivateKey *private_key);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_public_key
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_save_public_key(const char *filename,
- * SilcPublicKey public_key,
- * SilcPKCSFileEncoding encoding);
+ * bool silc_pkcs_save_public_key(const char *filename,
+ * SilcPublicKey public_key,
+ * SilcUInt32 encoding);
*
* DESCRIPTION
*
- * Saves public key into file with specified encoding. Returns FALSE
- * on error.
+ * Saves public key into file. Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_save_public_key(const char *filename,
- SilcPublicKey public_key,
- SilcPKCSFileEncoding encoding);
+bool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
+ SilcUInt32 encoding);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_private_key
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_public_key_data
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_load_private_key(const char *filename,
- * const unsigned char *passphrase,
- * SilcUInt32 passphrase_len,
- * SilcPrivateKey *ret_private_key);
+ * bool silc_pkcs_save_public_key_data(const char *filename,
+ * unsigned char *data,
+ * SilcUInt32 data_len,
+ * SilcUInt32 encoding);
*
* DESCRIPTION
*
- * Loads private key from file and allocates new private key. Returns TRUE
- * if loading was successful. The `passphrase' is used as decryption
- * key of the private key file, in case it is encrypted.
+ * Saves public key into file. The public key is already encoded as
+ * data when calling this function. Returns FALSE on error.
*
***/
-SilcBool silc_pkcs_load_private_key(const char *filename,
- const unsigned char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPrivateKey *ret_private_key);
+bool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
+ SilcUInt32 data_len, SilcUInt32 encoding);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_private_key
*
* SYNOPSIS
*
- * SilcBool silc_pkcs_save_private_key(const char *filename,
- * SilcPrivateKey private_key,
- * const unsigned char *passphrase,
- * SilcUInt32 passphrase_len,
- * SilcPKCSFileEncoding encoding,
- * SilcRng rng);
+ * bool silc_pkcs_save_private_key(const char *filename,
+ * SilcPrivateKey private_key,
+ * unsigned char *passphrase,
+ * SilcUInt32 passphrase_len,
+ * SilcUInt32 encoding);
*
* DESCRIPTION
*
* Saves private key into file. The private key is encrypted into
- * the file with the `passphrase' as a key, if PKCS supports encrypted
- * private keys. Returns FALSE on error.
+ * the file with the `passphrase' as a key. The encryption algorithm
+ * is AES with 256 bit key in CBC mode. Returns FALSE on error.
+ *
+ ***/
+bool silc_pkcs_save_private_key(const char *filename,
+ SilcPrivateKey private_key,
+ unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
+ SilcUInt32 encoding);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_load_public_key(const char *filename,
+ * SilcPublicKey *public_key,
+ * SilcUInt32 encoding);
+ *
+ * DESCRIPTION
+ *
+ * Loads public key from file and allocates new public key. Returns TRUE
+ * if loading was successful.
+ *
+ ***/
+bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
+ SilcUInt32 encoding);
+
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_private_key
+ *
+ * SYNOPSIS
+ *
+ * bool silc_pkcs_load_private_key(const char *filename,
+ * SilcPrivateKey *private_key,
+ * unsigned char *passphrase,
+ * SilcUInt32 passphrase_len,
+ * SilcUInt32 encoding);
+ *
+ * DESCRIPTION
+ *
+ * Loads private key from file and allocates new private key. Returns TRUE
+ * if loading was successful. The `passphrase' is used as decryption
+ * key of the private key file.
*
***/
-SilcBool silc_pkcs_save_private_key(const char *filename,
- SilcPrivateKey private_key,
- const unsigned char *passphrase,
- SilcUInt32 passphrase_len,
- SilcPKCSFileEncoding encoding,
- SilcRng rng);
+bool silc_pkcs_load_private_key(const char *filename,
+ SilcPrivateKey *private_key,
+ unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
+ SilcUInt32 encoding);
#endif /* !SILCPKCS_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2003 - 2007 Pekka Riikonen
+ Copyright (C) 2003 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
*/
/* $Id$ */
-#include "silc.h"
-#include "rsa.h"
-#include "silcpkcs1_i.h"
-
-/************************** PKCS #1 message format ***************************/
+#include "silcincludes.h"
+#include "silcpkcs1.h"
/* Minimum padding in block */
#define SILC_PKCS1_MIN_PADDING 8
set when `bt' is SILC_PKCS1_BT_PUB. This function returns TRUE on
success. */
-SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
- const unsigned char *data,
- SilcUInt32 data_len,
- unsigned char *dest_data,
- SilcUInt32 dest_data_size,
- SilcRng rng)
+bool silc_pkcs1_encode(SilcPkcs1BlockType bt,
+ const unsigned char *data,
+ SilcUInt32 data_len,
+ unsigned char *dest_data,
+ SilcUInt32 dest_data_size,
+ SilcRng rng)
{
SilcInt32 padlen;
int i;
SILC_LOG_DEBUG(("PKCS#1 encoding, bt %d", bt));
if (!data || !dest_data ||
- dest_data_size < SILC_PKCS1_MIN_PADDING + 3 ||
- dest_data_size < data_len) {
+ dest_data_size < 3 || dest_data_size < data_len) {
SILC_LOG_DEBUG(("Data to be encoded is too long"));
return FALSE;
}
case SILC_PKCS1_BT_PUB:
/* Encryption */
- if (!rng) {
- SILC_LOG_ERROR(("Cannot encrypt: random number generator not provided"));
- return FALSE;
- }
/* It is guaranteed this routine does not return zero byte. */
- for (i = 2; i < padlen; i++)
- dest_data[i] = silc_rng_get_byte_fast(rng);
-
+ if (rng)
+ for (i = 2; i < padlen; i++)
+ dest_data[i] = silc_rng_get_byte_fast(rng);
+ else
+ for (i = 2; i < padlen; i++)
+ dest_data[i] = silc_rng_global_get_byte_fast();
break;
}
the deocded block does not fit to `dest_data' this returns FALSE.
Returns TRUE on success. */
-SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt,
- const unsigned char *data,
- SilcUInt32 data_len,
- unsigned char *dest_data,
- SilcUInt32 dest_data_size,
- SilcUInt32 *dest_len)
+bool silc_pkcs1_decode(SilcPkcs1BlockType bt,
+ const unsigned char *data,
+ SilcUInt32 data_len,
+ unsigned char *dest_data,
+ SilcUInt32 dest_data_size,
+ SilcUInt32 *dest_len)
{
int i = 0;
return TRUE;
}
-
-
-/***************************** PKCS #1 PKCS API ******************************/
-
-/* Generates RSA key pair. */
-
-SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen,
- SilcRng rng,
- void **ret_public_key,
- void **ret_private_key)
-{
- SilcUInt32 prime_bits = keylen / 2;
- SilcMPInt p, q;
- SilcBool found = FALSE;
-
- if (keylen < 768 || keylen > 16384)
- return FALSE;
-
- silc_mp_init(&p);
- silc_mp_init(&q);
-
- /* Find p and q */
- while (!found) {
- silc_math_gen_prime(&p, prime_bits, FALSE, rng);
- silc_math_gen_prime(&q, prime_bits, FALSE, rng);
- if ((silc_mp_cmp(&p, &q)) != 0)
- found = TRUE;
- }
-
- /* If p is smaller than q, switch them */
- if ((silc_mp_cmp(&p, &q)) > 0) {
- SilcMPInt hlp;
- silc_mp_init(&hlp);
-
- silc_mp_set(&hlp, &p);
- silc_mp_set(&p, &q);
- silc_mp_set(&q, &hlp);
-
- silc_mp_uninit(&hlp);
- }
-
- /* Generate the actual keys */
- if (!silc_rsa_generate_keys(keylen, &p, &q, ret_public_key, ret_private_key))
- return FALSE;
-
- silc_mp_uninit(&p);
- silc_mp_uninit(&q);
-
- return TRUE;
-}
-
-/* Import PKCS #1 compliant public key */
-
-int silc_pkcs1_import_public_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_public_key)
-{
- SilcAsn1 asn1 = NULL;
- SilcBufferStruct alg_key;
- RsaPublicKey *pubkey;
-
- if (!ret_public_key)
- return 0;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- return 0;
-
- /* Allocate RSA public key */
- *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
- if (!pubkey)
- goto err;
-
- /* Parse the PKCS #1 public key */
- silc_buffer_set(&alg_key, key, key_len);
- if (!silc_asn1_decode(asn1, &alg_key,
- SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_INT(&pubkey->n),
- SILC_ASN1_INT(&pubkey->e),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- /* Set key length */
- pubkey->bits = ((silc_mp_sizeinbase(&pubkey->n, 2) + 7) / 8) * 8;
-
- silc_asn1_free(asn1);
-
- return key_len;
-
- err:
- silc_free(pubkey);
- silc_asn1_free(asn1);
- return 0;
-}
-
-/* Export PKCS #1 compliant public key */
-
-unsigned char *silc_pkcs1_export_public_key(void *public_key,
- SilcUInt32 *ret_len)
-{
- RsaPublicKey *key = public_key;
- SilcAsn1 asn1 = NULL;
- SilcBufferStruct alg_key;
- unsigned char *ret;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- goto err;
-
- /* Encode to PKCS #1 public key */
- memset(&alg_key, 0, sizeof(alg_key));
- if (!silc_asn1_encode(asn1, &alg_key,
- SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_INT(&key->n),
- SILC_ASN1_INT(&key->e),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- ret = silc_buffer_steal(&alg_key, ret_len);
- silc_asn1_free(asn1);
-
- return ret;
-
- err:
- if (asn1)
- silc_asn1_free(asn1);
- return NULL;
-}
-
-/* Returns key length */
-
-SilcUInt32 silc_pkcs1_public_key_bitlen(void *public_key)
-{
- RsaPublicKey *key = public_key;
- return key->bits;
-}
-
-/* Copy public key */
-
-void *silc_pkcs1_public_key_copy(void *public_key)
-{
- RsaPublicKey *key = public_key, *new_key;
-
- new_key = silc_calloc(1, sizeof(*new_key));
- if (!new_key)
- return NULL;
-
- silc_mp_init(&new_key->n);
- silc_mp_init(&new_key->e);
- silc_mp_set(&new_key->n, &key->n);
- silc_mp_set(&new_key->e, &key->e);
- new_key->bits = key->bits;
-
- return new_key;
-}
-
-/* Compare public keys */
-
-SilcBool silc_pkcs1_public_key_compare(void *key1, void *key2)
-{
- RsaPublicKey *k1 = key1, *k2 = key2;
-
- if (k1->bits != k2->bits)
- return FALSE;
- if (silc_mp_cmp(&k1->e, &k2->e) != 0)
- return FALSE;
- if (silc_mp_cmp(&k1->n, &k2->n) != 0)
- return FALSE;
-
- return TRUE;
-}
-
-/* Frees public key */
-
-void silc_pkcs1_public_key_free(void *public_key)
-{
- RsaPublicKey *key = public_key;
-
- silc_mp_uninit(&key->n);
- silc_mp_uninit(&key->e);
- silc_free(key);
-}
-
-/* Import PKCS #1 compliant private key */
-
-int silc_pkcs1_import_private_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_private_key)
-{
- SilcAsn1 asn1;
- SilcBufferStruct alg_key;
- RsaPrivateKey *privkey;
- SilcUInt32 ver;
-
- if (!ret_private_key)
- return 0;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- return 0;
-
- /* Allocate RSA private key */
- *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey));
- if (!privkey)
- goto err;
-
- /* Parse the PKCS #1 private key */
- silc_buffer_set(&alg_key, key, key_len);
- if (!silc_asn1_decode(asn1, &alg_key,
- SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SHORT_INT(&ver),
- SILC_ASN1_INT(&privkey->n),
- SILC_ASN1_INT(&privkey->e),
- SILC_ASN1_INT(&privkey->d),
- SILC_ASN1_INT(&privkey->p),
- SILC_ASN1_INT(&privkey->q),
- SILC_ASN1_INT(&privkey->dP),
- SILC_ASN1_INT(&privkey->dQ),
- SILC_ASN1_INT(&privkey->qP),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- if (ver != 0)
- goto err;
-
- /* Set key length */
- privkey->bits = ((silc_mp_sizeinbase(&privkey->n, 2) + 7) / 8) * 8;
-
- silc_asn1_free(asn1);
-
- return key_len;
-
- err:
- silc_free(privkey);
- silc_asn1_free(asn1);
- return 0;
-}
-
-/* Export PKCS #1 compliant private key */
-
-unsigned char *silc_pkcs1_export_private_key(void *private_key,
- SilcUInt32 *ret_len)
-{
- RsaPrivateKey *key = private_key;
- SilcAsn1 asn1;
- SilcBufferStruct alg_key;
- unsigned char *ret;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- return FALSE;
-
- /* Encode to PKCS #1 private key */
- memset(&alg_key, 0, sizeof(alg_key));
- if (!silc_asn1_encode(asn1, &alg_key,
- SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SHORT_INT(0),
- SILC_ASN1_INT(&key->n),
- SILC_ASN1_INT(&key->e),
- SILC_ASN1_INT(&key->d),
- SILC_ASN1_INT(&key->p),
- SILC_ASN1_INT(&key->q),
- SILC_ASN1_INT(&key->dP),
- SILC_ASN1_INT(&key->dQ),
- SILC_ASN1_INT(&key->qP),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- ret = silc_buffer_steal(&alg_key, ret_len);
- silc_asn1_free(asn1);
-
- return ret;
-
- err:
- silc_asn1_free(asn1);
- return NULL;
-}
-
-/* Returns key length */
-
-SilcUInt32 silc_pkcs1_private_key_bitlen(void *private_key)
-{
- RsaPrivateKey *key = private_key;
- return key->bits;
-}
-
-/* Frees private key */
-
-void silc_pkcs1_private_key_free(void *private_key)
-{
- RsaPrivateKey *key = private_key;
-
- silc_mp_uninit(&key->n);
- silc_mp_uninit(&key->e);
- silc_mp_uninit(&key->d);
- silc_mp_uninit(&key->dP);
- silc_mp_uninit(&key->dQ);
- silc_mp_uninit(&key->qP);
- silc_mp_uninit(&key->p);
- silc_mp_uninit(&key->q);
- silc_free(key);
-}
-
-/* PKCS #1 RSA routines */
-
-SilcBool silc_pkcs1_encrypt(void *public_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len,
- SilcRng rng)
-{
- RsaPublicKey *key = public_key;
- SilcMPInt mp_tmp;
- SilcMPInt mp_dst;
- unsigned char padded[2048 + 1];
- SilcUInt32 len = (key->bits + 7) / 8;
-
- if (sizeof(padded) < len)
- return FALSE;
- if (dst_size < len)
- return FALSE;
-
- /* Pad data */
- if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len,
- padded, len, rng))
- return FALSE;
-
- silc_mp_init(&mp_tmp);
- silc_mp_init(&mp_dst);
-
- /* Data to MP */
- silc_mp_bin2mp(padded, len, &mp_tmp);
-
- /* Encrypt */
- silc_rsa_public_operation(key, &mp_tmp, &mp_dst);
-
- /* MP to data */
- silc_mp_mp2bin_noalloc(&mp_dst, dst, len);
- *ret_dst_len = len;
-
- memset(padded, 0, sizeof(padded));
- silc_mp_uninit(&mp_tmp);
- silc_mp_uninit(&mp_dst);
-
- return TRUE;
-}
-
-SilcBool silc_pkcs1_decrypt(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len)
-{
- RsaPrivateKey *key = private_key;
- SilcMPInt mp_tmp;
- SilcMPInt mp_dst;
- unsigned char *padded, unpadded[2048 + 1];
- SilcUInt32 padded_len;
-
- if (dst_size < (key->bits + 7) / 8)
- return FALSE;
-
- silc_mp_init(&mp_tmp);
- silc_mp_init(&mp_dst);
-
- /* Data to MP */
- silc_mp_bin2mp(src, src_len, &mp_tmp);
-
- /* Decrypt */
- silc_rsa_private_operation(key, &mp_tmp, &mp_dst);
-
- /* MP to data */
- padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len);
-
- /* Unpad data */
- if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len,
- unpadded, sizeof(unpadded), ret_dst_len)) {
- memset(padded, 0, padded_len);
- silc_free(padded);
- silc_mp_uninit(&mp_tmp);
- silc_mp_uninit(&mp_dst);
- return FALSE;
- }
-
- /* Copy to destination */
- memcpy(dst, unpadded, *ret_dst_len);
-
- memset(padded, 0, padded_len);
- memset(unpadded, 0, sizeof(unpadded));
- silc_free(padded);
- silc_mp_uninit(&mp_tmp);
- silc_mp_uninit(&mp_dst);
-
- return TRUE;
-}
-
-/* PKCS #1 sign with appendix, hash OID included in the signature */
-
-SilcBool silc_pkcs1_sign(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash)
-{
- RsaPrivateKey *key = private_key;
- unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
- SilcMPInt mp_tmp;
- SilcMPInt mp_dst;
- SilcBufferStruct di;
- SilcUInt32 len = (key->bits + 7) / 8;
- const char *oid;
- SilcAsn1 asn1;
-
- SILC_LOG_DEBUG(("Sign"));
-
- if (sizeof(padded) < len)
- return FALSE;
- if (signature_size < len)
- return FALSE;
-
- oid = silc_hash_get_oid(hash);
- if (!oid)
- return FALSE;
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- return FALSE;
-
- /* Compute hash */
- if (compute_hash) {
- silc_hash_make(hash, src, src_len, hashr);
- src = hashr;
- src_len = silc_hash_len(hash);
- }
-
- /* Encode digest info */
- memset(&di, 0, sizeof(di));
- if (!silc_asn1_encode(asn1, &di,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_OID(oid),
- SILC_ASN1_NULL,
- SILC_ASN1_END,
- SILC_ASN1_OCTET_STRING(src, src_len),
- SILC_ASN1_END, SILC_ASN1_END)) {
- silc_asn1_free(asn1);
- return FALSE;
- }
- SILC_LOG_HEXDUMP(("DigestInfo"), silc_buffer_data(&di),
- silc_buffer_len(&di));
-
- /* Pad data */
- if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, silc_buffer_data(&di),
- silc_buffer_len(&di), padded, len, NULL)) {
- silc_asn1_free(asn1);
- return FALSE;
- }
-
- silc_mp_init(&mp_tmp);
- silc_mp_init(&mp_dst);
-
- /* Data to MP */
- silc_mp_bin2mp(padded, len, &mp_tmp);
-
- /* Sign */
- silc_rsa_private_operation(key, &mp_tmp, &mp_dst);
-
- /* MP to data */
- silc_mp_mp2bin_noalloc(&mp_dst, signature, len);
- *ret_signature_len = len;
-
- memset(padded, 0, sizeof(padded));
- silc_mp_uninit(&mp_tmp);
- silc_mp_uninit(&mp_dst);
- if (compute_hash)
- memset(hashr, 0, sizeof(hashr));
- silc_asn1_free(asn1);
-
- return TRUE;
-}
-
-/* PKCS #1 verification with appendix. */
-
-SilcBool silc_pkcs1_verify(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash)
-{
- RsaPublicKey *key = public_key;
- SilcBool ret = FALSE;
- SilcMPInt mp_tmp2;
- SilcMPInt mp_dst;
- unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
- SilcUInt32 verify_len, len = (key->bits + 7) / 8;
- SilcBufferStruct di, ldi;
- SilcHash ihash = NULL;
- SilcAsn1 asn1 = NULL;
- char *oid;
-
- SILC_LOG_DEBUG(("Verify signature"));
-
- asn1 = silc_asn1_alloc();
- if (!asn1)
- return FALSE;
-
- silc_mp_init(&mp_tmp2);
- silc_mp_init(&mp_dst);
-
- /* Format the signature into MP int */
- silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
-
- /* Verify */
- silc_rsa_public_operation(key, &mp_tmp2, &mp_dst);
-
- /* MP to data */
- verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);
-
- /* Unpad data */
- if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
- unpadded, sizeof(unpadded), &len))
- goto err;
- silc_buffer_set(&di, unpadded, len);
-
- /* If hash isn't given, allocate the one given in digest info */
- if (!hash) {
- /* Decode digest info */
- if (!silc_asn1_decode(asn1, &di,
- SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_OID(&oid),
- SILC_ASN1_END,
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- if (!silc_hash_alloc_by_oid(oid, &ihash)) {
- SILC_LOG_DEBUG(("Unknown OID %s", oid));
- goto err;
- }
- hash = ihash;
- }
-
- /* Hash the data */
- silc_hash_make(hash, data, data_len, hashr);
- data = hashr;
- data_len = silc_hash_len(hash);
- oid = (char *)silc_hash_get_oid(hash);
-
- /* Encode digest info for comparison */
- memset(&ldi, 0, sizeof(ldi));
- if (!silc_asn1_encode(asn1, &ldi,
- SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_SEQUENCE,
- SILC_ASN1_OID(oid),
- SILC_ASN1_NULL,
- SILC_ASN1_END,
- SILC_ASN1_OCTET_STRING(data, data_len),
- SILC_ASN1_END, SILC_ASN1_END))
- goto err;
-
- SILC_LOG_HEXDUMP(("DigestInfo remote"), silc_buffer_data(&di),
- silc_buffer_len(&di));
- SILC_LOG_HEXDUMP(("DigestInfo local"), silc_buffer_data(&ldi),
- silc_buffer_len(&ldi));
-
- /* Compare */
- if (silc_buffer_len(&di) == silc_buffer_len(&ldi) &&
- !memcmp(silc_buffer_data(&di), silc_buffer_data(&ldi),
- silc_buffer_len(&ldi)))
- ret = TRUE;
-
- memset(verify, 0, verify_len);
- memset(unpadded, 0, sizeof(unpadded));
- silc_free(verify);
- silc_mp_uninit(&mp_tmp2);
- silc_mp_uninit(&mp_dst);
- if (hash)
- memset(hashr, 0, sizeof(hashr));
- if (ihash)
- silc_hash_free(ihash);
- silc_asn1_free(asn1);
-
- return ret;
-
- err:
- memset(verify, 0, verify_len);
- silc_free(verify);
- silc_mp_uninit(&mp_tmp2);
- silc_mp_uninit(&mp_dst);
- if (ihash)
- silc_hash_free(ihash);
- silc_asn1_free(asn1);
- return FALSE;
-}
-
-/* PKCS #1 sign without hash oid */
-
-SilcBool silc_pkcs1_sign_no_oid(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash)
-{
- RsaPrivateKey *key = private_key;
- SilcMPInt mp_tmp;
- SilcMPInt mp_dst;
- unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
- SilcUInt32 len = (key->bits + 7) / 8;
-
- SILC_LOG_DEBUG(("Sign"));
-
- if (sizeof(padded) < len)
- return FALSE;
- if (signature_size < len)
- return FALSE;
-
- /* Compute hash if requested */
- if (compute_hash) {
- silc_hash_make(hash, src, src_len, hashr);
- src = hashr;
- src_len = silc_hash_len(hash);
- }
-
- /* Pad data */
- if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len,
- padded, len, NULL))
- return FALSE;
-
- silc_mp_init(&mp_tmp);
- silc_mp_init(&mp_dst);
-
- /* Data to MP */
- silc_mp_bin2mp(padded, len, &mp_tmp);
-
- /* Sign */
- silc_rsa_private_operation(key, &mp_tmp, &mp_dst);
-
- /* MP to data */
- silc_mp_mp2bin_noalloc(&mp_dst, signature, len);
- *ret_signature_len = len;
-
- memset(padded, 0, sizeof(padded));
- silc_mp_uninit(&mp_tmp);
- silc_mp_uninit(&mp_dst);
- if (compute_hash)
- memset(hashr, 0, sizeof(hashr));
-
- return TRUE;
-}
-
-/* PKCS #1 verify without hash oid */
-
-SilcBool silc_pkcs1_verify_no_oid(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash)
-{
- RsaPublicKey *key = public_key;
- SilcBool ret = FALSE;
- SilcMPInt mp_tmp2;
- SilcMPInt mp_dst;
- unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
- SilcUInt32 verify_len, len = (key->bits + 7) / 8;
-
- SILC_LOG_DEBUG(("Verify signature"));
-
- silc_mp_init(&mp_tmp2);
- silc_mp_init(&mp_dst);
-
- /* Format the signature into MP int */
- silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
-
- /* Verify */
- silc_rsa_public_operation(key, &mp_tmp2, &mp_dst);
-
- /* MP to data */
- verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);
-
- /* Unpad data */
- if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
- unpadded, sizeof(unpadded), &len)) {
- memset(verify, 0, verify_len);
- silc_free(verify);
- silc_mp_uninit(&mp_tmp2);
- silc_mp_uninit(&mp_dst);
- return FALSE;
- }
-
- /* Hash data if requested */
- if (hash) {
- silc_hash_make(hash, data, data_len, hashr);
- data = hashr;
- data_len = silc_hash_len(hash);
- }
-
- /* Compare */
- if (len == data_len && !memcmp(data, unpadded, len))
- ret = TRUE;
-
- memset(verify, 0, verify_len);
- memset(unpadded, 0, sizeof(unpadded));
- silc_free(verify);
- silc_mp_uninit(&mp_tmp2);
- silc_mp_uninit(&mp_dst);
- if (hash)
- memset(hashr, 0, sizeof(hashr));
-
- return ret;
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2003 - 2005 Pekka Riikonen
+ Copyright (C) 2003 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
*
* SYNOPSIS
*
- * SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
- * const unsigned char *data,
- * SilcUInt32 data_len,
- * unsigned char *dest_data,
- * SilcUInt32 dest_data_size,
- * SilcRng rng);
+ * bool silc_pkcs1_encode(SilcPkcs1BlockType bt,
+ * const unsigned char *data,
+ * SilcUInt32 data_len,
+ * unsigned char *dest_data,
+ * SilcUInt32 dest_data_size,
+ * SilcRng rng);
*
* DESCRIPTION
*
* function returns TRUE on success.
*
***/
-SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
- const unsigned char *data,
- SilcUInt32 data_len,
- unsigned char *dest_data,
- SilcUInt32 dest_data_size,
- SilcRng rng);
+bool silc_pkcs1_encode(SilcPkcs1BlockType bt,
+ const unsigned char *data,
+ SilcUInt32 data_len,
+ unsigned char *dest_data,
+ SilcUInt32 dest_data_size,
+ SilcRng rng);
/****f* silccrypt/SilcPKCS1API/silc_pkcs1_decode
*
* SYNOPSIS
*
- * SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt,
- * const unsigned char *data,
- * SilcUInt32 data_len,
- * unsigned char *dest_data,
- * SilcUInt32 dest_data_size,
- * SilcUInt32 *dest_len);
+ * bool silc_pkcs1_decode(SilcPkcs1BlockType bt,
+ * const unsigned char *data,
+ * SilcUInt32 data_len,
+ * unsigned char *dest_data,
+ * SilcUInt32 dest_data_size,
+ * SilcUInt32 *dest_len);
*
* DESCRIPTION
*
* Returns the decoded length into `dest_len'.
*
***/
-SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt,
- const unsigned char *data,
- SilcUInt32 data_len,
- unsigned char *dest_data,
- SilcUInt32 dest_data_size,
- SilcUInt32 *dest_len);
+bool silc_pkcs1_decode(SilcPkcs1BlockType bt,
+ const unsigned char *data,
+ SilcUInt32 data_len,
+ unsigned char *dest_data,
+ SilcUInt32 dest_data_size,
+ SilcUInt32 *dest_len);
#endif /* SILCPKCS1_H */
+++ /dev/null
-/*
-
- silcpkcs1_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C); 2006 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 SILCPKCS1_I_H
-#define SILCPKCS1_I_H
-
-SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen,
- SilcRng rng,
- void **ret_public_key,
- void **ret_private_key);
-int silc_pkcs1_import_public_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_public_key);
-unsigned char *silc_pkcs1_export_public_key(void *public_key,
- SilcUInt32 *ret_len);
-SilcUInt32 silc_pkcs1_public_key_bitlen(void *public_key);
-void *silc_pkcs1_public_key_copy(void *public_key);
-SilcBool silc_pkcs1_public_key_compare(void *key1, void *key2);
-void silc_pkcs1_public_key_free(void *public_key);
-int silc_pkcs1_import_private_key(unsigned char *key,
- SilcUInt32 key_len,
- void **ret_private_key);
-unsigned char *silc_pkcs1_export_private_key(void *private_key,
- SilcUInt32 *ret_len);
-SilcUInt32 silc_pkcs1_private_key_bitlen(void *private_key);
-void silc_pkcs1_private_key_free(void *private_key);
-SilcBool silc_pkcs1_encrypt(void *public_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len,
- SilcRng rng);
-SilcBool silc_pkcs1_decrypt(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *dst,
- SilcUInt32 dst_size,
- SilcUInt32 *ret_dst_len);
-SilcBool silc_pkcs1_sign(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash);
-SilcBool silc_pkcs1_verify(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash);
-SilcBool silc_pkcs1_sign_no_oid(void *private_key,
- unsigned char *src,
- SilcUInt32 src_len,
- unsigned char *signature,
- SilcUInt32 signature_size,
- SilcUInt32 *ret_signature_len,
- SilcBool compute_hash,
- SilcHash hash);
-SilcBool silc_pkcs1_verify_no_oid(void *public_key,
- unsigned char *signature,
- SilcUInt32 signature_len,
- unsigned char *data,
- SilcUInt32 data_len,
- SilcHash hash);
-
-#endif /* SILCPKCS1_I_H */
* This RNG has been rewritten twice since the creation.
*/
-#include "silc.h"
+#include "silcincludes.h"
#ifndef WIN32
#ifdef HAVE_GETSID
silc_rng_xor(rng, (r.ru_utime.tv_sec ^ r.ru_utime.tv_usec), pos++);
silc_rng_xor(rng, (r.ru_stime.tv_sec + r.ru_stime.tv_usec), pos++);
silc_rng_xor(rng, (r.ru_stime.tv_sec ^ r.ru_stime.tv_usec), pos++);
-#ifndef SILC_SYMBIAN
silc_rng_xor(rng, (r.ru_maxrss + r.ru_ixrss), pos++);
silc_rng_xor(rng, (r.ru_maxrss ^ r.ru_ixrss), pos++);
silc_rng_xor(rng, (r.ru_idrss + r.ru_idrss), pos++);
silc_rng_xor(rng, (r.ru_nsignals << 16), pos++);
silc_rng_xor(rng, (r.ru_nvcsw + r.ru_nivcsw), pos++);
silc_rng_xor(rng, (r.ru_nvcsw ^ r.ru_nivcsw), pos++);
-#endif /* SILC_SYMBIAN */
-#endif /* HAVE_GETRUSAGE */
+#endif
#ifdef SILC_RNG_DEBUG
SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
static void silc_rng_get_hard_noise(SilcRng rng)
{
-#if defined(SILC_UNIX)
+#ifndef SILC_WIN32
unsigned char buf[32];
int fd, len, i;
static void silc_rng_exec_command(SilcRng rng, char *command)
{
-#if defined(SILC_UNIX)
+#ifndef SILC_WIN32
unsigned char buf[1024];
FILE *fd;
int i;
SilcUInt8 silc_rng_get_byte_fast(SilcRng rng)
{
-#if defined(SILC_UNIX)
+#ifndef SILC_WIN32
unsigned char buf[1];
if (rng->fd_devurandom == -1) {
/* Initialize global RNG. If `rng' is provided it is set as the global
RNG object (it can be allocated by the application for example). */
-SilcBool silc_rng_global_init(SilcRng rng)
+bool silc_rng_global_init(SilcRng rng)
{
if (rng) {
global_rng = rng;
/* Uninitialize global RNG */
-SilcBool silc_rng_global_uninit(void)
+bool silc_rng_global_uninit(void)
{
if (global_rng) {
silc_rng_free(global_rng);
*
* SYNOPSIS
*
- * SilcBool silc_rng_global_init(SilcRng rng);
+ * bool silc_rng_global_init(SilcRng rng);
*
* DESCRIPTION
*
* the RNG as argument.
*
***/
-SilcBool silc_rng_global_init(SilcRng rng);
+bool silc_rng_global_init(SilcRng rng);
/****f* silccrypt/SilcRNGAPI/silc_rng_global_uninit
*
* SYNOPSIS
*
- * SilcBool silc_rng_global_uninit(void);
+ * bool silc_rng_global_uninit(void);
*
* DESCRIPTION
*
* be called if silc_rng_global_init was called with non-NULL RNG.
*
***/
-SilcBool silc_rng_global_uninit(void);
+bool silc_rng_global_uninit(void);
/****f* silccrypt/SilcRNGAPI/silc_rng_global_get_byte
*
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from RFC3602. */
int p2_len = 32;
const unsigned char c2[] = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a\x3a\x86\x30\x28\xb5\xe1\xdc\x0a\x75\x86\x60\x2d\x25\x3c\xff\xf9\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1";
-/* CTR test vectors from RFC3686. */
-
-/* 16 bytes plaintext, 128 bits key */
-const unsigned char key3[] = "\xAE\x68\x52\xF8\x12\x10\x67\xCC\x4B\xF7\xA5\x76\x55\x77\xF3\x9E";
-int key3_len = 16 * 8;
-const unsigned char iv3[] = "\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
-const unsigned char p3[] = "Single block msg";
-int p3_len = 16;
-const unsigned char c3[] = "\xE4\x09\x5D\x4F\xB7\xA7\xB3\x79\x2D\x61\x75\xA3\x26\x13\x11\xB8";
-
-/* 32 bytes plaintext, 128 bits key */
-const unsigned char key4[] = "\x7E\x24\x06\x78\x17\xFA\xE0\xD7\x43\xD6\xCE\x1F\x32\x53\x91\x63";
-int key4_len = 16 * 8;
-const unsigned char iv4[] = "\x00\x6C\xB6\xDB\xC0\x54\x3B\x59\xDA\x48\xD9\x0B\x00\x00\x00\x00";
-const unsigned char p4[] = "\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";
-int p4_len = 32;
-const unsigned char c4[] = "\x51\x04\xA1\x06\x16\x8A\x72\xD9\x79\x0D\x41\xEE\x8E\xDA\xD3\x88\xEB\x2E\x1E\xFC\x46\xDA\x57\xC8\xFC\xE6\x30\xDF\x91\x41\xBE\x28";
-
-/* 36 bytes plaintext, 256 bits key */
-const unsigned char key5[] = "\xFF\x7A\x61\x7C\xE6\x91\x48\xE4\xF1\x72\x6E\x2F\x43\x58\x1D\xE2\xAA\x62\xD9\xF8\x05\x53\x2E\xDF\xF1\xEE\xD6\x87\xFB\x54\x15\x3D";
-int key5_len = 32 * 8;
-const unsigned char iv5[] = "\x00\x1C\xC5\xB7\x51\xA5\x1D\x70\xA1\xC1\x11\x48\x00\x00\x00\x00";
-const unsigned char p5[] = "\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\x20\x21\x22\x23";
-int p5_len = 36;
-const unsigned char c5[] = "\xEB\x6C\x52\x82\x1D\x0B\xBB\xF7\xCE\x75\x94\x46\x2A\xCA\x4F\xAA\xB4\x07\xDF\x86\x65\x69\xFD\x07\xF4\x8C\xC0\xB5\x83\xD6\x07\x1F\x1E\xC0\xE6\xB8";
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
- SilcCipher cipher, cipher2;
+ bool success = FALSE;
+ SilcCipher cipher;
unsigned char dst[256], pdst[256];
int i;
SILC_LOG_DEBUG(("Registering builtin hash functions"));
silc_cipher_register_default();
- SILC_LOG_DEBUG(("Allocating AES-CBC cipher"));
- if (!silc_cipher_alloc("aes-128-cbc", &cipher)) {
- SILC_LOG_DEBUG(("Allocating AES-CBC cipher failed"));
+ if (!silc_cipher_is_supported("aes-128-cbc")) {
+ SILC_LOG_DEBUG(("aes-128-cbc is not supported"));
goto err;
}
- if (!silc_cipher_alloc("aes-128-cbc", &cipher2)) {
+
+ SILC_LOG_DEBUG(("Allocating AES-CBC cipher"));
+ if (!silc_cipher_alloc("aes-128-cbc", &cipher)) {
SILC_LOG_DEBUG(("Allocating AES-CBC cipher failed"));
goto err;
}
memset(dst, 0, sizeof(dst));
memset(pdst, 0, sizeof(pdst));
silc_cipher_set_iv(cipher, iv1);
- assert(silc_cipher_set_key(cipher, key1, key1_len, TRUE));
- assert(silc_cipher_set_key(cipher2, key1, key1_len, FALSE));
+ assert(silc_cipher_set_key(cipher, key1, key1_len));
assert(silc_cipher_encrypt(cipher, p1, dst, p1_len, NULL));
SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
silc_cipher_get_block_len(cipher),
goto err;
}
SILC_LOG_DEBUG(("Encrypt is successful"));
- silc_cipher_set_iv(cipher2, iv1);
- assert(silc_cipher_decrypt(cipher2, dst, pdst, p1_len, NULL));
+ silc_cipher_set_iv(cipher, iv1);
+ assert(silc_cipher_decrypt(cipher, dst, pdst, p1_len, NULL));
SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p1_len);
SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p1, p1_len);
if (memcmp(pdst, p1, p1_len)) {
memset(dst, 0, sizeof(dst));
memset(pdst, 0, sizeof(pdst));
silc_cipher_set_iv(cipher, iv2);
- assert(silc_cipher_set_key(cipher, key2, key2_len, TRUE));
- assert(silc_cipher_set_key(cipher2, key2, key2_len, FALSE));
+ assert(silc_cipher_set_key(cipher, key2, key2_len));
assert(silc_cipher_encrypt(cipher, p2, dst, p2_len, NULL));
SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
silc_cipher_get_block_len(cipher),
goto err;
}
SILC_LOG_DEBUG(("Encrypt is successful"));
- silc_cipher_set_iv(cipher2, iv2);
- assert(silc_cipher_decrypt(cipher2, dst, pdst, p2_len, NULL));
+ silc_cipher_set_iv(cipher, iv2);
+ assert(silc_cipher_decrypt(cipher, dst, pdst, p2_len, NULL));
SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p2_len);
SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p2, p2_len);
if (memcmp(pdst, p2, p2_len)) {
goto err;
}
SILC_LOG_DEBUG(("Decrypt is successful"));
- silc_cipher_free(cipher);
- silc_cipher_free(cipher2);
-
-
- SILC_LOG_DEBUG(("Allocating aes-128-ctr cipher"));
- if (!silc_cipher_alloc("aes-128-ctr", &cipher)) {
- SILC_LOG_DEBUG(("Allocating aes-128-ctr cipher failed"));
- goto err;
- }
-
- /* Third test vector */
- SILC_LOG_DEBUG(("Third test vector"));
- memset(dst, 0, sizeof(dst));
- memset(pdst, 0, sizeof(pdst));
- silc_cipher_set_iv(cipher, iv3);
- assert(silc_cipher_set_key(cipher, key3, key3_len, TRUE));
- assert(silc_cipher_encrypt(cipher, p3, dst, p3_len, NULL));
- SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
- silc_cipher_get_block_len(cipher),
- silc_cipher_get_key_len(cipher),
- silc_cipher_get_name(cipher)));
- SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p3, p3_len);
- SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p3_len);
- SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c3, p3_len);
- if (memcmp(dst, c3, p3_len)) {
- SILC_LOG_DEBUG(("Encrypt failed"));
- goto err;
- }
- SILC_LOG_DEBUG(("Encrypt is successful"));
- silc_cipher_set_iv(cipher, iv3);
- assert(silc_cipher_decrypt(cipher, dst, pdst, p3_len, NULL));
- SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p3_len);
- SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p3, p3_len);
- if (memcmp(pdst, p3, p3_len)) {
- SILC_LOG_DEBUG(("Decrypt failed"));
- goto err;
- }
- SILC_LOG_DEBUG(("Decrypt is successful"));
-
-
- /* Fourth test vector */
- SILC_LOG_DEBUG(("Fourth test vector"));
- memset(dst, 0, sizeof(dst));
- memset(pdst, 0, sizeof(pdst));
- silc_cipher_set_iv(cipher, iv4);
- assert(silc_cipher_set_key(cipher, key4, key4_len, TRUE));
- assert(silc_cipher_encrypt(cipher, p4, dst, p4_len, NULL));
- SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
- silc_cipher_get_block_len(cipher),
- silc_cipher_get_key_len(cipher),
- silc_cipher_get_name(cipher)));
- SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p4, p4_len);
- SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p4_len);
- SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c4, p4_len);
- if (memcmp(dst, c4, p4_len)) {
- SILC_LOG_DEBUG(("Encrypt failed"));
- goto err;
- }
- SILC_LOG_DEBUG(("Encrypt is successful"));
- silc_cipher_set_iv(cipher, iv4);
- assert(silc_cipher_decrypt(cipher, dst, pdst, p4_len, NULL));
- SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p4_len);
- SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p4, p4_len);
- if (memcmp(pdst, p4, p4_len)) {
- SILC_LOG_DEBUG(("Decrypt failed"));
- goto err;
- }
- SILC_LOG_DEBUG(("Decrypt is successful"));
- silc_cipher_free(cipher);
-
- SILC_LOG_DEBUG(("Allocating aes-256-ctr cipher"));
- if (!silc_cipher_alloc("aes-256-ctr", &cipher)) {
- SILC_LOG_DEBUG(("Allocating aes-256-ctr cipher failed"));
- goto err;
- }
- if (!silc_cipher_alloc("aes-256-ctr", &cipher2)) {
- SILC_LOG_DEBUG(("Allocating aes-256-ctr cipher failed"));
- goto err;
- }
-
- /* Fifth test vector */
- SILC_LOG_DEBUG(("Fifth test vector"));
- memset(dst, 0, sizeof(dst));
- memset(pdst, 0, sizeof(pdst));
- silc_cipher_set_iv(cipher, iv5);
- assert(silc_cipher_set_key(cipher, key5, key5_len, TRUE));
- assert(silc_cipher_set_key(cipher2, key5, key5_len, FALSE));
- assert(silc_cipher_encrypt(cipher, p5, dst, p5_len, NULL));
- SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
- silc_cipher_get_block_len(cipher),
- silc_cipher_get_key_len(cipher),
- silc_cipher_get_name(cipher)));
- SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p5, p5_len);
- SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p5_len);
- SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c5, p5_len);
- if (memcmp(dst, c5, p5_len)) {
- SILC_LOG_DEBUG(("Encrypt failed"));
- goto err;
- }
- SILC_LOG_DEBUG(("Encrypt is successful"));
- silc_cipher_set_iv(cipher2, iv5);
- assert(silc_cipher_decrypt(cipher2, dst, pdst, p5_len, NULL));
- SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p5_len);
- SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p5, p5_len);
- if (memcmp(pdst, p5, p5_len)) {
- SILC_LOG_DEBUG(("Decrypt failed"));
- goto err;
- }
- SILC_LOG_DEBUG(("Decrypt is successful"));
- silc_cipher_free(cipher2);
success = TRUE;
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from RFC 2202 */
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char digest[16];
SilcUInt32 len;
SilcHmac hmac;
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from RFC 2202 */
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char digest[20];
SilcUInt32 len;
SilcHmac hmac;
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from draft-ietf-ipsec-ciph-sha-256-01.txt */
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char digest[20];
SilcUInt32 len;
SilcHmac hmac;
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from RFC 1321 */
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char digest[16];
SilcHash md5;
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from NIST secure hashing definition for SHA-1 */
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char digest[20];
SilcHash sha1;
-#include "silc.h"
+#include "silcincludes.h"
/* Test vectors from NIST secure hashing definition for SHA-256 */
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char digest[20];
SilcHash sha256;
/* Tests API in silcpkcs.h */
-#include "silc.h"
+#include "silcincludes.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";
int test()
{
- SilcBool success = FALSE;
+ bool success = FALSE;
SilcPKCS pkcs;
unsigned char *pk, *prv;
char *identifier;
#include <stdio.h>
#include <stdlib.h>
-#include "silc.h"
+#include "silcincludes.h"
#include "twofish.h"
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "twofish_internal.h"
#include "twofish.h"
-/*
+/*
* SILC Crypto API for Twofish
*/
/* Sets the key for the cipher. */
-SILC_CIPHER_API_SET_KEY(twofish_cbc)
+SILC_CIPHER_API_SET_KEY(twofish)
{
SilcUInt32 k[8];
return TRUE;
}
-/* Sets IV for the cipher. */
+/* Sets the string as a new key for the cipher. The string is first
+ hashed and then used as a new key. */
-SILC_CIPHER_API_SET_IV(twofish_cbc)
+SILC_CIPHER_API_SET_KEY_WITH_STRING(twofish)
{
-
+ return FALSE;
}
/* Returns the size of the cipher context. */
-SILC_CIPHER_API_CONTEXT_LEN(twofish_cbc)
+SILC_CIPHER_API_CONTEXT_LEN(twofish)
{
return sizeof(TwofishContext);
}
/* Encrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_ENCRYPT(twofish_cbc)
+SILC_CIPHER_API_ENCRYPT_CBC(twofish)
{
SilcUInt32 tiv[4];
int i;
- SILC_ASSERT((len & (16 - 1)) == 0);
- if (len & (16 - 1))
- return FALSE;
SILC_CBC_GET_IV(tiv, iv);
SILC_CBC_ENC_PRE(tiv, src);
/* Decrypts with the cipher in CBC mode. Source and destination buffers
maybe one and same. */
-SILC_CIPHER_API_DECRYPT(twofish_cbc)
+SILC_CIPHER_API_DECRYPT_CBC(twofish)
{
SilcUInt32 tmp[4], tmp2[4], tiv[4];
int i;
- if (len & (16 - 1))
- return FALSE;
-
SILC_CBC_GET_IV(tiv, iv);
SILC_CBC_DEC_PRE(tmp, src);
twofish_decrypt((TwofishContext *)context, tmp, tmp2);
SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
}
-
+
SILC_CBC_PUT_IV(tiv, iv);
-
+
return TRUE;
}
u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };
-u1byte qt0[2][16] =
+u1byte qt0[2][16] =
{ { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
{ 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
};
u1byte qt1[2][16] =
-{ { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
+{ { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
{ 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
};
-u1byte qt2[2][16] =
+u1byte qt2[2][16] =
{ { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
{ 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
};
-u1byte qt3[2][16] =
+u1byte qt3[2][16] =
{ { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
{ 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
};
-
+
u1byte qp(const u4byte n, const u1byte x)
{ u1byte a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;
a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
a4 = qt2[n][a3]; b4 = qt3[n][b3];
return (b4 << 4) | a4;
-}
+};
#ifdef Q_TABLES
{ u4byte i;
for(i = 0; i < 256; ++i)
- {
+ {
q(0,i) = qp(0, (u1byte)i);
q(1,i) = qp(1, (u1byte)i);
}
-}
+};
#else
void gen_mtab(void)
{ u4byte i, f01, f5b, fef;
-
+
for(i = 0; i < 256; ++i)
{
f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
}
-}
+};
#define mds(n,x) m_tab[n][x]
return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);
#endif
-}
+};
#ifdef MK_TABLE
mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));
#else
- sb[0][i] = q20(by); sb[1][i] = q21(by);
+ sb[0][i] = q20(by); sb[1][i] = q21(by);
sb[2][i] = q22(by); sb[3][i] = q23(by);
#endif
}
break;
-
+
case 3: for(i = 0; i < 256; ++i)
{
by = (u1byte)i;
mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));
#else
- sb[0][i] = q30(by); sb[1][i] = q31(by);
+ sb[0][i] = q30(by); sb[1][i] = q31(by);
sb[2][i] = q32(by); sb[3][i] = q33(by);
#endif
}
break;
-
+
case 4: for(i = 0; i < 256; ++i)
{
by = (u1byte)i;
mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));
#else
- sb[0][i] = q40(by); sb[1][i] = q41(by);
+ sb[0][i] = q40(by); sb[1][i] = q41(by);
sb[2][i] = q42(by); sb[3][i] = q43(by);
#endif
}
}
-}
+};
# ifdef ONE_STEP
# define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
where the coefficients are in the finite field GF(2^8) with a
modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
remainder we have to start with a 12th order polynomial with our
-eight input bytes as the coefficients of the 4th to 11th terms.
+eight input bytes as the coefficients of the 4th to 11th terms.
That is:
m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0
-
+
We then multiply the generator polynomial by m[7] * x^7 and subtract
-it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
-artihmetic on the coefficients is done in GF(2^8). We then multiply
+it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
+artihmetic on the coefficients is done in GF(2^8). We then multiply
the generator polynomial by x^6 * coeff(x^10) and use this to remove
the x^10 term. We carry on in this way until the x^4 term is removed
so that we are left with:
r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]
-which give the resulting 4 bytes of the remainder. This is equivalent
-to the matrix multiplication in the Twofish description but much faster
+which give the resulting 4 bytes of the remainder. This is equivalent
+to the matrix multiplication in the Twofish description but much faster
to implement.
*/
for(i = 0; i < 8; ++i)
{
t = p1 >> 24; /* get most significant coefficient */
-
+
p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8; /* shift others up */
-
+
/* multiply t by a (the primitive element - i.e. left shift) */
- u = (t << 1);
-
+ u = (t << 1);
+
if(t & 0x80) /* subtract modular polynomial on overflow */
-
- u ^= G_MOD;
+
+ u ^= G_MOD;
p1 ^= t ^ (u << 16); /* remove t * (a * x^2 + 1) */
u ^= (t >> 1); /* form u = a * t + t / a = t * (a + 1 / a); */
-
+
if(t & 0x01) /* add the modular polynomial on underflow */
-
+
u ^= G_MOD >> 1;
p1 ^= (u << 24) | (u << 8); /* remove t * (a + 1/a) * (x^3 + x) */
}
return p1;
-}
+};
/* initialise the key schedule from the user supplied key */
u4byte *twofish_set_key(TwofishContext *ctx,
const u4byte in_key[], const u4byte key_len)
-{
+{
u4byte i, a, b, me_key[4], mo_key[4];
u4byte *l_key = ctx->l_key;
u4byte *s_key = ctx->s_key;
-
+
#ifdef Q_TABLES
if(!qt_gen)
{
#endif
return l_key;
-}
+};
/* encrypt a block of text */
void twofish_encrypt(TwofishContext *ctx,
const u4byte in_blk[4], u4byte out_blk[])
-{
+{
u4byte t0, t1, blk[4];
u4byte *l_key = ctx->l_key;
u4byte *s_key = ctx->s_key;
out_blk[0] = blk[2] ^ l_key[4];
out_blk[1] = blk[3] ^ l_key[5];
out_blk[2] = blk[0] ^ l_key[6];
- out_blk[3] = blk[1] ^ l_key[7];
-}
+ out_blk[3] = blk[1] ^ l_key[7];
+};
/* decrypt a block of text */
void twofish_decrypt(TwofishContext *ctx,
const u4byte in_blk[4], u4byte out_blk[4])
-{
+{
u4byte t0, t1, blk[4];
u4byte *l_key = ctx->l_key;
u4byte *s_key = ctx->s_key;
out_blk[0] = blk[2] ^ l_key[0];
out_blk[1] = blk[3] ^ l_key[1];
out_blk[2] = blk[0] ^ l_key[2];
- out_blk[3] = blk[1] ^ l_key[3];
-}
+ out_blk[3] = blk[1] ^ l_key[3];
+};
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2000 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
#ifndef TWOFISH_H
#define TWOFISH_H
-/*
+/*
* SILC Crypto API for Twofish
*/
-SILC_CIPHER_API_SET_KEY(twofish_cbc);
-SILC_CIPHER_API_SET_IV(twofish_cbc);
-SILC_CIPHER_API_CONTEXT_LEN(twofish_cbc);
-SILC_CIPHER_API_ENCRYPT(twofish_cbc);
-SILC_CIPHER_API_DECRYPT(twofish_cbc);
+SILC_CIPHER_API_SET_KEY(twofish);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(twofish);
+SILC_CIPHER_API_CONTEXT_LEN(twofish);
+SILC_CIPHER_API_ENCRYPT_CBC(twofish);
+SILC_CIPHER_API_DECRYPT_CBC(twofish);
#endif
+++ /dev/null
-<!--
-@LIBRARY=SILC HTTP Library
-@FILENAME=silchttplib.html
-@LINK=silchttpserver.html:SILC HTTP Server Interface
-@LINK=silchttpphp.html:SILC HTTP PHP Translator
--->
-
-<big><b>SILC HTTP Library</b></big>
-<br />
-<small>Directory: lib/silchttp/</small>
-<br />
-<small>Library: libhttp.a, libhttp.lib</small>
-<br /><br />
-<b>Introduction</b>
-
-<br /><br />
-SILC HTTP Library provides currently interface for very simple HTTP
-Server. It also provides support to serve PHP pages through the server.
-
-<br /><br />
-@LINKS@
+++ /dev/null
-#
-# Makefile.ad
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2006 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 = libsilchttp.la
-
-libsilchttp_la_SOURCES = \
- silchttpserver.c \
- silchttpphp.c
-
-#ifdef SILC_DIST_TOOLKIT
-include_HEADERS = \
- silchttpserver.h \
- silchttpphp.h
-
-SILC_EXTRA_DIST = tests
-#endif SILC_DIST_TOOLKIT
-
-EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-/*
-
- silchttpphp.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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 "silchttpphp.h"
-
-/* Executes PHP code and returns result */
-
-SilcBuffer silc_http_php(char *php_data)
-{
- SilcBuffer ret;
- char *name, tmp[32];
-
- /* Write the PHP data to temporary file */
-#ifdef SILC_WIN32
- name = _mktemp("silchttpphpXXXXXX");
- if (!name)
- return NULL;
-#else
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "/tmp/silchttpphpXXXXXX");
- if (mkstemp(tmp) == -1)
- return NULL;
- name = tmp;
-#endif /* SILC_WIN32 */
-
- silc_file_writefile_mode(name, php_data, strlen(php_data), 0600);
-
- /* Execute PHP */
- ret = silc_http_php_file(name);
-
-#ifdef SILC_WIN32
- _unlink(name);
-#else
- unlink(name);
-#endif /* SILC_WIN32 */
-
- return ret;
-}
-
-/* Loads PHP file and executes the PHP code and returns the result */
-
-SilcBuffer silc_http_php_file(const char *filename)
-{
- SilcBuffer ret = NULL;
- unsigned char tmp[8192];
- FILE *fd;
- int len;
-
- SILC_LOG_DEBUG(("Executing PHP"));
-
- memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "php -f %s", filename);
-
-#ifdef SILC_WIN32
- fd = _popen(tmp, "r");
-#else
- fd = popen(tmp, "r");
-#endif /* SILC_WIN32 */
- if (!fd)
- return NULL;
-
- /* Read the result */
- do {
- len = fread(tmp, 1, sizeof(tmp), fd);
- if (len < 0) {
- silc_buffer_free(ret);
- pclose(fd);
- return NULL;
- }
-
- if (len) {
- if (!ret) {
- ret = silc_buffer_alloc(0);
- if (!ret) {
- pclose(fd);
- return NULL;
- }
- }
-
- silc_buffer_format(ret,
- SILC_STR_ADVANCE,
- SILC_STR_DATA(tmp, len),
- SILC_STR_END);
- }
- } while (len);
-
- if (ret) {
- silc_buffer_format(ret,
- SILC_STR_ADVANCE,
- SILC_STR_DATA('\0', 1),
- SILC_STR_END);
- silc_buffer_push(ret, silc_buffer_truelen(ret));
- }
-
- return ret;
-}
+++ /dev/null
-/*
-
- silchttpphp.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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* silchttp/SILC HTTP PHP Translator
- *
- * DESCRIPTION
- *
- * PHP translator for SILC HTTP Server, enabling PHP support for the pages
- * served through the SILC HTTP Server interface (silchttpserver.h).
- * The PHP must be installed in the system and must be in the execution
- * path for the interface to work.
- *
- ***/
-
-#ifndef SILCHTTPPHP_H
-#define SILCHTTPPHP_H
-
-/****f* silchttp/SilcHTTPServer/silc_http_php
- *
- * SYNOPSIS
- *
- * SilcBuffer silc_http_php(char *php_data);
- *
- * DESCRIPTION
- *
- * Executes the PHP code contained in the buffer `php_data' and returns
- * the result in the allocated SilcBuffer or NULL on error. The caller
- * must free the returned buffer.
- *
- ***/
-SilcBuffer silc_http_php(char *php_data);
-
-/****f* silchttp/SilcHTTPServer/silc_http_php_file
- *
- * SYNOPSIS
- *
- * SilcBuffer silc_http_php_file(const char *filepath);
- *
- * DESCRIPTION
- *
- * Reads the PHP contents from the file indicated by the `filepath' and
- * executes the PHP code and returns the result in the allocated
- * SilcBuffer or NULL on error. The caller must free the returned buffer.
- *
- ***/
-SilcBuffer silc_http_php_file(const char *filename);
-
-#endif /* SILCHTTPPHP_H */
+++ /dev/null
-/*
-
- silchttpserver.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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 "silchttpserver.h"
-
-/************************** Types and definitions ***************************/
-
-#define SILC_HTTP_SERVER_TIMEOUT 120 /* Connection timeout */
-#define SILC_HTTP_SERVER_CONNS 2 /* Default number of connections */
-#define SILC_HTTP_SERVER_BUFLEN 1024 /* Default data buffer length */
-#define SILC_HTTP_SERVER_HEADER "HTTP/1.1 200 OK\r\nServer: SILCHTTP/1.0\r\n"
-
-/* HTTP server context */
-struct SilcHttpServerStruct {
- SilcNetListener listener; /* Server listener */
- SilcSchedule schedule; /* Scheduler */
- SilcList allconns; /* All connections */
- SilcList conns; /* Connection free list */
- SilcHttpServerCallback callback; /* Requset callback */
- void *context; /* Request callback context */
-};
-
-/* HTTP connection context */
-struct SilcHttpConnectionStruct {
- struct SilcHttpConnectionStruct *next;
- SilcHttpServer httpd; /* Server */
- SilcStream stream; /* Connection stream */
- SilcBuffer inbuf; /* Read data buffer */
- SilcBuffer outbuf; /* Write data buffer */
- SilcInt64 touched; /* Time last connection was touched */
- SilcMime curheaders; /* HTTP request headers */
- SilcMime headers; /* HTTP reply headers */
- unsigned char *hptr; /* Pointer to start of headers */
- char *method; /* Method */
- char *uri; /* URI */
- unsigned int keepalive : 1; /* Keep alive */
-};
-
-/************************ Static utility functions **************************/
-
-/* Close HTTP connection */
-
-static void silc_http_server_close_connection(SilcHttpConnection conn)
-{
- if (conn->headers) {
- silc_mime_free(conn->headers);
- conn->headers = NULL;
- }
- if (conn->curheaders) {
- silc_mime_free(conn->curheaders);
- conn->curheaders = NULL;
- }
- silc_buffer_clear(conn->inbuf);
- silc_buffer_clear(conn->outbuf);
- silc_buffer_reset(conn->inbuf);
- silc_buffer_reset(conn->outbuf);
- conn->hptr = conn->method = conn->uri = NULL;
-
- if (conn->keepalive)
- return;
-
- SILC_LOG_DEBUG(("Closing HTTP connection %p", conn));
-
- silc_schedule_task_del_by_context(conn->httpd->schedule, conn);
- silc_stream_set_notifier(conn->stream, conn->httpd->schedule, NULL, NULL);
- silc_stream_destroy(conn->stream);
-
- /* Add to free list */
- silc_list_add(conn->httpd->conns, conn);
-}
-
-/* Parse HTTP data */
-
-static SilcBool silc_http_server_parse(SilcHttpServer httpd,
- SilcHttpConnection conn)
-{
- SilcUInt32 data_len, cll;
- unsigned char *data, *tmp;
- const char *value, *cl;
- SilcBufferStruct postdata;
- int i;
-
- SILC_LOG_DEBUG(("Parsing HTTP data"));
-
- data = silc_buffer_data(conn->inbuf);
- data_len = silc_buffer_len(conn->inbuf);
-
- /* Check for end of headers */
- for (i = 0; i < data_len ; i++) {
- if (data_len - i >= 4 &&
- data[i ] == '\r' && data[i + 1] == '\n' &&
- data[i + 2] == '\r' && data[i + 3] == '\n')
- break;
- }
- if (i == data_len)
- return TRUE;
-
- SILC_LOG_HEXDUMP(("HTTP data"), silc_buffer_data(conn->inbuf),
- silc_buffer_len(conn->inbuf));
-
- if (!conn->method && !conn->uri) {
- tmp = memchr(data, '\n', data_len);
- if (!tmp || tmp[-1] != '\r') {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- *tmp = 0;
-
- /* Get method */
- if (strchr(data, ' '))
- *strchr(data, ' ') = 0;
- conn->method = data;
- SILC_LOG_DEBUG(("Method: '%s'", conn->method));
-
- /* Get URI */
- tmp = memchr(data, '\0', data_len);
- if (!tmp) {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- tmp++;
- if (strchr(tmp, ' '))
- *strchr(tmp, ' ') = 0;
- conn->uri = tmp;
- SILC_LOG_DEBUG(("URI: '%s'", conn->uri));
-
- /* Protocol version compatibility */
- tmp = memchr(tmp, '\0', data_len - (tmp - data)) + 1;
- SILC_LOG_DEBUG(("Protocol: %s", tmp));
- if (strstr(tmp, "HTTP/1.0"))
- conn->keepalive = FALSE;
- if (strstr(tmp, "HTTP/1.1"))
- conn->keepalive = TRUE;
- if (strstr(tmp, "HTTP/1.2"))
- conn->keepalive = TRUE;
-
- /* Get HTTP headers */
- tmp = memchr(tmp, '\0', data_len - (tmp - data));
- if (!tmp) {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- if (data_len - (tmp - data) < 2) {
- if (data_len < SILC_HTTP_SERVER_BUFLEN)
- return TRUE;
- return FALSE;
- }
- conn->hptr = ++tmp;
- }
-
- /* Parse headers and data area */
- conn->curheaders = silc_mime_decode(NULL, conn->hptr,
- data_len - (conn->hptr - data));
- if (!conn->curheaders)
- return FALSE;
-
- /* Check for persistent connection */
- value = silc_mime_get_field(conn->curheaders, "Connection");
- if (value && !strcasecmp(value, "close"))
- conn->keepalive = FALSE;
-
- /* Deliver request to caller */
- if (!strcasecmp(conn->method, "GET") || !strcasecmp(conn->method, "HEAD")) {
- httpd->callback(httpd, conn, conn->uri, conn->method,
- NULL, httpd->context);
-
- } else if (!strcasecmp(conn->method, "POST")) {
- /* Get POST data */
- tmp = (unsigned char *)silc_mime_get_data(conn->curheaders, &data_len);
- if (!tmp)
- return FALSE;
-
- /* Check we have received all data */
- cl = silc_mime_get_field(conn->curheaders, "Content-Length");
- if (cl && sscanf(cl, "%lu", (unsigned long *)&cll) == 1) {
- if (data_len < cll) {
- /* More data to come */
- silc_mime_free(conn->curheaders);
- conn->curheaders = NULL;
- return TRUE;
- }
- }
-
- silc_buffer_set(&postdata, tmp, data_len);
- SILC_LOG_HEXDUMP(("HTTP POST data"), tmp, data_len);
-
- httpd->callback(httpd, conn, conn->uri, conn->method,
- &postdata, httpd->context);
- } else {
- /* Send bad request */
- silc_http_server_send_error(httpd, conn, "400 Bad Request",
- "<body><h1>400 Bad Request</h1><body>");
- return TRUE;
- }
-
- return TRUE;
-}
-
-/* Send HTTP data to connection */
-
-static SilcBool silc_http_server_send_internal(SilcHttpServer httpd,
- SilcHttpConnection conn,
- SilcBuffer data,
- SilcBool headers)
-{
- int ret;
-
- SILC_LOG_HEXDUMP(("HTTP data"), silc_buffer_data(data),
- silc_buffer_len(data));
-
- /* Write the packet to the stream */
- while (silc_buffer_len(data) > 0) {
- ret = silc_stream_write(conn->stream, silc_buffer_data(data),
- silc_buffer_len(data));
- if (ret == 0 || ret == - 2)
- return FALSE;
-
- if (ret == -1) {
- /* Cannot write now, write later. */
- if (silc_buffer_len(data) - ret >= silc_buffer_taillen(conn->outbuf))
- if (!silc_buffer_realloc(conn->outbuf,
- silc_buffer_truelen(conn->outbuf) +
- silc_buffer_len(data) - ret)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- silc_buffer_pull_tail(conn->outbuf, silc_buffer_len(data) - ret);
- silc_buffer_put(conn->outbuf, silc_buffer_data(data) + ret,
- silc_buffer_len(data) - ret);
- return TRUE;
- }
-
- /* Wrote data */
- silc_buffer_pull(data, ret);
- }
-
- if (!headers) {
- /* Data sent, close connection */
- SILC_LOG_DEBUG(("Data sent %p", conn));
- silc_http_server_close_connection(conn);
- }
-
- return TRUE;
-}
-
-/* Allocate connection context */
-
-static SilcHttpConnection silc_http_server_alloc_connection(void)
-{
- SilcHttpConnection conn;
-
- conn = silc_calloc(1, sizeof(*conn));
- if (!conn)
- return NULL;
-
- conn->inbuf = silc_buffer_alloc(SILC_HTTP_SERVER_BUFLEN);
- if (!conn->inbuf) {
- silc_free(conn);
- return NULL;
- }
-
- conn->outbuf = silc_buffer_alloc(SILC_HTTP_SERVER_BUFLEN);
- if (!conn->outbuf) {
- silc_buffer_free(conn->inbuf);
- silc_free(conn);
- return NULL;
- }
-
- silc_buffer_reset(conn->inbuf);
- silc_buffer_reset(conn->outbuf);
-
- return conn;
-}
-
-/* Check if connection has timedout */
-
-SILC_TASK_CALLBACK(silc_http_server_connection_timeout)
-{
- SilcHttpConnection conn = context;
- SilcInt64 curtime = silc_time();
-
- if (curtime - conn->touched > SILC_HTTP_SERVER_TIMEOUT) {
- SILC_LOG_DEBUG(("Connection timeout %p", conn));
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- silc_schedule_task_add_timeout(conn->httpd->schedule,
- silc_http_server_connection_timeout, conn,
- SILC_HTTP_SERVER_TIMEOUT, 0);
-}
-
-/* Data I/O callback */
-
-static void silc_http_server_io(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SilcHttpConnection conn = context;
- SilcHttpServer httpd = conn->httpd;
- int ret;
-
- switch (status) {
- case SILC_STREAM_CAN_READ:
- SILC_LOG_DEBUG(("Read HTTP data %p", conn));
-
- conn->touched = silc_time();
-
- /* Make sure we have fair amount of free space in inbuf */
- if (silc_buffer_taillen(conn->inbuf) < SILC_HTTP_SERVER_BUFLEN)
- if (!silc_buffer_realloc(conn->inbuf, silc_buffer_truelen(conn->inbuf) +
- SILC_HTTP_SERVER_BUFLEN * 2)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- /* Read data from stream */
- ret = silc_stream_read(conn->stream, conn->inbuf->tail,
- silc_buffer_taillen(conn->inbuf));
-
- if (ret == 0 || ret == -2) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- if (ret == -1) {
- /* Cannot read now, do it later. */
- silc_buffer_pull(conn->inbuf, silc_buffer_len(conn->inbuf));
- return;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes data", ret));
-
- /* Parse the data */
- silc_buffer_pull_tail(conn->inbuf, ret);
- if (!silc_http_server_parse(httpd, conn)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- }
-
- break;
-
- case SILC_STREAM_CAN_WRITE:
- SILC_LOG_DEBUG(("Write HTTP data %p", conn));
-
- conn->touched = silc_time();
-
- /* Write pending data to stream */
- while (silc_buffer_len(conn->outbuf) > 0) {
- ret = silc_stream_write(conn->stream, silc_buffer_data(conn->outbuf),
- silc_buffer_len(conn->outbuf));
-
- if (ret == 0 || ret == -2) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return;
- }
-
- if (ret == -1)
- /* Cannot write now, write later. */
- return;
-
- /* Wrote data */
- silc_buffer_pull(conn->outbuf, ret);
- }
-
- /* Data sent, close connection */
- SILC_LOG_DEBUG(("Data sent"));
- silc_http_server_close_connection(conn);
- break;
-
- default:
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- break;
- }
-}
-
-/* Accepts new connection */
-
-static void silc_http_server_new_connection(SilcNetStatus status,
- SilcStream stream,
- void *context)
-{
- SilcHttpServer httpd = context;
- SilcHttpConnection conn;
- const char *hostname = NULL, *ip = NULL;
-
- /* Get free connection */
- silc_list_start(httpd->conns);
- conn = silc_list_get(httpd->conns);
- if (!conn) {
- /* Add new connection */
- conn = silc_http_server_alloc_connection();
- if (!conn) {
- silc_stream_destroy(stream);
- return;
- }
- silc_list_add(httpd->allconns, conn);
- }
- silc_list_del(httpd->conns, conn);
-
- conn->httpd = httpd;
- conn->stream = stream;
-
- silc_socket_stream_get_info(stream, NULL, &hostname, &ip, NULL);
- SILC_LOG_INFO(("HTTPD: New connection %s (%s)", hostname, ip));
- SILC_LOG_DEBUG(("New connection %p", conn));
-
- /* Schedule the connection for data I/O */
- silc_stream_set_notifier(stream, httpd->schedule, silc_http_server_io, conn);
-
- /* Add connection timeout check */
- silc_schedule_task_add_timeout(httpd->schedule,
- silc_http_server_connection_timeout, conn,
- SILC_HTTP_SERVER_TIMEOUT, 0);
-}
-
-
-/******************************* Public API *********************************/
-
-/* Allocate HTTP server */
-
-SilcHttpServer silc_http_server_alloc(const char *ip, SilcUInt16 port,
- SilcSchedule schedule,
- SilcHttpServerCallback callback,
- void *context)
-{
- SilcHttpServer httpd;
- SilcHttpConnection conn;
- int i;
-
- SILC_LOG_DEBUG(("Start HTTP server at %s:%d", ip, port));
-
- if (!ip || !schedule || !callback)
- return FALSE;
-
- httpd = silc_calloc(1, sizeof(*httpd));
- if (!httpd)
- return NULL;
-
- /* Create server listener */
- httpd->listener =
- silc_net_tcp_create_listener(&ip, 1, port, TRUE, FALSE, schedule,
- silc_http_server_new_connection, httpd);
- if (!httpd->listener) {
- SILC_LOG_ERROR(("Could not bind HTTP server at %s:%d", ip, port));
- silc_http_server_free(httpd);
- return NULL;
- }
-
- httpd->schedule = schedule;
- httpd->callback = callback;
- httpd->context = context;
-
- /* Allocate connections list */
- for (i = 0; i < SILC_HTTP_SERVER_CONNS; i++) {
- conn = silc_http_server_alloc_connection();
- if (!conn)
- break;
- silc_list_add(httpd->conns, conn);
- silc_list_add(httpd->allconns, conn);
- }
-
- SILC_LOG_DEBUG(("HTTP Server started"));
-
- return httpd;
-}
-
-/* Free HTTP server */
-
-void silc_http_server_free(SilcHttpServer httpd)
-{
- SilcHttpConnection conn;
-
- silc_list_start(httpd->allconns);
- while ((conn = silc_list_get(httpd->allconns))) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- silc_buffer_free(conn->inbuf);
- silc_buffer_free(conn->outbuf);
- silc_free(conn);
- }
-
- if (httpd->listener)
- silc_net_close_listener(httpd->listener);
-
- silc_free(httpd);
-}
-
-/* Send HTTP data to connection */
-
-SilcBool silc_http_server_send(SilcHttpServer httpd,
- SilcHttpConnection conn,
- SilcBuffer data)
-{
- SilcBufferStruct h;
- unsigned char *headers, tmp[16];
- SilcUInt32 headers_len;
- SilcBool ret;
-
- SILC_LOG_DEBUG(("Sending HTTP data"));
-
- conn->touched = silc_time();
-
- /* Write headers */
- silc_buffer_set(&h, SILC_HTTP_SERVER_HEADER,
- strlen(SILC_HTTP_SERVER_HEADER));
- ret = silc_http_server_send_internal(httpd, conn, &h, TRUE);
- if (!ret) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
-
- if (!conn->headers) {
- conn->headers = silc_mime_alloc();
- if (!conn->headers) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- }
-
- silc_mime_add_field(conn->headers, "Last-Modified",
- silc_time_string(conn->touched));
- silc_snprintf(tmp, sizeof(tmp), "%d", (int)silc_buffer_len(data));
- silc_mime_add_field(conn->headers, "Content-Length", tmp);
- if (conn->keepalive) {
- silc_mime_add_field(conn->headers, "Connection", "keep-alive");
- silc_snprintf(tmp, sizeof(tmp), "%d", (int)SILC_HTTP_SERVER_TIMEOUT);
- silc_mime_add_field(conn->headers, "Keep-alive", tmp);
- }
-
- headers = silc_mime_encode(conn->headers, &headers_len);
- if (headers) {
- silc_buffer_set(&h, headers, headers_len);
- if (!silc_http_server_send_internal(httpd, conn, &h, TRUE)) {
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- silc_free(headers);
- }
-
- /* Write the page data */
- return silc_http_server_send_internal(httpd, conn, data, FALSE);
-}
-
-/* Send error reply */
-
-SilcBool silc_http_server_send_error(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *error,
- const char *error_message)
-{
- SilcBool ret;
- SilcBufferStruct data;
-
- memset(&data, 0, sizeof(data));
- silc_buffer_strformat(&data,
- "HTTP/1.1 ", error, "\r\n\r\n", error_message,
- SILC_STRFMT_END);
-
- /* Send the message */
- ret = silc_http_server_send_internal(httpd, conn, &data, FALSE);
-
- silc_buffer_purge(&data);
-
- /* Close connection */
- conn->keepalive = FALSE;
- silc_http_server_close_connection(conn);
-
- return ret;
-}
-
-/* Get field */
-
-const char *silc_http_server_get_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field)
-{
- if (!conn->curheaders)
- return NULL;
- return silc_mime_get_field(conn->curheaders, field);
-}
-
-/* Add field */
-
-SilcBool silc_http_server_add_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field,
- const char *value)
-{
- SILC_LOG_DEBUG(("Adding header %s:%s", field, value));
-
- if (!conn->headers) {
- conn->headers = silc_mime_alloc();
- if (!conn->headers) {
- silc_http_server_close_connection(conn);
- return FALSE;
- }
- }
-
- silc_mime_add_field(conn->headers, field, value);
- return TRUE;
-}
+++ /dev/null
-/*
-
- silchttpserver.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 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* silchttp/SILC HTTP Server Interface
- *
- * DESCRIPTION
- *
- * Very simple HTTP server interface. This HTTP server supports basic HTTP
- * features. All pages on the server are dynamically created by the caller
- * of this interface. The server does not support plugins, modules, cgi-bin,
- * server-side includes or any other special features. Naturally, the caller
- * of this interface may itself implement such features.
- *
- ***/
-
-#ifndef SILCHTTPSERVER_H
-#define SILCHTTPSERVER_H
-
-/****s* silchttp/SilcHTTPServer/SilcHttpServer
- *
- * NAME
- *
- * typedef struct SilcHttpServerStruct *SilcHttpServer;
- *
- * DESCRIPTION
- *
- * The actual HTTP server allocated with silc_http_server_alloc and
- * freed with silc_http_server_free.
- *
- ***/
-typedef struct SilcHttpServerStruct *SilcHttpServer;
-
-/****s* silchttp/SilcHTTPServer/SilcHttpConnection
- *
- * NAME
- *
- * typedef struct SilcHttpConnectionStruct *SilcHttpConnection;
- *
- * DESCRIPTION
- *
- * HTTP connection context. This is allocated by the library and
- * delivered to application in SilcHttpServerCallback callbcak function.
- * It is given as argument to many silc_http_server_* functions.
- * It is freed automatically by the library.
- *
- ***/
-typedef struct SilcHttpConnectionStruct *SilcHttpConnection;
-
-/****f* silchttp/SilcHTTPServer/SilcHttpServerCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcHttpServerCallback)(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *uri,
- * const char *method,
- * SilcBuffer data,
- * void *context);
- *
- * DESCRIPTION
- *
- * The HTTP request callback that is called everytime a new HTTP request
- * comes from a HTTP client. The `uri' is the requested URI (web page),
- * and the `method' is the HTTP request method (GET, POST, etc.). The
- * `data' is non-NULL only if the `method' is POST, and it includes the
- * the POST data.
- *
- * The requested web page must be returned to the HTTP client from this
- * callback by calling silc_http_server_send or error is returned by
- * calling silc_http_server_send_error.
- *
- * The silc_http_server_get_header may be called to find a specific
- * HTTP header from this request. New headers may be added to the
- * reply by calling silc_http_server_add_header.
- *
- ***/
-typedef void (*SilcHttpServerCallback)(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *uri,
- const char *method,
- SilcBuffer data,
- void *context);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_alloc
- *
- * SYNOPSIS
- *
- * SilcHttpServer
- * silc_http_server_alloc(const char *ip, SilcUInt16 port,
- * SilcSchedule schedule,
- * SilcHttpServerCallback callback, void *context);
- *
- * DESCRIPTION
- *
- * Allocates HTTP server and binds it to the IP address `ip' on the
- * `port'. The `callback' with `context' will be called everytime a new
- * HTTP request comes to the server from a HTTP client. In that callback
- * the caller must then reply with the requested Web page or with error.
- *
- ***/
-SilcHttpServer silc_http_server_alloc(const char *ip, SilcUInt16 port,
- SilcSchedule schedule,
- SilcHttpServerCallback callback,
- void *context);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_free
- *
- * SYNOPSIS
- *
- * void silc_http_server_free(SilcHttpServer httpd);
- *
- * DESCRIPTION
- *
- * Close HTTP server and free all resources.
- *
- ***/
-void silc_http_server_free(SilcHttpServer httpd);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_send
- *
- * SYNOPSIS
- *
- * SilcBool silc_http_server_send(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * SilcBuffer data);
- *
- * DESCRIPTION
- *
- * Send the HTTP data indicated by `data' buffer into the connection
- * indicated by `conn'. Returns TRUE after the data is sent, and FALSE
- * if error occurred. Usually the `data' would be the requested web page.
- *
- ***/
-SilcBool silc_http_server_send(SilcHttpServer httpd,
- SilcHttpConnection conn,
- SilcBuffer data);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_send_error
- *
- * SYNOPSIS
- *
- * SilcBool silc_http_server_send_error(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *error,
- * const char *error_message);
- *
- * DESCRIPTION
- *
- * Send HTTP error back to the connection indicated by `conn'. The
- * `error' is one of the 4xx or 5xx errors defined by the HTTP protocol.
- * The `error_message' is the optional error message sent to the
- * connection. Returns FALSE if the error could not be sent.
- *
- * Typical errors are: 400 Bad Request
- * 403 Forbidden
- * 404 Not Found
- *
- * EXAMPLE
- *
- * silc_http_server_send_error(httpd, conn, "400 Bad Request",
- * "<body><h1>400 Bad Request!!</h1></body>");
- *
- ***/
-SilcBool silc_http_server_send_error(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *error,
- const char *error_message);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_get_header
- *
- * SYNOPSIS
- *
- * const char *silc_http_server_get_header(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *field);
- *
- * DESCRIPTION
- *
- * Finds a header field indicated by `field' from the current HTTP
- * request sent by the HTTP client. Returns the field value or NULL
- * if such header field does not exist.
- *
- ***/
-const char *silc_http_server_get_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field);
-
-/****f* silchttp/SilcHTTPServer/silc_http_server_add_header
- *
- * SYNOPSIS
- *
- * SilcBool silc_http_server_add_header(SilcHttpServer httpd,
- * SilcHttpConnection conn,
- * const char *field,
- * const char *value);
- *
- * DESCRIPTION
- *
- * Adds a new header to the HTTP headers to be sent back to the
- * HTTP client. This may be called to add needed headers to the
- * HTTP reply.
- *
- * EXAMPLE
- *
- * silc_http_server_add_header(httpd, conn, "Content-Type", "image/jpeg");
- * silc_http_server_send(httpd, conn, image_data);
- *
- ***/
-SilcBool silc_http_server_add_header(SilcHttpServer httpd,
- SilcHttpConnection conn,
- const char *field,
- const char *value);
-
-#endif /* SILCHTTPSERVER_H */
+++ /dev/null
-#
-# Makefile.am
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2006 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_silchttpserver
-
-test_silchttpserver_SOURCES = test_silchttpserver.c
-
-LIBS = $(SILC_COMMON_LIBS)
-LDADD = -L.. -L../.. -lsilc -lsilchttp
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-/* SilcHttpServer tests */
-/* Actually this is almost a full-fledged HTTP server. It can serve HTML
- and PHP pages pretty well. In PHP the variables passed in URI with '?'
- work in PHP script, with this HTTPD of ours, only if $_REQUEST variable
- is used to fetch them (limitation in PHP command line version). In other
- ways '?' in URI is not supported. */
-/* Usage: ./test_silchttpserver [-d] [<htdocsdir>] */
-
-#include "silc.h"
-#include "../silchttpserver.h"
-#include "../silchttpphp.h"
-
-char *htdocs = ".";
-
-/* Add proper content type to reply per URI */
-
-static void http_content_type(SilcHttpServer httpd, SilcHttpConnection conn,
- const char *uri)
-{
- const char *type;
-
- type = silc_http_server_get_header(httpd, conn, "Content-Type");
- if (type)
- silc_http_server_add_header(httpd, conn, "Content-Type", type);
- else if (strstr(uri, ".jpg"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "image/jpeg");
- else if (strstr(uri, ".gif"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "image/gif");
- else if (strstr(uri, ".png"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "image/png");
- else if (strstr(uri, ".css"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "text/css");
- else if (strstr(uri, ".htm"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "text/html");
- else if (strstr(uri, ".php"))
- silc_http_server_add_header(httpd, conn, "Content-Type", "text/html");
-}
-
-/* Serve pages */
-
-static void http_callback_file(SilcHttpServer httpd, SilcHttpConnection conn,
- const char *uri, const char *method,
- SilcBuffer data, void *context)
-{
- SilcBufferStruct page;
- SilcBuffer php;
- char *filedata, filename[256];
- SilcUInt32 data_len;
- SilcBool usephp = FALSE;
-
- if (!strcasecmp(method, "GET")) {
- if (strstr(uri, ".php"))
- usephp = TRUE;
-
- if (!strcmp(uri, "/"))
- snprintf(filename, sizeof(filename), "%s/index.html", htdocs);
- else
- snprintf(filename, sizeof(filename), "%s%s", htdocs, uri);
-
- if (strchr(filename, '?'))
- *strchr(filename, '?') = ' ';
- while (strchr(filename, '&'))
- *strchr(filename, '&') = ' ';
-
- SILC_LOG_DEBUG(("Filename: '%s'", filename));
-
- if (!usephp) {
- filedata = silc_file_readfile(filename, &data_len);
- if (!filedata) {
- silc_http_server_send_error(httpd, conn, "404 Not Found",
- "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>");
- return;
- }
-
- http_content_type(httpd, conn, uri);
-
- /* Send page */
- silc_buffer_set(&page, filedata, data_len);
- silc_http_server_send(httpd, conn, &page);
- silc_buffer_purge(&page);
- } else {
- php = silc_http_php_file(filename);
- if (!php) {
- silc_http_server_send_error(httpd, conn, "404 Not Found",
- "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>");
- return;
- }
-
- http_content_type(httpd, conn, uri);
-
- /* Send page */
- silc_http_server_send(httpd, conn, php);
- silc_buffer_free(php);
- }
-
- return;
- }
-
- silc_http_server_send_error(httpd, conn, "404 Not Found",
- "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>");
-}
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcSchedule schedule;
- SilcHttpServer httpd;
-
- if (argc > 1) {
- if (!strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*http*,*mime*");
- if (argc > 2)
- htdocs = argv[2];
- } else {
- htdocs = argv[1];
- }
- }
-
- signal(SIGPIPE, SIG_IGN);
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(0, NULL);
- if (!schedule)
- goto err;
-
- SILC_LOG_DEBUG(("Allocating HTTP server at 127.0.0.1:5000"));
- httpd = silc_http_server_alloc("127.0.0.1", 5000, schedule,
- http_callback_file, NULL);
- if (!httpd)
- goto err;
-
- silc_schedule(schedule);
-
- 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;
-}
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* Table for finding multiplicative inverse */
typedef struct {
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include <gmp.h>
void silc_mp_init(SilcMPInt *mp)
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 - 2006 Pekka Riikonen
+ 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "mp_tfm.h"
void silc_mp_init(SilcMPInt *mp)
SilcUInt32 silc_mp_get_ui(SilcMPInt *mp)
{
- fp_int *tmp = mp;
- return tmp->used > 0 ? tmp->dp[0] : 0;
+ SILC_NOT_IMPLEMENTED("silc_mp_get_ui");
+ assert(FALSE);
}
char *silc_mp_get_str(char *str, SilcMPInt *mp, int base)
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "mp_tma.h"
void silc_mp_init(SilcMPInt *mp)
(void)mp_init(mp);
}
-SilcBool silc_mp_sinit(SilcStack stack, SilcMPInt *mp)
-{
- /* XXX TODO */
- mp_init(mp);
- return TRUE;
-}
-
void silc_mp_uninit(SilcMPInt *mp)
{
mp_clear(mp);
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* Encodes MP integer into binary data. Returns allocated data that
must be free'd by the caller. If `len' is provided the destination
unsigned char *silc_mp_mp2bin(SilcMPInt *val, SilcUInt32 len,
SilcUInt32 *ret_len)
{
+ int i;
SilcUInt32 size;
unsigned char *ret;
+ SilcMPInt tmp;
size = (len ? len : ((silc_mp_sizeinbase(val, 2) + 7) / 8));
ret = silc_calloc(size, sizeof(*ret));
- if (!ret)
- return NULL;
- silc_mp_mp2bin_noalloc(val, ret, size);
+ silc_mp_init(&tmp);
+ silc_mp_set(&tmp, val);
+
+ for (i = size; i > 0; i--) {
+ ret[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
+ silc_mp_div_2exp(&tmp, &tmp, 8);
+ }
+
+ silc_mp_uninit(&tmp);
if (ret_len)
*ret_len = size;
/*
silcmath.h
-
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2005 Pekka Riikonen
-
+
+ Copyright (C) 1997 - 2001 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
*
* SYNOPSIS
*
- * SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits,
- * SilcBool verbose, SilcRng rng);
+ * int silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, bool verbose,
+ * SilcRng);
*
* DESCRIPTION
*
- * Find appropriate prime. It generates a number by taking random bytes.
- * It then tests the number that it's not divisible by any of the small
- * primes and then it performs Fermat's prime test. I thank Rieks Joosten
- * (r.joosten@pijnenburg.nl) for such a good help with prime tests.
+ * Find appropriate prime. It generates a number by taking random bytes.
+ * It then tests the number that it's not divisible by any of the small
+ * primes and then it performs Fermat's prime test. I thank Rieks Joosten
+ * (r.joosten@pijnenburg.nl) for such a good help with prime tests.
*
* If argument verbose is TRUE this will display some status information
* about the progress of generation. If the `rng' is NULL then global
* number number.
*
***/
-SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits,
- SilcBool verbose, SilcRng rng);
+bool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, bool verbose,
+ SilcRng rng);
/****f* silcmath/SilcMathAPI/silc_math_prime_test
*
*
* DESCRIPTION
*
- * Performs primality testings for given number. Returns TRUE if the
+ * Performs primality testings for given number. Returns TRUE if the
* number is probably a prime.
*
***/
-SilcBool silc_math_prime_test(SilcMPInt *p);
+bool silc_math_prime_test(SilcMPInt *p);
#endif
***/
void silc_mp_init(SilcMPInt *mp);
-/****f* silcmath/SilcMPAPI/silc_mp_sinit
- *
- * SYNOPSIS
- *
- * SilcBool silc_mp_sinit(SilcStack stack, SilcMPInt *mp);
- *
- * DESCRIPTION
- *
- * Initializes the SilcMPInt *that is the actual MP Integer.
- * This must be called before any of the silc_mp_ routines can be
- * used. The integer is uninitialized with the silc_mp_uninit function.
- * This routine is equivalent to silc_mp_init but allocates the memory
- * from `stack'.
- *
- * NOTES
- *
- * The `stack' is saved into the `mp' for the duration of the existence
- * of `mp'. This means that `stack' must not become invalid while `mp'
- * is used. It also means that any routine that may need memory allocation
- * to for example enlarge `mp' will allocate the memory from `stack'.
- *
- ***/
-SilcBool silc_mp_sinit(SilcStack stack, SilcMPInt *mp);
-
/****f* silcmath/SilcMPAPI/silc_mp_uninit
*
* SYNOPSIS
* DESCRIPTION
*
* Same as silc_mp_mp2bin but does not allocate any memory. The
- * encoded data is returned into `dst' of size of `dst_len'.
+ * encoded data is returned into `dst' and it's length to the `ret_len'.
*
***/
void silc_mp_mp2bin_noalloc(SilcMPInt *val, unsigned char *dst,
/* Created: Mon Dec 8 16:35:37 GMT+0200 1997 */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/*
Fixed primetable for small prime division. We use this primetable to
If argument verbose is TRUE this will display some status information
about the progress of generation. */
-SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits,
- SilcBool verbose, SilcRng rng)
+bool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, bool verbose,
+ SilcRng rng)
{
unsigned char *numbuf = NULL;
SilcUInt32 i, b, k;
SilcUInt32 *spmods;
SilcMPInt r, base, tmp, tmp2, oprime;
- SilcBool valid = FALSE;
+ bool valid = FALSE;
silc_mp_init(&r);
silc_mp_init(&base);
/* Performs primality testings for given number. Returns TRUE if the
number is probably a prime. */
-SilcBool silc_math_prime_test(SilcMPInt *p)
+bool silc_math_prime_test(SilcMPInt *p)
{
SilcMPInt r, base, tmp;
int i, ret = 0;
#ifndef TMA_H
#define TMA_H
-#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
-#include "tma_class.h"
+#include <tma_class.h>
/* Assure these -Pekka */
#undef MP_8BIT
#ifdef LTM3
#define LTM_LAST
#endif
-#include "tma_superclass.h"
-#include "tma_class.h"
+#include <tma_superclass.h>
+#include <tma_class.h>
#else
#define LTM_LAST
#endif
+++ /dev/null
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: @PACKAGE@ (server library)
-Description: SILC Server Library
-Version: @VERSION@
-Conflicts: libsilc <= 1.1
-Requires: silc = @VERSION@
-Libs: -L${libdir} -lsilcserver @LIBS@
-Cflags: -I${includedir}
-
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
-
- server.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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_EVENT_SIGNAL(&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_EVENT_SIGNAL(&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_event_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_EVENT_SIGNAL(&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_EVENT_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) {
- /* XXX shouldn't the fsm be &thread->fsm */
- 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;
- silc_fsm_thread_init(&ac->t, &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_EVENT_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_EVENT_SIGNAL(&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_EVENT_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_event_init(&server->wait_event, &server->fsm, 0);
- silc_fsm_event_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;
-
- /* 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_EVENT_SIGNAL(&server->wait_event);
-
- /* Signal to connect to router */
- server->connect_router = TRUE;
- SILC_FSM_EVENT_SIGNAL(&server->wait_event);
-
- /* Start getting statistics from the network on normal server */
- if (server->server_type != SILC_ROUTER) {
- server->get_statistics = TRUE;
- SILC_FSM_EVENT_SIGNAL(&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_EVENT_SIGNAL(&server->wait_event);
-}
-
-/* Disconnects remote connection */
-
-SilcBool silc_server_disconnect(SilcServer server,
- SilcPacketStream stream,
- SilcStatus error,
- const char *error_string)
-{
- return TRUE;
-}
+++ /dev/null
-/*
-
- server_entry.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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"
-
-/* XXX locking missing from routines! */
-
-/************************ 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;
-
- 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, old_id, &id_cache))
- return NULL;
- if (!silc_idcache_update(server->servers, id_cache, old_id, new_id,
- NULL, NULL)) {
- SILC_LOG_ERROR(("Error updating Server ID"));
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Replaced"));
-
- return id_cache->context;
-}
-
-
-/****************************** 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_CLIENT)));
- SILC_LOG_DEBUG(("New Client ID %s",
- silc_id_render(new_id, SILC_ID_CLIENT)));
-
- /* 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, old_id, &id_cache))
- return NULL;
- entry = id_cache->context;
- name = id_cache->name;
- if (!silc_idcache_update(server->clients, id_cache, old_id, new_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;
-
- 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, old_id, &id_cache))
- return NULL;
- if (!silc_idcache_update(server->channels, id_cache, old_id, new_id,
- NULL, NULL)) {
- SILC_LOG_ERROR(("Error updating Channel ID"));
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Replaced"));
-
- return id_cache->context;
-}
-
-/* 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;
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- server_internal.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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_INTERNAL_H
-#define SERVER_INTERNAL_H
-
-#include "server_st_accept.h"
-#include "server_st_connect.h"
-#include "server_st_notify.h"
-#include "server_st_query.h"
-#include "server_st_command.h"
-#include "server_st_command_reply.h"
-#include "server_st_packet.h"
-
-/* SILC port */
-#define SILC_PORT 706
-
-/* Server type */
-typedef enum {
- SILC_SERVER = 0,
- SILC_ROUTER = 1,
- SILC_BACKUP_ROUTER = 2
-} SilcServerType;
-
-/* Forward declarations */
-typedef struct SilcServerEntryStruct *SilcServerEntry;
-typedef struct SilcClientEntryStruct *SilcClientEntry;
-typedef struct SilcChannelEntryStruct *SilcChannelEntry;
-typedef struct SilcServerCommandStruct *SilcServerCommand;
-typedef struct SilcServerThreadStruct *SilcServerThread;
-
-/* Pending command context */
-typedef struct {
- SilcFSMEventStruct wait_reply; /* Pending command signaller */
- SilcServerCommand reply; /* Command reply context */
- SilcUInt16 cmd_ident; /* Command identifier */
- SilcInt16 refcnt; /* Reference counter */
-} *SilcServerPending;
-
-/* Command state context. This is used with both commands and command
- replies. When command or command reply is executed its state is saved
- here while processing. */
-struct SilcServerCommandStruct {
- struct SilcServerCommandStruct *next;
- SilcServerThread thread; /* Server thread */
- SilcPacket packet; /* Command packet */
- SilcCommandPayload payload; /* Command payload */
- SilcServerPending pending; /* Pending command context */
-};
-
-/* Entry data header. Client and server entries has this as their first
- field. */
-typedef struct {
- SilcConnectionType type; /* Connection type */
- SilcSKE ske; /* Key exchange protocol, for rekey */
- SilcHash hash; /* Hash selected in SKE protocol */
- SilcPublicKey public_key; /* Public key */
- unsigned char fingerprint[20]; /* SHA-1 fingerprint */
-
- long last_receive; /* Time last received data */
- long last_sent; /* Time last sent data */
-
- unsigned long created; /* Time when entry was created */
-
- SilcUInt32 refcnt; /* Reference counter */
-
- /* Flags */
- unsigned int registered : 1; /* Set if registered to network */
- unsigned int local : 1; /* Set if locally connected entry */
- unsigned int resolving : 1; /* Set if entry data being resolved */
- unsigned int resolved : 1; /* Set if entry data resolved */
- unsigned int disabled : 1; /* Set if entry is disabled */
- unsigned int resumed : 1; /* Set if entry resumed */
- unsigned int resume_res : 1; /* Set if resolved while resuming */
- unsigned int noattr : 1; /* Set if entry does not support
- user attributes in WHOIS */
-} *SilcEntryData, SilcEntryDataStruct;
-
-/* Server entry */
-struct SilcServerEntryStruct {
- SilcEntryDataStruct data; /* Entry data header */
- SilcServerID id; /* Server ID */
- char *server_name; /* Server name */
- char *server_info; /* Server info */
- char *motd; /* Message of the day */
- SilcPacketStream stream; /* Connection to entry/origin of entry */
- SilcUInt8 server_type; /* Server type */
-};
-
-/* Client's joined channel entry */
-typedef struct SilcChannelClientEntryStruct {
- SilcClientEntry client; /* Client on channel */
- SilcChannelEntry channel; /* Joined channel */
- SilcUInt32 mode; /* Client's mode on channel */
-} *SilcChannelClientEntry;
-
-/* Client entry */
-struct SilcClientEntryStruct {
- SilcEntryDataStruct data; /* Entry data header */
- SilcClientID id; /* Client ID */
- unsigned char *nickname; /* Client's nickname (not normalized) */
- char *servername; /* Client's server's name */
- char *username; /* Client's username */
- char *userinfo; /* Client's user info */
- SilcUInt32 mode; /* Client's mode in the network */
- unsigned char *attrs; /* User attributes */
- SilcUInt16 attrs_len; /* Attributes data length */
- SilcHashTable channels; /* Joined channels */
- SilcPacketStream stream; /* Connection to entry/origin of entry */
- SilcUInt16 resolve_cmd_ident; /* Command identifier when resolving */
-
- long last_command;
- SilcUInt8 fast_command;
- unsigned long updated;
-
- /* we need this so nobody can resume more than once at the same time -
- * server crashes, really odd behaviour, ... */
- SilcClientEntry resuming_client;
-};
-
-/* Channel entry */
-struct SilcChannelEntryStruct {
- SilcChannelID id; /* Channel ID */
- char *channel_name; /* Channel name */
- SilcUInt32 mode; /* Channel's mode */
- SilcPacketStream router; /* Channel's owner */
-
- unsigned char *passphrase; /* Channel's passphrase */
- SilcHashTable channel_pubkeys; /* Channel authentication public keys */
- SilcPublicKey founder_key; /* Channel founder's public key */
-
- char *topic; /* Current topic */
- char *cipher; /* User set cipher */
- char *hmac_name; /* User set HMAC */
- SilcUInt32 user_limit; /* Maximum user limit */
- SilcHashTable invite_list; /* Invited list */
- SilcHashTable ban_list; /* Ban list */
- SilcHashTable user_list; /* Joined users */
-
- SilcCipher channel_key; /* Current channel key */
- unsigned char *key; /* Current channel key data */
- SilcUInt32 key_len; /* Channel key data length */
- SilcHmac hmac; /* Current HMAC */
- SilcUInt32 refcnt; /* Reference counter */
-
- // SilcServerChannelRekey rekey;
- unsigned long created;
- unsigned long updated;
-
- /* Flags */
- unsigned int global_users : 1;
- unsigned int disabled : 1;
- unsigned int users_resolved : 1;
-};
-
-/* Internal context for accepting new connection */
-typedef struct SilcServerAcceptStruct {
- SilcEntryDataStruct data;
- SilcServerThread thread;
- SilcFSMThreadStruct t; /* Thread for accepting connection */
- SilcStream stream; /* Remote connection */
- SilcPacketStream packet_stream; /* Remote connection */
- SilcConnAuth connauth; /* Connection authentication context */
- SilcFSMEventStruct wait_register; /* Signaller when registering received */
- SilcPacket register_packet; /* NEW_CLIENT/NEW_SERVER packet */
-
- SilcServerParamClient cconfig;
- SilcServerParamServer sconfig;
- SilcServerParamRouter rconfig;
- SilcSKEStatus status;
- SilcSKESecurityProperties prop;
- SilcSKEKeyMaterial keymat;
- SilcSKERekeyMaterial rekey;
- SilcAsyncOperation op;
- const char *hostname;
- const char *ip;
- SilcUInt16 port;
- SilcStatus error;
- char *error_string;
- SilcBool auth_success;
- SilcConnectionType conn_type;
- SilcHash hash;
- struct SilcServerAcceptStruct *next;
-} *SilcServerAccept;
-
-/* Server statistics structure. */
-typedef struct {
- /* Local stats (server and router) */
- SilcUInt32 my_clients; /* Locally connected clients */
- SilcUInt32 my_servers; /* Locally connected servers */
- SilcUInt32 my_routers; /* Locally connected routers */
- SilcUInt32 my_channels; /* Locally created channels */
- SilcUInt32 my_chanclients; /* Local clients on local channels */
- SilcUInt32 my_aways; /* Local clients away (gone) */
- SilcUInt32 my_detached; /* Local clients detached */
- SilcUInt32 my_server_ops; /* Local server operators */
- SilcUInt32 my_router_ops; /* Local router operators */
-
- /* Global stats (mainly for router) */
- SilcUInt32 cell_clients; /* All clients in cell */
- SilcUInt32 cell_servers; /* All servers in cell */
- SilcUInt32 cell_channels; /* All channels in cell */
- SilcUInt32 cell_chanclients; /* All clients on cell's channels */
- SilcUInt32 clients; /* All clients */
- SilcUInt32 servers; /* All servers */
- SilcUInt32 routers; /* All routers */
- SilcUInt32 channels; /* All channels */
- SilcUInt32 chanclients; /* All clients on channels */
- SilcUInt32 aways; /* All clients away (gone) */
- SilcUInt32 detached; /* All clients detached */
- SilcUInt32 server_ops; /* All server operators */
- SilcUInt32 router_ops; /* All router operators */
- /* More to add
- SilcUInt32 secret_channels;
- SilcUInt32 private_channels;
- */
-
- /* General */
- SilcUInt32 conn_attempts; /* Connection attempts */
- SilcUInt32 conn_failures; /* Connection failure */
- SilcUInt32 auth_attempts; /* Authentication attempts */
- SilcUInt32 auth_failures; /* Authentication failures */
- SilcUInt32 packets_sent; /* Sent SILC packets */
- SilcUInt32 packets_received; /* Received SILC packets */
- SilcUInt32 conn_num; /* Number of connections */
- SilcUInt32 commands_sent; /* Commands/replies sent */
- SilcUInt32 commands_received; /* Commands/replies received */
-} SilcServerStatistics;
-
-/* Server thread context */
-struct SilcServerThreadStruct {
- struct SilcServerThreadStruct *next;
- SilcServer server; /* Pointer to server */
- SilcStack stack; /* Data stack for fast allocations */
- SilcPacketEngine packet_engine; /* Packet engine */
- SilcFSMThreadStruct thread; /* FSM thread */
- SilcFSMStruct fsm; /* Thread's FSM */
- SilcFSMEventStruct wait_event; /* Thread's event signaller */
- SilcUInt32 num_conns; /* Number of connections in the thread */
- SilcList new_conns; /* New network connections */
- SilcList packet_queue; /* Incoming packet queue */
-
- /* Events */
- unsigned int new_connection : 1; /* New connection received */
- unsigned int new_packet : 1; /* New packet in packet queue */
-};
-
-/* Server context. */
-struct SilcServerStruct {
- char *server_name; /* Server name */
- SilcServerEntry server_entry; /* Server entry */
- SilcServerID id; /* Server ID */
- SilcUInt32 starttime;
-
- SilcFSMStruct fsm; /* Server FSM */
- SilcSchedule schedule; /* Scheduler */
- SilcMutex lock; /* Server lock */
- SilcRng rng; /* Random number generator */
- SilcServerParams params; /* Server parameters */
- SilcDList listeners; /* Network listeners */
- SilcList threads; /* Server worker threads */
- SilcList new_conns; /* New network connections */
- SilcList command_pool; /* Command context freelist */
- SilcHashTable pending_commands; /* Pending commands */
-
- SilcFSMEventStruct wait_event; /* Main state signaller */
- SilcFSMEventStruct thread_up; /* Signaller when thread is up */
-
- SilcIDCache clients; /* Client entry cache */
- SilcIDCache servers; /* Server entry cache */
- SilcIDCache channels; /* Channel entry cache */
-
- SilcSKR repository; /* Public key/certificate repository */
- SilcHashTable watcher_list; /* Watcher list, nickname */
- SilcHashTable watcher_list_pk; /* Watcher list, public keys */
-
- void *app_context; /* Application specific context */
-
- char *config_file;
-
- /* Events */
- unsigned int new_connection : 1; /* New connection received */
- unsigned int connect_router : 1; /* Connect to configured routers */
- unsigned int get_statistics : 1; /* Get statistics */
- unsigned int reconfigure : 1; /* Reconfigure server */
- unsigned int server_shutdown : 1; /* Shutdown server */
- unsigned int run_callback : 1; /* Call running callback */
-
- /* Flags */
- unsigned int server_type : 2; /* Server type (server.h) */
- unsigned int standalone : 1; /* Set if server is standalone, and
- does not have connection to network. */
- unsigned int listenning : 1; /* Set if server is listenning for
- incoming connections. */
- unsigned int background : 1; /* Set when server is on background */
- unsigned int backup_router : 1; /* Set if this is backup router */
- unsigned int backup_primary : 1; /* Set if we've switched our primary
- router to a backup router. */
- unsigned int backup_noswitch: 1; /* Set if we've won't switch to
- become primary (we are backup) */
- unsigned int backup_closed : 1; /* Set if backup closed connection.
- Do not allow resuming in this case. */
- unsigned int wait_backup : 1; /* Set if we are waiting for backup
- router to connect to us. */
- unsigned int no_reconnect : 1; /* If set, server won't reconnect to
- router after disconnection. */
-
- SilcPacketStream router; /* Pointer to the primary router */
-
- /* Current command identifier, 0 not used */
- SilcUInt16 cmd_ident;
-
- /* Server public key */
- SilcPublicKey public_key;
- SilcPrivateKey private_key;
-
- /* Hash objects for general hashing */
- SilcHash md5hash;
- SilcHash sha1hash;
-
- /* Server statistics */
- SilcServerStatistics stat;
-
-#ifdef SILC_SIM
- /* SIM (SILC Module) list */
- SilcDList sim;
-#endif
-
- /* Application callbacks */
- SilcServerRunning running; /* Called to indicate server is up */
- SilcServerStop stopped; /* Called to indicate server is down */
- void *running_context;
- void *stop_context;
-};
-
-/* Rekey must be performed at the lastest when this many packets is sent */
-#define SILC_SERVER_REKEY_THRESHOLD 0xfffffe00
-
-/* Macros */
-
-#define SILC_IS_CLIENT(entry) (entry->data.type == SILC_CONN_CLIENT)
-#define SILC_IS_SERVER(entry) (entry->data.type == SILC_CONN_SERVER)
-#define SILC_IS_ROUTER(entry) (entry->data.type == SILC_CONN_ROUTER)
-
-/* Return pointer to the primary router connection */
-#define SILC_PRIMARY_ROUTE(server) server->router
-
-/* Return TRUE if a packet must be broadcasted (router broadcasts) */
-#define SILC_BROADCAST(server) (server->server_type == SILC_ROUTER)
-
-/* Return TRUE if entry is locally connected or local to us */
-#define SILC_IS_LOCAL(entry) (((SilcEntryData)entry)->local)
-
-/* Return TRUE if entry is registered */
-#define SILC_IS_REGISTERED(entry) (((SilcEntryData)entry)->registered)
-
-/* Registers generic task for file descriptor for reading from network and
- writing to network. As being generic task the actual task is allocated
- only once and after that the same task applies to all registered fd's. */
-#define SILC_REGISTER_CONNECTION_FOR_IO(fd) \
-do { \
- silc_schedule_task_add(server->schedule, (fd), \
- silc_server_packet_process, \
- context, 0, 0, \
- SILC_TASK_GENERIC, \
- SILC_TASK_PRI_NORMAL); \
-} while(0)
-
-#define SILC_SET_CONNECTION_FOR_INPUT(s, fd) \
-do { \
- silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ, FALSE); \
-} while(0)
-
-#define SILC_SET_CONNECTION_FOR_OUTPUT(s, fd) \
-do { \
- silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | SILC_TASK_WRITE), \
- FALSE); \
-} while(0)
-
-#define SILC_OPER_STATS_UPDATE(c, type, mod) \
-do { \
- if ((c)->mode & (mod)) { \
- if (SILC_IS_LOCAL((c))) \
- server->stat.my_ ## type ## _ops--; \
- if (server->server_type == SILC_ROUTER) \
- server->stat. type ## _ops--; \
- (c)->mode &= ~(mod); \
- } \
-} while(0)
-
-#define SILC_UMODE_STATS_UPDATE(oper, mod) \
-do { \
- if (client->mode & (mod)) { \
- if (!(mode & (mod))) { \
- if (SILC_IS_LOCAL(client)) \
- server->stat.my_ ## oper ## _ops--; \
- if (server->server_type == SILC_ROUTER) \
- server->stat. oper ## _ops--; \
- } \
- } else { \
- if (mode & (mod)) { \
- if (SILC_IS_LOCAL(client)) \
- server->stat.my_ ## oper ## _ops++; \
- if (server->server_type == SILC_ROUTER) \
- server->stat. oper ## _ops++; \
- } \
- } \
-} while(0)
-
-#define SILC_GET_SKE_FLAGS(x, p) \
- if ((x)) { \
- if ((x)->param && (x)->param->key_exchange_pfs) \
- (p) |= SILC_SKE_SP_FLAG_PFS; \
- if (!(x)->publickeys) \
- (p) |= SILC_SKE_SP_FLAG_MUTUAL; \
- }
-
-#define SILC_CONNTYPE_STRING(ctype) \
- (ctype == SILC_CONN_CLIENT ? "Client" : \
- ctype == SILC_CONN_SERVER ? "Server" : "Router")
-
-/* This macro is used to send notify messages with formatted string. The
- string is formatted with arguments and the formatted string is sent as
- argument. */
-#define SILC_SERVER_SEND_NOTIFY(server, stream, type, fmt) \
-do { \
- char *__fmt__ = silc_format fmt; \
- if (__fmt__) \
- silc_server_send_notify(server, stream, FALSE, \
- type, 1, __fmt__, strlen(__fmt__)); \
- silc_free(__fmt__); \
-} while(0)
-
-/* Send notify to operators */
-#define SILC_SERVER_SEND_OPERS(server, route, local, type, fmt) \
-do { \
- char *__fmt__ = silc_format fmt; \
- silc_server_send_opers_notify(server, route, local, \
- type, 1, __fmt__, strlen(__fmt__)); \
- silc_free(__fmt__); \
-} while(0)
-
-#define SILC_SERVER_LOG_FLUSH_DELAY 300 /* Default log flush delay */
-
-/* Macros */
-
-/* Check whether rekey protocol is active */
-#define SILC_SERVER_IS_REKEY(sock) \
- (sock->protocol && sock->protocol->protocol && \
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
-
-/* Check whether backup resuming protocol is active */
-#define SILC_SERVER_IS_BACKUP(sock) \
- (sock->protocol && sock->protocol->protocol && \
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP)
-
-/* Output a message to stderr or to the appropriate log facility wether
- we are in the background or not. */
-#define SILC_SERVER_LOG_INFO(fmt) \
- silc_server_stderr(SILC_LOG_INFO, silc_format fmt)
-#define SILC_SERVER_LOG_WARNING(fmt) \
- silc_server_stderr(SILC_LOG_WARNING, silc_format fmt)
-#define SILC_SERVER_LOG_ERROR(fmt) \
- silc_server_stderr(SILC_LOG_ERROR, silc_format fmt)
-#define SILC_SERVER_LOG_FATAL(fmt) \
- silc_server_stderr(SILC_LOG_WARNING, silc_format fmt)
-
-/* Server's states */
-SILC_FSM_STATE(silc_server_st_run);
-SILC_FSM_STATE(silc_server_st_new_connection);
-SILC_FSM_STATE(silc_server_st_wait_new_thread);
-SILC_FSM_STATE(silc_server_st_stop);
-SILC_FSM_STATE(silc_server_st_reconfigure);
-SILC_FSM_STATE(silc_server_st_get_stats);
-SILC_FSM_STATE(silc_server_st_connect_router);
-
-/* Server's thread's states */
-SILC_FSM_STATE(silc_server_thread_st_start);
-SILC_FSM_STATE(silc_server_thread_st_run);
-
-/* Prototypes */
-void silc_server_watcher_list_destroy(void *key, void *context,
- void *user_context);
-
-#include "server_entry.h"
-
-#endif /* SERVER_INTERNAL_H */
+++ /dev/null
-/*
-
- 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(¶ms->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);
-}
+++ /dev/null
-/*
-
- server_send.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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);
- vsilc_snprintf(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;
-}
-
-
-/****************************** Command packets *****************************/
-
-/* Generic function to send any command. The arguments must be sent already
- encoded into correct form in correct order, and they must as follows:
- { argument type, argument data, argument length }. */
-
-SilcBool silc_server_send_command(SilcServer server,
- SilcPacketStream stream,
- SilcCommand command,
- SilcUInt16 ident,
- SilcUInt32 argc, ...)
-{
- SilcBuffer packet;
- va_list ap;
- SilcBool ret = FALSE;
-
- /* Statistics */
- server->stat.commands_sent++;
-
- va_start(ap, argc);
-
- packet = silc_command_payload_encode_vap(command, ident, argc, ap);
- if (!packet) {
- va_end(ap);
- return ret;
- }
-
- ret = silc_packet_send(stream, SILC_PACKET_COMMAND, 0,
- packet->data, silc_buffer_len(packet));
-
- silc_buffer_free(packet);
- va_end(ap);
-
- return ret;
-}
-
-/* Generic function to send a command reply. The arguments must be sent
- already encoded into correct form in correct order, and they must be
- { argument type, argument data, argument length }. */
-
-SilcBool silc_server_send_command_reply(SilcServer server,
- SilcPacketStream stream,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- SilcUInt16 ident,
- SilcUInt32 argc, ...)
-{
- SilcBuffer packet;
- va_list ap;
- SilcBool ret = FALSE;
-
- /* Statistics */
- server->stat.commands_sent++;
-
- va_start(ap, argc);
-
- packet = silc_command_reply_payload_encode_vap(command, status, error,
- ident, argc, ap);
- if (!packet) {
- va_end(ap);
- return ret;
- }
-
- ret = silc_packet_send(stream, SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, silc_buffer_len(packet));
-
- silc_buffer_free(packet);
- va_end(ap);
-
- 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;
-}
+++ /dev/null
-/*
-
- server_st_accept.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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,
- SilcSKEPKType pk_type,
- SilcPublicKey public_key,
- 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_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_event_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_EVENT_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 */
- silc_snprintf(n, sizeof(n), "%s", u);
- silc_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;
- }
- silc_snprintf(n, sizeof(n), "%s", u);
- silc_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_EVENT_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;
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- server_st_command.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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_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_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_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_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_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);
-
-#if defined(SILC_DEBUG)
- /* Check for double free */
- 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_event_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_EVENT_SIGNAL(&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;
- }
-
- client->last_command = time(NULL) + timeout;
- }
-
- 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 : return SILC_FSM_CONTINUE;
-}
-
-/********************************* WHOIS ************************************/
-
-SILC_FSM_STATE(silc_server_st_command_whois)
-{
- SilcServerCommand cmd = state_context;
- SilcArgumentPayload args = silc_command_get_args(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK(1, 256);
-
- /** WHOIS query */
- silc_fsm_next(fsm, silc_server_st_query_whois);
-
- return SILC_FSM_CONTINUE;
-}
-
-
-/********************************* WHOWAS ***********************************/
-
-SILC_FSM_STATE(silc_server_st_command_whowas)
-{
- SilcServerCommand cmd = state_context;
- SilcArgumentPayload args = silc_command_get_args(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK(1, 2);
-
- /** WHOWAS query */
- silc_fsm_next(fsm, silc_server_st_query_whowas);
-
- return SILC_FSM_CONTINUE;
-}
-
-
-/******************************** IDENTIFY **********************************/
-
-SILC_FSM_STATE(silc_server_st_command_identify)
-{
- SilcServerCommand cmd = state_context;
- SilcArgumentPayload args = silc_command_get_args(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK(1, 256);
-
- /** IDENTIFY query */
- silc_fsm_next(fsm, silc_server_st_query_identify);
-
- return 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);
- SilcClientEntry client = silc_packet_get_context(cmd->packet->stream);
- SilcBuffer nidp, oidp = NULL;
- SilcClientID new_id;
- SilcUInt32 nick_len;
- unsigned char *nick, *nickc;
- SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK(1, 1);
-
- /* This command can come only from client */
- if (!SILC_IS_CLIENT(client)) {
- silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
- goto out;
- }
-
- /* Get nickname */
- nick = silc_argument_get_arg_type(args, 1, &nick_len);
- if (!nick) {
- silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- goto out;
- }
-
- /* Truncate over long nicks */
- if (nick_len > 128) {
- nick_len = 128;
- nick[nick_len - 1] = '\0';
- }
-
- /* Check for same nickname */
- if (strlen(client->nickname) == nick_len &&
- !memcmp(client->nickname, nick, nick_len)) {
- nidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
- goto send_reply;
- }
-
- /* Check for valid nickname string. */
- nickc = silc_identifier_check(nick, nick_len, SILC_STRING_UTF8, 128, NULL);
- if (!nickc) {
- silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- goto out;
- }
-
- /* Create new Client ID */
- if (!silc_server_create_client_id(thread->server, nickc, &new_id)) {
- silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
- goto out;
- }
- silc_free(nickc);
-
- oidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
-
- /* Replace the old nickname and ID with new ones. This checks for
- validity of the nickname too. */
- if (!silc_server_replace_client_id(thread->server, &client->id, &new_id,
- nick)) {
- silc_server_command_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- goto out;
- }
-
- nidp = silc_id_payload_encode(&client->id, SILC_ID_CLIENT);
-
-#if 0
- /* Send notify about nickname and ID change to network. */
- silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
- SILC_BROADCAST(server), client->id,
- &new_id, nick);
-
- /* Send NICK_CHANGE notify to the client's channels */
- silc_server_send_notify_on_channels(server, NULL, client,
- SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
- oidp->data, silc_buffer_len(oidp),
- nidp->data, silc_buffer_len(nidp),
- client->nickname,
- strlen(client->nickname));
-#endif
-
- send_reply:
- /* Send the new Client ID as reply command back to client */
- silc_server_send_command_reply(thread->server, cmd->packet->stream,
- SILC_COMMAND_NICK,
- SILC_STATUS_OK, 0, ident, 2,
- 2, nidp->data, silc_buffer_len(nidp),
- 3, nick, nick_len);
- silc_buffer_free(nidp);
- silc_buffer_free(oidp);
-
- out:
- silc_server_command_free(cmd);
- 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 ************************************/
-
-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 ************************************/
-
-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;
- SilcID 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_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, &id)) {
- silc_server_command_status_data(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_ERR_BAD_SERVER_ID, 0,
- 2, tmp, tmp_len);
- goto out;
- }
-
- /* Must be our ID */
- if (!SILC_ID_SERVER_COMPARE(&id.u.server_id, &thread->server->id)) {
- silc_server_command_status_data(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
- 2, tmp, tmp_len);
- goto out;
- }
-
- /* Send our reply */
- silc_server_command_status_reply(cmd, silc_command_get(cmd->payload),
- SILC_STATUS_OK, 0);
-
- 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;
-}
+++ /dev/null
-/*
-
- server_st_command.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005, 2006 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_whois);
-SILC_FSM_STATE(silc_server_st_command_whowas);
-SILC_FSM_STATE(silc_server_st_command_identify);
-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 */
+++ /dev/null
-/*
-
- 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_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;
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- 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;
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- 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;
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- server_st_packet.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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_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_EVENT_SIGNAL(&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_EVENT_SIGNAL(&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_EVENT_SIGNAL(&ac->wait_register);
-
- return SILC_FSM_FINISH;
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- server_st_query.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2002 - 2006 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 ***************************/
-
-/* Resolving entry */
-typedef struct SilcServerQueryResolveStruct {
- struct SilcServerQueryResolveStruct *next;
- SilcFSMThreadStruct thread; /* FSM thread for waiting reply */
- SilcServerPending pending; /* Pending command context */
- SilcPacketStream stream; /* Resolving connection */
- SilcID *ids; /* Resolved IDs */
- unsigned int ids_count : 30; /* Number of resolved IDs */
- unsigned int attached : 1; /* Set if attached to a resolving */
- unsigned int local : 1; /* Set if client is local to us */
-} *SilcServerQueryResolve;
-
-/* Represents one error occurred during query */
-typedef struct {
- SilcID id; /* ID */
- unsigned int index : 15; /* Index to IDs */
- unsigned int type : 2; /* 0 = take from query->ids, 1 = take
- from args, 2 = no args in error. */
- unsigned int error : 7; /* The actual error (SilcStatus) */
-} *SilcServerQueryError;
-
-/* Query session context */
-typedef struct {
- /* Queried data */
- char *nickname; /* Queried nickname, normalized */
- char *nick_server; /* Queried nickname's server */
- char *server_name; /* Queried server name, normalized */
- char *channel_name; /* Queried channel name, normalized */
- SilcID *ids; /* Queried IDs */
- SilcUInt32 ids_count; /* number of queried IDs */
- SilcUInt32 reply_count; /* Requested reply count */
- SilcDList attrs; /* Requested Attributes in WHOIS */
- SilcFSMEventStruct wait_resolve; /* Resolving signaller */
-
- /* Query session data */
- SilcServerComman cmd; /* Command context for query */
- SilcList clients; /* Found clients */
- SilcList servers; /* Found servers */
- SilcList channels; /* Found channels */
- SilcList resolve; /* Clients to resolve */
- SilcList resolvings; /* Ongoing resolvings */
- SilcServerQueryError errors; /* Query errors */
- SilcServerPending redirect; /* Pending redirect */
- SilcUInt16 errors_count; /* number of errors */
- SilcUInt8 resolve_retry; /* Resolving retry count */
- SilcCommand querycmd; /* Query command */
-} *SilcServerQuery;
-
-
-/************************ Static utility functions **************************/
-
-
-/********************************* WHOIS ************************************/
-
-SILC_FSM_STATE(silc_server_st_query_whois)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerCommand cmd = state_context;
- SilcArgumentPayload args = silc_command_get_args(cmd->payload);
- SilcServerQuery query;
-
- SILC_LOG_DEBUG(("WHOIS query"));
-
- query = silc_calloc(1, sizeof(*query));
- if (!query) {
- silc_server_command_free(cmd);
- return SILC_FSM_FINISH;
- }
-
- query->querycmd = SILC_COMMAND_WHOIS;
- query->cmd = cmd;
-
- silc_fsm_set_state_context(fsm, query);
-
- /* If we are normal server and query contains a nickname OR query
- doesn't contain nickname or ids BUT does contain user attributes,
- send it to the router */
- if (server->server_type != SILC_ROUTER && !server->standalone &&
- cmd->packet->stream != SILC_PRIMARY_ROUTE(server) &&
- (silc_argument_get_arg_type(args, 1, NULL) ||
- (!silc_argument_get_arg_type(args, 1, NULL) &&
- !silc_argument_get_arg_type(args, 4, NULL) &&
- silc_argument_get_arg_type(args, 3, NULL)))) {
- /** Send query to router */
- silc_fsm_next(fsm, silc_server_st_query_send_router);
- return SILC_FSM_CONTINUE;
- }
-
- /** Parse WHOIS query */
- silc_fsm_next(fsm, silc_server_st_query_parse);
- return SILC_FSM_CONTINUE;
-}
-
-
-/********************************* WHOWAS ***********************************/
-
-SILC_FSM_STATE(silc_server_st_query_whowas)
-{
- SilcServerThread thread = fsm_context;
- SilcServerCommand cmd = state_context;
-
- SILC_LOG_DEBUG(("WHOWAS query"));
-
- query = silc_calloc(1, sizeof(*query));
- if (!query) {
- silc_server_command_free(cmd);
- return SILC_FSM_FINISH;
- }
-
- query->querycmd = SILC_COMMAND_WHOWAS;
- query->cmd = cmd;
-
- silc_fsm_set_state_context(fsm, query);
-
- /* WHOWAS query is always sent to router if we are normal server */
- if (server->server_type == SILC_SERVER && !server->standalone &&
- cmd->packet->stream != SILC_PRIMARY_ROUTE(server)) {
- /** Send query to router */
- silc_fsm_next(fsm, silc_server_st_query_send_router);
- return SILC_FSM_CONTINUE;
- }
-
- /** Parse WHOWAS query */
- silc_fsm_next(fsm, silc_server_st_query_parse);
- return SILC_FSM_CONTINUE;
-}
-
-
-/******************************** IDENTIFY **********************************/
-
-SILC_FSM_STATE(silc_server_st_query_identify)
-{
- SilcServerThread thread = fsm_context;
- SilcServerCommand cmd = state_context;
- SilcArgumentPayload args = silc_command_get_args(cmd->payload);
-
- SILC_LOG_DEBUG(("IDENTIFY query"));
-
- query = silc_calloc(1, sizeof(*query));
- if (!query) {
- silc_server_command_free(cmd);
- return SILC_FSM_FINISH;
- }
-
- query->querycmd = SILC_COMMAND_IDENTIFY;
- query->cmd = cmd;
-
- silc_fsm_set_state_context(fsm, query);
-
- /* If we are normal server and query does not contain IDs, send it directly
- to router (it contains nickname, server name or channel name). */
- if (server->server_type == SILC_SERVER && !server->standalone &&
- cmd->packet->stream != SILC_PRIMARY_ROUTE(server) &&
- !silc_argument_get_arg_type(args, 5, NULL)) {
- /** Send query to router */
- silc_fsm_next(fsm, silc_server_st_query_send_router);
- return SILC_FSM_CONTINUE;
- }
-
- /** Parse IDENTIFY query */
- silc_fsm_next(fsm, silc_server_st_query_parse);
- return SILC_FSM_CONTINUE;
-}
-
-
-/**************************** Query redirecting *****************************/
-
-/* Send the query to router for further processing */
-
-SILC_FSM_STATE(silc_server_st_query_send_router)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcBuffer tmpbuf;
- SilcUInt16 cmd_ident, old_ident;
-
- SILC_LOG_DEBUG(("Redirecting query to router"));
-
- /* Send the command to our router */
- cmd_ident = silc_server_cmd_ident(server);
- old_ident = silc_command_get_ident(query->cmd->payload);
- silc_command_set_ident(query->cmd->payload, cmd_ident);
-
- tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
- if (!tmpbuf || !silc_packet_send(SILC_PRIMARY_ROUTE(server),
- SILC_PACKET_COMMAND, 0,
- tmpbuf->data, silc_buffer_len(tmpbuf))) {
- /** Error sending packet */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- silc_command_set_ident(query->cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
-
- /* Statistics */
- server->stat.commands_sent++;
-
- /* Continue parsing the query after receiving reply from router */
- query->redirect = silc_server_command_pending(thread, query->redirect_ident);
- if (!query->redirect) {
- /** No memory */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- /** Wait router reply */
- query->resolved = TRUE;
- silc_fsm_next(fsm, silc_server_st_query_router_reply)
- return SILC_FSM_CONTINUE;
-}
-
-/* Wait for router reply and process the reply when it arrives. */
-
-SILC_FSM_STATE(silc_server_st_query_router_reply)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcServerPending pending = query->redirect;
- SilcBool timedout;
-
- /* Wait here for the reply */
- SILC_FSM_EVENT_TIMEDWAIT(&pending->wait_reply, 10, 0, &timedout);
-
- if (timedout) {
- /** Timeout waiting reply */
- silc_server_command_pending_free(thread, pending);
- silc_server_query_send_error(server, query, SILC_STATUS_ERR_TIMEDOUT, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Check if the query failed */
- if (!silc_command_get_status(pending->reply->payload, NULL, NULL)) {
- SilcBuffer buffer;
-
- SILC_LOG_DEBUG(("Sending error to original query"));
-
- /* Send the same command reply payload which contains the error */
- silc_command_set_command(pending->reply->payload, query->querycmd);
- silc_command_set_ident(pending->reply->payload,
- silc_command_get_ident(query->cmd->payload));
- buffer = silc_command_payload_encode_payload(pending->reply->payload);
- if (buffer)
- silc_packet_send(query->cmd->packet->stream,
- SILC_PACKET_COMMAND_REPLY, 0,
- buffer->data, silc_buffer_len(buffer));
- silc_buffer_free(buffer);
-
- /* Statistics */
- server->stat.commands_sent++;
-
- /** Query error received */
- silc_server_command_pending_free(thread, pending);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- silc_server_command_pending_free(thread, pending);
-
- /** Parse query command */
- silc_fsm_next(fsm, silc_server_st_query_parse);
- return SILC_FSM_CONTINUE;
-}
-
-/***************************** Query processing *****************************/
-
-/* Parse the command query */
-
-SILC_FSM_STATE(silc_server_st_query_parse)
-{
- SilcServerThread thread = fsm_context;
- SilcServerQuery query = state_context;
- SilcServerCommand cmd = query->cmd;
- SilcArgumentPayload args = silc_command_get_args(cmd->payload);
- SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(args);
- unsigned char *tmp;
- SilcID id;
- int i;
-
- SILC_LOG_DEBUG(("Parsing %s query",
- silc_get_command_name(query->querycmd)));
-
- switch (query->querycmd) {
-
- case SILC_COMMAND_WHOIS:
- /* Get requested attributes if set */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN)
- query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
-
- /* Get Client IDs if present. Take IDs always instead of nickname. */
- tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (!tmp) {
- /* No IDs present */
-
- /* Get nickname */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp && !query->attrs) {
- /* No nickname, no ids and no attributes - send error */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
-
- /** Not enough arguments */
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Get the nickname@server string and parse it */
- if (tmp && ((tmp_len > 128) ||
- !silc_parse_userfqdn(tmp, &query->nickname,
- &query->nick_server))) {
- /** Bad nickname */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Check nickname */
- if (tmp) {
- tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
- SILC_STRING_UTF8, 128, &tmp_len);
- if (!tmp) {
- /** Bad nickname */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
- /* XXX why free nickname */
- silc_free(query->nickname);
- query->nickname = tmp;
- }
-
- } else {
- /* Parse the IDs included in the query */
- query->ids = silc_calloc(argc - 3, sizeof(*query->ids));
- if (!query->ids) {
- /** No memory */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- for (i = 0; i < argc - 3; i++) {
- tmp = silc_argument_get_arg_type(args, i + 4, &tmp_len);
- if (!tmp)
- continue;
-
- if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
- id.type != SILC_ID_CLIENT) {
- silc_server_query_add_error(server, query, 1, i + 4,
- SILC_STATUS_ERR_BAD_CLIENT_ID);
- continue;
- }
-
- /* Normal server must check whether this ID exist, and if not then
- send the query to router, unless done so already */
- if (server->server_type == SILC_SERVER && !query->resolved &&
- !silc_server_find_client_by_id(server, &client_id, TRUE, NULL)) {
- /** Send query to router */
- silc_free(query->ids);
- query->ids = NULL;
- query->ids_count = 0;
- silc_fsm_next(fsm, silc_server_st_query_send_router);
- return SILC_FSM_CONTINUE;
- }
-
- query->ids[query->ids_count] = id;
- query->ids_count++;
- }
- }
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (tmp && tmp_len == sizeof(SilcUInt32))
- SILC_GET32_MSB(query->reply_count, tmp);
- break
-
- case SILC_COMMAND_WHOWAS:
- /* Get nickname */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp) {
- /** Not enough arguments */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Get the nickname@server string and parse it */
- if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
- /** Bad nickname */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Check nickname */
- tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
- SILC_STRING_UTF8, 128, &tmp_len);
- if (!tmp) {
- /** Bad nickname */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
- /* XXX why free nickname */
- silc_free(query->nickname);
- query->nickname = tmp;
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (tmp && tmp_len == sizeof(SilcUInt32))
- SILC_GET32_MSB(query->reply_count, tmp);
- break;
-
- case SILC_COMMAND_IDENTIFY:
- /* Get IDs if present. Take IDs always instead of names. */
- tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
- if (!tmp) {
- /* No IDs present */
-
- /* Try get nickname */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (tmp) {
- /* Get the nickname@server string and parse it */
- if (tmp_len > 128 ||
- !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
- silc_server_query_add_error(server, query, 1, 1,
- SILC_STATUS_ERR_BAD_NICKNAME);
-
- /* Check nickname */
- tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
- SILC_STRING_UTF8, 128, &tmp_len);
- if (!tmp) {
- /** Bad nickname */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
- /* XXX why free nickname */
- silc_free(query->nickname);
- query->nickname = tmp;
- }
-
- /* Try get server name */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (tmp) {
- /* Check server name */
- tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
- 256, &tmp_len);
- if (!tmp) {
- /** Bad server name */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_SERVER, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
- query->server_name = tmp;
- }
-
- /* Get channel name */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- if (tmp && tmp_len <= 256) {
- /* Check channel name */
- tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
- 256, &tmp_len);
- if (!tmp) {
- /** Bad channel name */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_BAD_CHANNEL, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
- query->channel_name = tmp;
- }
-
- if (!query->nickname && !query->server_name && !query->channel_name) {
- /** Nothing was queried */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- } else {
- /* Parse the IDs included in the query */
- query->ids = silc_calloc(argc - 4, sizeof(*query->ids));
-
- for (i = 0; i < argc - 4; i++) {
- tmp = silc_argument_get_arg_type(args, i + 5, &tmp_len);
- if (!tmp)
- continue;
-
- if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
- silc_server_query_add_error(server, query, 1, i + 5,
- SILC_STATUS_ERR_BAD_CLIENT_ID);
- continue;
- }
-
- /* Normal server must check whether this ID exist, and if not then
- send the query to router, unless done so already */
- if (server->server_type == SILC_SERVER && !query->resolved) {
- if (id.type == SILC_ID_CLIENT) {
- if (!silc_server_find_client_by_id(server, id, TRUE, NULL)) {
- /** Send query to router */
- silc_free(query->ids);
- query->ids = NULL;
- query->ids_count = 0;
- silc_fsm_next(fsm, silc_server_st_query_send_router);
- return SILC_FSM_CONTINUE;
- }
- } else {
- /* For now all other ID's except Client ID's are explicitly
- sent to router for resolving. */
-
- /** Send query to router */
- silc_free(query->ids);
- query->ids = NULL;
- query->ids_count = 0;
- silc_fsm_next(fsm, silc_server_st_query_send_router);
- return SILC_FSM_CONTINUE;
- }
- }
-
- query->ids[query->ids_count] = id;
- query->ids_count++;
- }
- }
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (tmp && tmp_len == sizeof(SilcUInt32))
- SILC_GET32_MSB(query->reply_count, tmp);
- break;
- }
-
- /** Find entries for query */
- silc_fsm_next(fsm, silc_server_st_query_find);
- return SILC_FSM_CONTINUE;
-}
-
-/* Find the entries according to the query */
-
-SILC_FSM_STATE(silc_server_st_query_find)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcServerCommand cmd = query->cmd;
- SilcIDCacheEntry id_entry;
- SilcID *id;
- void *entry;
- int i;
-
- SILC_LOG_DEBUG(("Finding entries with %s query",
- silc_get_command_name(query->querycmd)));
-
- if (query->nickname) {
- /* Find by nickname */
- if (!silc_server_find_clients(server, query->nickname, &query->clients))
- silc_server_query_add_error(server, query, 1, 1,
- SILC_STATUS_ERR_NO_SUCH_NICK);
- }
-
- if (query->server_name) {
- /* Find server by name */
- if (!silc_server_find_server_by_name(server, query->server_name, TRUE,
- &id_entry))
- silc_server_query_add_error(server, query, 1, 2,
- SILC_STATUS_ERR_NO_SUCH_SERVER);
- else
- silc_list_add(query->servers, id_entry);
- }
-
- if (query->channel_name) {
- /* Find channel by name */
- if (!silc_server_find_channel_by_name(server, query->channel_name,
- &id_entry))
- silc_server_query_add_error(server, query, 1, 3,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- else
- silc_list_add(query->channels, id_entry);
- }
-
- if (query->ids_count) {
- /* Find entries by the queried IDs */
- for (i = 0; i < query->ids_count; i++) {
- id = &query->ids[i];
-
- switch (id->type) {
-
- case SILC_ID_CLIENT:
- /* Get client entry */
- if (!silc_server_find_client_by_id(server, &id->u.client_id, TRUE,
- &id_entry)) {
- silc_server_query_add_error(server, query, 0, i,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- continue;
- }
-
- silc_list_add(query->clients, id_entry);
- break;
-
- case SILC_ID_SERVER:
- /* Get server entry */
- if (!silc_server_find_server_by_id(server, &id->u.server_id, TRUE,
- &id_entry)) {
- silc_server_query_add_error(server, query, 0, i,
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
- continue;
- }
-
- silc_list_add(query->servers, id_entry);
- break;
-
- case SILC_ID_CHANNEL:
- /* Get channel entry */
- if (!silc_server_find_channel_by_id(server, &id->u.channel_id,
- &id_entry)) {
- silc_server_query_add_error(server, query, 0, i,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
- continue;
- }
-
- silc_list_add(query->channels, id_entry);
- break;
-
- default:
- break;
- }
- }
- }
-
- /* Check the attributes to narrow down the search by using them. */
- if (query->attrs) {
- /** Check user attributes */
- silc_fsm_next(fsm, silc_server_st_query_check_attrs);
- return SILC_FSM_CONTINUE;
- }
-
- /** Process found entries */
- silc_fsm_next(fsm, silc_server_st_query_process);
- return SILC_FSM_CONTINUE;
-}
-
-/* Check user attributes to narrow down clients in WHOIS query */
-
-SILC_FSM_STATE(silc_server_st_query_check_attrs)
-{
-
- /** Proecss found entries */
- silc_fsm_next(fsm, silc_server_st_query_process);
- return SILC_FSM_CONTINUE;
-}
-
-/* Process found entries */
-
-SILC_FSM_STATE(silc_server_st_query_process)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcServerCommand cmd = query->cmd;
- SilcServerQueryResolve res;
- SilcIDCacheEntry id_entry;
- SilcClientEntry client_entry;
- SilcServerEntry server_entry;
- SilcChannelEntry channel_entry;
- SilcID *id;
- void *entry;
- int i;
-
- SILC_LOG_DEBUG(("Process %s query",
- silc_get_command_name(query->querycmd)));
-
- SILC_LOG_DEBUG(("Querying %d clients", silc_list_count(query->clients)));
- SILC_LOG_DEBUG(("Querying %d servers", silc_list_count(query->servers)));
- SILC_LOG_DEBUG(("Querying %d channels", silc_list_count(query->channels)));
-
- /* If nothing was found, then just send the errors */
- if (!silc_list_count(query->clients) &&
- !silc_list_count(query->channels) &&
- !silc_list_count(query->servers)) {
- /** Nothing found, send errors */
- silc_fsm_next(fsm, silc_server_st_query_reply);
- return SILC_FSM_CONTINUE;
- }
-
-#if 0
- /* If caller does not want us to resolve anything (has resolved already)
- then just continue with sending the reply */
- if (!resolve) {
- silc_server_query_send_reply(server, query, clients, clients_count,
- servers, servers_count, channels,
- channels_count);
- silc_free(clients);
- silc_free(servers);
- silc_free(channels);
- return;
- }
-#endif
-
- /* Now process all found information and if necessary do some more
- resolving. */
- switch (query->querycmd) {
-
- case SILC_COMMAND_WHOIS:
- silc_list_start(query->clients);
- while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
- client_entry = id_entry->context;
-
- /* Ignore unregistered clients */
- if (!SILC_IS_REGISTERED(client_entry)) {
- silc_list_del(query->clients, id_entry);
- continue;
- }
-
- /* If Requested Attributes is set then we always resolve the client
- information, if not then check whether the entry is complete or not
- and decide whether we need to resolve the missing information. */
- if (!query->attrs) {
-
- /* Even if nickname and stuff are present, we may need to resolve
- the entry on normal server. */
- if (client_entry->nickname && client_entry->username &&
- client_entry->userinfo) {
-
- /* If we are router, client is local to us, or client is on channel
- we do not need to resolve the client information. */
- if (server->server_type != SILC_SERVER ||
- SILC_IS_LOCAL(client_entry)||
- silc_hash_table_count(client_entry->channels) ||
- query->resolved)
- continue;
- }
- }
-
- /* Remove the NOATTR status periodically */
- if (client_entry->data.noattr &&
- client_entry->updated + 600 < time(NULL))
- client_entry->data.noattr = FALSE;
-
- /* When requested attributes is present and local client is detached
- we cannot send the command to the client, we'll reply on behalf of
- the client instead. */
- if (query->attrs && SILC_IS_LOCAL(client_entry) &&
- (client_entry->mode & SILC_UMODE_DETACHED ||
- client_entry->data.noattr))
- continue;
-
-#if 0
- /* If attributes are present in query, and in the entry and we have
- done resolvings already we don't need to resolve anymore */
- if (query->resolved && query->attrs && client_entry->attrs)
- continue;
-#endif
-
- /* Mark this entry to be resolved */
- silc_list_add(query->resolve, id_entry);
- }
- break;
-
- case SILC_COMMAND_WHOWAS:
- silc_list_start(query->clients);
- while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
- client_entry = id_entry->context;
-
- /* Take only unregistered clients */
- if (SILC_IS_REGISTERED(client_entry)) {
- silc_list_del(query->clients, id_entry);
- continue;
- }
-
- /* If both nickname and username are present no resolving is needed */
- if (client_entry->nickname && client_entry->username)
- continue;
-
- /* Mark this entry to be resolved */
- silc_list_add(query->resolve, id_entry);
- }
- break;
-
- case SILC_COMMAND_IDENTIFY:
- silc_list_start(query->clients);
- while ((id_entry = silc_list_get(query->clients)) != SILC_LIST_END) {
- client_entry = id_entry->context;
-
- /* Ignore unregistered clients */
- if (!SILC_IS_REGISTERED(client_entry))
- continue;
-
- /* Even if nickname is present, we may need to resolve the entry
- on normal server. */
- if (client_entry->nickname) {
-
- /* If we are router, client is local to us, or client is on channel
- we do not need to resolve the client information. */
- if (server->server_type != SILC_SERVER ||
- SILC_IS_LOCAL(client_entry)||
- silc_hash_table_count(client_entry->channels) ||
- query->resolved)
- continue;
- }
-
- /* Mark this entry to be resolved */
- silc_list_add(query->resolve, id_entry);
- }
- break;
- }
-
- /* If we need to resolve entries, do it now */
- if (silc_list_count(query->resolve)) {
- /** Resolve entries */
- silc_fsm_next(fsm, silc_server_st_query_resolve);
- return SILC_FSM_CONTINUE;
- }
-
- /** Send reply to query */
- silc_fsm_next(fsm, silc_server_st_query_reply);
- return SILC_FSM_CONTINUE;
-}
-
-/* Resolve incomplete client entries. Other types of entries need not
- resolving. */
-
-SILC_FSM_STATE(silc_server_st_query_resolve)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcArgumentPayload cmd_args = silc_command_get_args(query->cmd->payload);
- SilcServerQueryResolve res;
- SilcIDCacheEntry id_entry;
- unsigned char args[256][28];
- SilcUInt32 arg_lens[256], arg_types[256], argc = 0;
- SilcBuffer res_cmd;
- int i;
-
- SILC_LOG_DEBUG(("Resolve incomplete entries"));
-
- silc_list_start(query->resolve);
- while ((id_entry = silc_list_get(query->resolve)) != SILC_LIST_END) {
- client_entry = id_entry->context;
-
- /* If entry is being resolved, attach to that resolving */
- if (client_entry->data.resolving) {
- res = silc_calloc(1, sizeof(*res));
- if (!res)
- continue;
-
- silc_fsm_thread_init(&res->thread, fsm, res, NULL, NULL, FALSE);
- res->stream = client_entry->stream;
-
- res->pending =
- silc_server_command_pending(thread, client_entry->resolve_cmd_ident);
- if (!res->pending) {
- SILC_LOG_ERROR(("BUG: No pending command for resolving client entry"));
- continue;
- }
-
- res->attached = TRUE;
- silc_list_add(query->resolvings, res);
- continue;
- }
-
- /* Check if we have resolving destination already set */
- silc_list_start(query->resolvings);
- while ((res = silc_list_get(query->resolvings)) != SILC_LIST_END)
- if (res->stream == client_entry->stream && !res->attached)
- break;
-
- if (!res) {
- /* Create new resolving context */
- res = silc_calloc(1, sizeof(*res));
- if (!res)
- continue;
-
- silc_fsm_thread_init(&res->thread, fsm, res, NULL, NULL, FALSE);
- res->stream = client_entry->stream;
-
- res->pending =
- silc_server_command_pending(thread, silc_server_cmd_ident(server));
- if (!res->pending)
- continue;
-
- silc_list_add(query->resolvings, res);
- }
-
- /* Mark the entry as being resolved */
- client_entry->data.resolving = TRUE;
- client_entry->data.resolved = FALSE;
- client_entry->resolve_cmd_ident = res->pending->cmd_ident;
- client_entry->updated = time(NULL);
-
- if (SILC_IS_LOCAL(client_entry))
- res->local = TRUE;
-
- switch (query->querycmd) {
- case SILC_COMMAND_WHOIS:
- case SILC_COMMAND_IDENTIFY:
- res->ids = silc_realloc(res->ids, sizeof(*res->ids) *
- (res->ids_count + 1));
- if (!res->ids)
- continue;
-
- res->ids[res->ids_count++].u.client_id = client_entry->id;
- break;
-
- case SILC_COMMAND_WHOWAS:
- break;
- }
- }
-
- SILC_LOG_DEBUG(("Sending the resolvings"));
-
- /* Send the resolvings */
- silc_list_start(query->resolvings);
- while ((res = silc_list_get(query->resolvings)) != SILC_LIST_END) {
-
- if (!res->attached) {
-
- switch (query->querycmd) {
- case SILC_COMMAND_WHOIS:
- case SILC_COMMAND_IDENTIFY:
-
- /* If Requested Attributes were present put them to this resolving */
- if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
- arg_types[argc] = 3;
- args[argc] = silc_argument_get_arg_type(cmd_args, 3,
- &arg_lens[argc]);
- argc++;
- }
-
- /* Encode IDs */
- for (i = 0; i < res->ids_count; i++) {
- arg_types[argc] = (query->querycmd == SILC_COMMAND_WHOIS ?
- 4 + i : 5 + i);
- silc_id_id2str(&res->ids[argc].u.client_id, SILC_ID_CLIENT,
- args[argc], sizeof(args[argc]), &arg_lens[argc]);
- argc++;
- if (i + 1 > 255)
- break;
- }
-
- /* Send the command */
- res_cmd = silc_command_payload_encode(query->querycmd, argc,
- args, arg_lens, arg_types,
- res->pending->cmd_ident);
- if (!res_cmd) {
- /** No memory */
- silc_server_query_send_error(server, query,
- SILC_STATUS_ERR_RESOURCE_LIMIT, 0);
- silc_fsm_next(fsm, silc_server_st_query_error);
- return SILC_FSM_CONTINUE;
- }
-
- silc_packet_send(res->stream, SILC_PACKET_COMMAND, 0,
- res_cmd->data, silc_buffer_send(res_cmd));
- silc_buffer_free(res_cmd);
- silc_free(res->ids);
- res->ids = NULL;
-
- /* Statistics */
- server->stat.commands_sent++;
- break;
-
- case SILC_COMMAND_WHOWAS:
- /* Send WHOWAS command */
- silc_server_send_command(server, res->stream, query->querycmd,
- res->pending->cmd_ident, 1,
- 1, query->nickname, strlen(query->nickname));
- break;
- }
- }
-
- /*** Resolve */
- silc_fsm_set_state_context(&res->thread, query);
- silc_fsm_start_sync(&res->thread, silc_server_st_query_wait_resolve);
- }
-
- /** Wait all resolvings */
- silc_fsm_next(fsm, silc_server_st_query_resolved);
- return SILC_FSM_CONTINUE;
-}
-
-/* Wait for resolving command reply */
-
-SILC_FSM_STATE(silc_server_st_query_wait_resolve)
-{
- SilcServerQueryResolve res = fsm_context;
- SilcServerQuery query = state_context;
- SilcBool timedout;
-
- /* Wait here for the reply */
- SILC_FSM_EVENT_TIMEDWAIT(&res->pending->wait_reply,
- res->local ? 3 : 10, 0, &timedout);
-
-
-
- silc_list_del(query->resolvings, res);
- silc_server_command_pending_free(res->pending);
- silc_free(res);
-
- /* Signal main thread that reply was received */
- SILC_FSM_EVENT_SIGNAL(&query->wait_resolve);
-
- return SILC_FSM_FINISH;
-}
-
-/* Wait here that all resolvings has been received */
-
-SILC_FSM_STATE(silc_server_st_query_resolved)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcServerCommand cmd = query->cmd;
-
- /* Wait here until all resolvings has arrived */
- SILC_FSM_EVENT_WAIT(&query->wait_resolve);
- if (silc_list_count(query->resolvings) > 0)
- return SILC_FSM_CONTINUE;
-
-}
-
-/* Send the reply to the query. */
-
-SILC_FSM_STATE(silc_server_st_query_reply)
-{
- SilcServerThread thread = fsm_context;
- SilcServer server = thread->server;
- SilcServerQuery query = state_context;
- SilcServerCommand cmd = query->cmd;
- SilcIDCacheEntry id_entry;
-
-}
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- server_util.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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"
-
-/* Return next available command identifier. */
-
-SilcUInt16 silc_server_cmd_ident(SilcServer server)
-{
- SilcUInt16 cmd_ident;
-
- silc_mutex_lock(server->lock);
- cmd_ident = ++server->cmd_ident;
- silc_mutex_unlock(server->lock);
-
- return cmd_ident;
-}
-
-/* XXX locking */
-
-SilcBool silc_server_check_watcher_list(SilcServer server,
- SilcClientEntry client,
- const char *new_nick,
- SilcNotifyType notify)
-{
- return TRUE;
-}
-
-/* This function is used to send the notify packets and motd to the
- incoming client connection. */
-
-void silc_server_send_welcome(SilcServerAccept ac, SilcClientEntry client)
-{
- SilcServer server = ac->thread->server;
- SilcPacketStream stream = client->stream;
-
- SILC_LOG_DEBUG(("Send welcome notifys"));
-
- /* Send some nice info to the client */
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("Welcome to the SILC Network %s",
- client->username));
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("Your host is %s, running version %s",
- server->server_name, SILC_DIST_VERSION_STRING));
-
- if (server->server_type == SILC_ROUTER) {
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("There are %d clients, %d servers and %d "
- "routers in SILC Network",
- server->stat.clients, server->stat.servers,
- server->stat.routers));
- } else {
- if (server->stat.clients && server->stat.servers + 1)
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("There are %d clients, %d servers and %d "
- "routers in SILC Network",
- server->stat.clients, server->stat.servers,
- (server->standalone ? 0 :
- !server->stat.routers ? 1 :
- server->stat.routers)));
- }
-
- if (server->stat.cell_clients && server->stat.cell_servers + 1)
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("There are %d clients on %d servers in our cell",
- server->stat.cell_clients,
- server->stat.cell_servers));
- if (server->server_type == SILC_ROUTER) {
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("I have %d clients, %d channels, %d servers and "
- "%d routers",
- server->stat.my_clients,
- server->stat.my_channels,
- server->stat.my_servers,
- server->stat.my_routers));
- } else {
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("I have %d clients and %d channels formed",
- server->stat.my_clients,
- server->stat.my_channels));
- }
-
- if (server->stat.server_ops || server->stat.router_ops)
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("There are %d server operators and %d router "
- "operators online",
- server->stat.server_ops,
- server->stat.router_ops));
- if (server->stat.my_router_ops + server->stat.my_server_ops)
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("I have %d operators online",
- server->stat.my_router_ops +
- server->stat.my_server_ops));
-
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("Your connection is secured with %s cipher, "
- "key length %d bits",
- silc_cipher_get_name(ac->prop->cipher),
- silc_cipher_get_key_len(ac->prop->cipher)));
- SILC_SERVER_SEND_NOTIFY(server, stream, SILC_NOTIFY_TYPE_NONE,
- ("Your current nickname is %s",
- client->nickname));
-
- /* Send motd */
- silc_server_send_motd(server, stream);
-}
-
-/* Creates new Client ID. */
-
-SilcBool silc_server_create_client_id(SilcServer server, char *nickname,
- SilcClientID *new_id)
-{
- unsigned char hash[16];
- SilcBool finding = FALSE;
-
- SILC_LOG_DEBUG(("Creating new Client ID"));
-
- /* Create hash of the nickname (it's already checked as valid identifier
- string). */
- silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
-
- /* Create the ID */
- memset(new_id, 0, sizeof(*new_id));
- memcpy(new_id->ip.data, server->id.ip.data, server->id.ip.data_len);
- new_id->ip.data_len = server->id.ip.data_len;
- new_id->rnd = silc_rng_get_byte(server->rng);
- memcpy(new_id->hash, hash, CLIENTID_HASH_LEN);
-
- /* Assure that the ID does not exist already */
- while (1) {
- if (!silc_server_find_client_by_id(server, new_id, FALSE, NULL))
- break;
-
- /* The ID exists, start increasing the rnd from 0 until we find a
- ID that does not exist. If we wrap and it still exists then we
- will return FALSE and the caller must send some other nickname
- since this cannot be used anymore. */
- new_id->rnd++;
-
- if (finding && new_id->rnd == 0)
- return FALSE;
-
- if (!finding) {
- new_id->rnd = 0;
- finding = TRUE;
- }
- }
-
- SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(new_id, SILC_ID_CLIENT)));
-
- return TRUE;
-}
-
-/* Creates a Server ID. */
-
-SilcBool silc_server_create_server_id(SilcServer server,
- const char *ip, SilcUInt16 port,
- SilcServerID *new_id)
-{
- SILC_LOG_DEBUG(("Creating new Server ID"));
-
- if (!new_id)
- return FALSE;
-
- /* Create the ID */
-
- if (!silc_net_addr2bin(ip, new_id->ip.data, sizeof(new_id->ip.data)))
- return FALSE;
-
- new_id->ip.data_len = silc_net_is_ip4(ip) ? 4 : 16;
- new_id->port = SILC_SWAB_16(port);
- new_id->rnd = silc_rng_get_rn16(server->rng);
-
- SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(new_id, SILC_ID_SERVER)));
-
- return TRUE;
-}
-
-/* Checks whether the `server_id' is valid. It must be based to the
- IP address provided in the `remote' socket connection. */
-
-SilcBool silc_server_check_server_id(const char *ip_address,
- SilcServerID *server_id)
-{
- unsigned char ip[16];
-
- if (!silc_net_addr2bin(ip_address, ip, sizeof(ip)))
- return FALSE;
-
- if (silc_net_is_ip4(ip_address)) {
- if (!memcmp(server_id->ip.data, ip, 4))
- return TRUE;
- } else {
- if (!memcmp(server_id->ip.data, ip, 16))
- return TRUE;
- }
-
- return FALSE;
-}
+++ /dev/null
-/*
-
- server_util.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 SERVER_UTIL_H
-#define SERVER_UTIL_H
-
-/* This function removes all client entries that are originated from
- `router' and are owned by `entry'. `router' and `entry' can be same
- too. If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
- distributed to our local clients. */
-SilcBool silc_server_remove_clients_by_server(SilcServer server,
- SilcServerEntry router,
- SilcServerEntry entry,
- SilcBool server_signoff);
-
-/* Updates the clients that are originated from the `from' to be originated
- from the `to'. If the `resolve_real_server' is TRUE then this will
- attempt to figure out which clients really are originated from the
- `from' and which are originated from a server that we have connection
- to, when we've acting as backup router. If it is FALSE the `to' will
- be the new source. If `from' is NULL then all clients (except locally
- connected) are updated `to'. */
-void silc_server_update_clients_by_server(SilcServer server,
- SilcServerEntry from,
- SilcServerEntry to,
- SilcBool resolve_real_server);
-
-/* Updates servers that are from `from' to be originated from `to'. This
- will also update the server's connection to `to's connection. */
-void silc_server_update_servers_by_server(SilcServer server,
- SilcServerEntry from,
- SilcServerEntry to);
-
-/* Toggles the enabled/disabled status of local server connections. Packets
- can be sent to the servers when `toggle_enabled' is TRUE and will be
- dropped if `toggle_enabled' is FALSE, after this function is called. */
-void silc_server_local_servers_toggle_enabled(SilcServer server,
- SilcBool toggle_enabled);
-
-/* Removes servers that are originated from the `from'. The server
- entry is deleted in this function. If `remove_clients' is TRUE then
- all clients originated from the server are removed too, and server
- signoff is sent. Note that this does not remove the `from'. This
- also does not remove locally connected servers. */
-void silc_server_remove_servers_by_server(SilcServer server,
- SilcServerEntry from,
- SilcBool remove_clients);
-
-/* Removes channels that are from `from. */
-void silc_server_remove_channels_by_server(SilcServer server,
- SilcServerEntry from);
-
-/* Updates channels that are from `from' to be originated from `to'. */
-void silc_server_update_channels_by_server(SilcServer server,
- SilcServerEntry from,
- SilcServerEntry to);
-
-/* Checks whether given channel has global users. If it does this returns
- TRUE and FALSE if there is only locally connected clients on the channel. */
-SilcBool silc_server_channel_has_global(SilcChannelEntry channel);
-
-/* Checks whether given channel has locally connected users. If it does this
- returns TRUE and FALSE if there is not one locally connected client. */
-SilcBool silc_server_channel_has_local(SilcChannelEntry channel);
-
-/* This function removes the channel and all users on the channel, unless
- the channel is permanent. In this case the channel is disabled but all
- users are removed from the channel. Returns TRUE if the channel is
- destroyed totally, and FALSE if it is permanent and remains. */
-SilcBool silc_server_channel_delete(SilcServer server,
- SilcChannelEntry channel);
-
-/* Returns TRUE if the given client is on the channel. FALSE if not.
- This works because we assure that the user list on the channel is
- always in up to date thus we can only check the channel list from
- `client' which is faster than checking the user list from `channel'. */
-SilcBool silc_server_client_on_channel(SilcClientEntry client,
- SilcChannelEntry channel,
- SilcChannelClientEntry *chl);
-
-/* Find number of sockets by IP address indicated by `ip'. Returns 0 if
- socket connections with the IP address does not exist. */
-SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
- SilcSocketType type);
-
-/* Find number of sockets by IP address indicated by remote host, indicated
- by `ip' or `hostname', `port', and `type'. Returns 0 if socket connections
- does not exist. If `ip' is provided then `hostname' is ignored. */
-SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
- const char *ip,
- const char *hostname,
- SilcUInt16 port,
- SilcSocketType type);
-
-/* Finds locally cached public key by the public key received in the SKE.
- If we have it locally cached then we trust it and will use it in the
- authentication protocol. Returns the locally cached public key or NULL
- if we do not find the public key. */
-SilcPublicKey silc_server_find_public_key(SilcServer server,
- SilcHashTable local_public_keys,
- SilcPublicKey remote_public_key);
-
-/* This returns the first public key from the table of public keys. This
- is used only in cases where single public key exists in the table and
- we want to get a pointer to it. For public key tables that has multiple
- keys in it the silc_server_find_public_key must be used. */
-SilcPublicKey silc_server_get_public_key(SilcServer server,
- SilcHashTable local_public_keys);
-
-/* Check whether the connection `sock' is allowed to connect to us. This
- checks for example whether there is too much connections for this host,
- and required version for the host etc. */
-SilcBool silc_server_connection_allowed(SilcServer server,
- SilcSocketConnection sock,
- SilcSocketType type,
- SilcServerConfigConnParams *global,
- SilcServerConfigConnParams *params,
- SilcSKE ske);
-
-/* Checks that client has rights to add or remove channel modes. If any
- of the checks fails FALSE is returned. */
-SilcBool silc_server_check_cmode_rights(SilcServer server,
- SilcChannelEntry channel,
- SilcChannelClientEntry client,
- SilcUInt32 mode);
-
-/* Check that the client has rights to change its user mode. Returns
- FALSE if setting some mode is not allowed. */
-SilcBool silc_server_check_umode_rights(SilcServer server,
- SilcClientEntry client,
- SilcUInt32 mode);
-
-/* This function is used to send the notify packets and motd to the
- incoming client connection. */
-void silc_server_send_connect_notifys(SilcServer server,
- SilcSocketConnection sock,
- SilcClientEntry client);
-
-/* Kill the client indicated by `remote_client' sending KILLED notify
- to the client, to all channels client has joined and to primary
- router if needed. The killed client is also removed from all channels. */
-void silc_server_kill_client(SilcServer server,
- SilcClientEntry remote_client,
- const char *comment,
- void *killer_id,
- SilcIdType killer_id_type);
-
-/* This function checks whether the `client' nickname is being watched
- by someone, and notifies the watcher of the notify change of notify
- type indicated by `notify'. */
-SilcBool silc_server_check_watcher_list(SilcServer server,
- SilcClientEntry client,
- const char *new_nick,
- SilcNotifyType notify);
-
-/* Remove the `client' from watcher list. After calling this the `client'
- is not watching any nicknames. */
-SilcBool silc_server_del_from_watcher_list(SilcServer server,
- SilcClientEntry client);
-
-/* Force the client indicated by `chl' to change the channel user mode
- on channel indicated by `channel' to `forced_mode'. */
-SilcBool silc_server_force_cumode_change(SilcServer server,
- SilcSocketConnection sock,
- SilcChannelEntry channel,
- SilcChannelClientEntry chl,
- SilcUInt32 forced_mode);
-
-/* Find active socket connection by the IP address and port indicated by
- `ip' and `port', and socket connection type of `type'. */
-SilcSocketConnection
-silc_server_find_socket_by_host(SilcServer server,
- SilcSocketType type,
- const char *ip, SilcUInt16 port);
-
-/* This function can be used to match the invite and ban lists. */
-SilcBool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
- SilcUInt8 type, void *check);
-
-/* Process invite or ban information */
-SilcBool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
- SilcUInt8 action, SilcArgumentPayload args);
-
-/* Destructor for invite or ban list entrys */
-void silc_server_inviteban_destruct(void *key, void *context,
- void *user_context);
-
-/* Creates connections according to configuration. */
-void silc_server_create_connections(SilcServer server);
-
-
-/* Processes a channel public key, either adds or removes it. */
-SilcStatus
-silc_server_process_channel_pk(SilcServer server,
- SilcChannelEntry channel,
- SilcUInt32 type, const unsigned char *pk,
- SilcUInt32 pk_len);
-
-/* Returns the channel public keys as Argument List payload. */
-SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
- SilcChannelEntry channel,
- SilcBool announce,
- SilcBool delete);
-
-/* Sets the channel public keys into channel from the list of public keys. */
-SilcStatus silc_server_set_channel_pk_list(SilcServer server,
- SilcSocketConnection sender,
- SilcChannelEntry channel,
- const unsigned char *pklist,
- SilcUInt32 pklist_len);
-
-/* Verifies the Authentication Payload `auth' with one of the public keys
- on the `channel' public key list. */
-SilcBool silc_server_verify_channel_auth(SilcServer server,
- SilcChannelEntry channel,
- SilcClientID *client_id,
- const unsigned char *auth,
- SilcUInt32 auth_len);
-
-#endif /* SERVER_UTIL_H */
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-#
-# 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
+++ /dev/null
-#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*,*pkcs*,*asn1*");
- }
-
- 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", "",
- &info->public_key,
- &info->private_key)) {
- if (!silc_create_key_pair("rsa", 2048, "test.pub", "test.prv", 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;
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 2003 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcsftp.h"
#include "sftp_util.h"
/* Request context. Every request will allocate this context and set
the correct callback function according the `type' field. */
typedef struct SilcSFTPRequestStruct {
- struct SilcSFTPRequestStruct *next;
+ SilcUInt32 id;
+ SilcSFTPPacket type;
SilcSFTPStatusCallback status;
SilcSFTPHandleCallback handle;
SilcSFTPDataCallback data;
SilcSFTPAttrCallback attr;
SilcSFTPExtendedCallback extended;
void *context;
- SilcUInt32 id;
- SilcSFTPPacket type;
+ struct SilcSFTPRequestStruct *next;
} *SilcSFTPRequest;
/* SFTP client context */
typedef struct {
- SilcStream stream;
- SilcSchedule schedule;
+ SilcSFTPSendPacketCallback send_packet;
+ void *send_context;
SilcSFTPVersionCallback version;
- SilcSFTPErrorCallback error;
- void *context;
+ void *version_context;
+ SilcUInt32 id;
SilcList requests;
SilcBuffer packet;
- SilcUInt32 id;
} *SilcSFTPClient;
/* File handle */
SilcUInt32 data_len;
};
-static void silc_sftp_client_receive_process(SilcSFTP context,
- SilcBuffer buffer);
-
/* Creates SilcSFTPHandle and returns pointer to it. The caller must free
the context. */
*data_len = handle->data_len;
}
-/* Generic routine to send SFTP packet to the SFTP server. */
+/* General routine to send SFTP packet to the SFTP server. */
static void silc_sftp_send_packet(SilcSFTPClient sftp,
SilcSFTPPacket type,
{
SilcBuffer tmp;
va_list vp;
- int ret;
va_start(vp, len);
tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
sftp->packet = tmp;
SILC_LOG_HEXDUMP(("SFTP packet to server"), sftp->packet->data,
- silc_buffer_len(sftp->packet));
+ sftp->packet->len);
/* Send the packet */
- while (silc_buffer_len(sftp->packet) > 0) {
- ret = silc_stream_write(sftp->stream, silc_buffer_data(sftp->packet),
- silc_buffer_len(sftp->packet));
- if (ret == -2) {
- SILC_LOG_ERROR(("Error sending SFTP packet type %d", type));
- sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_NO_CONNECTION,
- sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
- if (ret == 0) {
- sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_EOF, sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
- if (ret == -1)
- return;
-
- silc_buffer_pull(sftp->packet, ret);
- }
+ (*sftp->send_packet)(sftp->packet, sftp->send_context);
/* Clear packet */
- silc_buffer_reset(sftp->packet);
+ sftp->packet->data = sftp->packet->tail = sftp->packet->head;
+ sftp->packet->len = 0;
}
/* Finds request by request ID. */
-static SilcSFTPRequest silc_sftp_find_request(SilcSFTPClient sftp,
- SilcUInt32 id)
+static SilcSFTPRequest silc_sftp_find_request(SilcSFTPClient sftp, SilcUInt32 id)
{
SilcSFTPRequest req;
return req;
}
- SILC_LOG_DEBUG(("Unknown request ID %d", id));
+ SILC_LOG_DEBUG(("Unknown request ID"));
return NULL;
}
break;
default:
- SILC_LOG_DEBUG(("Unknown request type %d", req->type));
break;
}
va_end(vp);
}
-/* Handles stream I/O */
+/* Starts SFTP client and returns context for it. The version callback
+ indicated by the `callback' will be called after the SFTP session has
+ been started and server has returned the version of the protocol. The
+ SFTP client context is returned in the callback too. This returns
+ allocated SFTP client context or NULL on error. */
-static void silc_sftp_client_io(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SilcSFTPClient sftp = context;
- unsigned char inbuf[33792];
- SilcBufferStruct packet;
- int ret;
-
- switch (status) {
- case SILC_STREAM_CAN_READ:
- SILC_LOG_DEBUG(("Reading data from stream"));
-
- /* Read data from stream */
- ret = silc_stream_read(stream, inbuf, sizeof(inbuf));
- if (ret <= 0) {
- if (ret == 0)
- sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
- if (ret == -2)
- sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
- return;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes", ret));
-
- /* Now process the SFTP packet */
- silc_buffer_set(&packet, inbuf, ret);
- silc_sftp_client_receive_process(context, &packet);
- break;
-
- case SILC_STREAM_CAN_WRITE:
- if (!silc_buffer_headlen(sftp->packet))
- return;
-
- SILC_LOG_DEBUG(("Writing pending data to stream"));
-
- /* Write pending data to stream */
- silc_buffer_push(sftp->packet, silc_buffer_headlen(sftp->packet));
- while (silc_buffer_len(sftp->packet) > 0) {
- ret = silc_stream_write(stream, sftp->packet->data,
- silc_buffer_len(sftp->packet));
- if (ret == 0) {
- sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
-
- if (ret == -2) {
- sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
-
- if (ret == -1)
- return;
-
- /* Wrote data */
- silc_buffer_pull(sftp->packet, ret);
- }
- break;
-
- default:
- break;
- }
-}
-
-/* Starts SFTP client and returns context for it. */
-
-SilcSFTP silc_sftp_client_start(SilcStream stream,
- SilcSchedule schedule,
- SilcSFTPVersionCallback version_cb,
- SilcSFTPErrorCallback error_cb,
+SilcSFTP silc_sftp_client_start(SilcSFTPSendPacketCallback send_packet,
+ void *send_context,
+ SilcSFTPVersionCallback callback,
void *context)
{
SilcSFTPClient sftp;
- SILC_LOG_DEBUG(("Starting SFTP client"));
-
- if (!stream)
+ if (!send_packet)
return NULL;
sftp = silc_calloc(1, sizeof(*sftp));
if (!sftp)
return NULL;
- sftp->stream = stream;
- sftp->version = version_cb;
- sftp->error = error_cb;
- sftp->context = context;
- sftp->schedule = schedule;
+ sftp->send_packet = send_packet;
+ sftp->send_context = send_context;
+ sftp->version = callback;
+ sftp->version_context = context;
silc_list_init(sftp->requests, struct SilcSFTPRequestStruct, next);
- /* We handle the stream now */
- silc_stream_set_notifier(stream, schedule, silc_sftp_client_io, sftp);
-
/* Send the SFTP session initialization to the server */
silc_sftp_send_packet(sftp, SILC_SFTP_INIT, 4,
SILC_STR_UI_INT(SILC_SFTP_PROTOCOL_VERSION),
{
SilcSFTPClient sftp = (SilcSFTPClient)context;
- silc_stream_set_notifier(sftp->stream, sftp->schedule, NULL, NULL);
if (sftp->packet)
silc_buffer_free(sftp->packet);
silc_free(sftp);
}
/* Function that is called to process the incmoing SFTP packet. */
+/* XXX Some day this will go away and we have automatic receive callbacks
+ for SilcSocketConnection API or SilcPacketContext API. */
-void silc_sftp_client_receive_process(SilcSFTP context, SilcBuffer buffer)
+void silc_sftp_client_receive_process(SilcSFTP context,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
SilcSFTPClient sftp = (SilcSFTPClient)context;
SilcSFTPRequest req;
SilcSFTPPacket type;
- unsigned char *payload = NULL;
+ const unsigned char *payload = NULL;
SilcUInt32 payload_len;
int ret;
SilcBufferStruct buf;
SilcUInt32 id;
- SILC_LOG_DEBUG(("Process SFTP packet"));
+ SILC_LOG_DEBUG(("Start"));
/* Parse the packet */
- type = silc_sftp_packet_decode(buffer, &payload, &payload_len);
- if (type <= 0)
+ type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
+ &payload_len);
+ if (!type)
return;
- silc_buffer_set(&buf, payload, payload_len);
+ silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
switch (type) {
- case SILC_SFTP_DATA:
- {
- unsigned char *data = NULL;
- SilcUInt32 data_len = 0;
-
- SILC_LOG_DEBUG(("Data packet"));
-
- ret = silc_buffer_unformat(&buf,
- SILC_STR_UI_INT(&id),
- SILC_STR_UI32_NSTRING(&data, &data_len),
- SILC_STR_END);
- if (ret < 0)
- break;
-
- /* Get request */
- req = silc_sftp_find_request(sftp, id);
- if (!req)
- break;
-
- /* Call the callback */
- silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
- data, data_len);
- }
- break;
-
case SILC_SFTP_VERSION:
{
SilcSFTPVersion version;
SILC_STR_END);
if (ret < 0) {
(*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_FAILURE, 0,
- sftp->context);
+ sftp->version_context);
break;
}
/* Call the callback */
(*sftp->version)((SilcSFTP)sftp, SILC_SFTP_STATUS_OK, version,
- sftp->context);
+ sftp->version_context);
}
break;
}
break;
+ case SILC_SFTP_DATA:
+ {
+ unsigned char *data = NULL;
+ SilcUInt32 data_len = 0;
+
+ SILC_LOG_DEBUG(("Data packet"));
+
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&id),
+ SILC_STR_UI32_NSTRING(&data, &data_len),
+ SILC_STR_END);
+ if (ret < 0)
+ break;
+
+ /* Get request */
+ req = silc_sftp_find_request(sftp, id);
+ if (!req)
+ break;
+
+ /* Call the callback */
+ silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
+ data, data_len);
+ }
+ break;
+
case SILC_SFTP_NAME:
{
SilcUInt32 count;
SILC_LOG_DEBUG(("Attributes packet"));
- ret =
- silc_buffer_unformat(&buf,
- SILC_STR_UI_INT(&id),
- SILC_STR_DATA(&data, silc_buffer_len(&buf) - 4),
- SILC_STR_END);
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&id),
+ SILC_STR_UI_XNSTRING(&data, buf.len - 4),
+ SILC_STR_END);
if (ret < 0)
break;
if (!req)
break;
- silc_buffer_set(&tmpbuf, data, silc_buffer_len(&buf) - 4);
+ silc_buffer_set(&tmpbuf, data, buf.len - 4);
attr = silc_sftp_attr_decode(&tmpbuf);
if (!attr)
break;
ret = silc_buffer_unformat(&buf,
SILC_STR_UI_INT(&id),
- SILC_STR_DATA(&data,
- silc_buffer_len(&buf) - 4),
+ SILC_STR_UI_XNSTRING(&data, buf.len - 4),
SILC_STR_END);
if (ret < 0)
break;
/* Call the callback */
silc_sftp_call_request(sftp, req, type, SILC_SFTP_STATUS_OK,
- data, silc_buffer_len(&buf) - 4);
+ data, buf.len - 4);
}
break;
attrs_buf = silc_sftp_attr_encode(attrs);
if (!attrs_buf)
return;
- len = 4 + 4 + strlen(filename) + 4 + silc_buffer_len(attrs_buf);
+ len = 4 + 4 + strlen(filename) + 4 + attrs_buf->len;
silc_sftp_send_packet(client, req->type, len,
SILC_STR_UI_INT(req->id),
SILC_STR_UI32_STRING(filename),
SILC_STR_UI_INT(pflags),
SILC_STR_UI_XNSTRING(attrs_buf->data,
- silc_buffer_len(attrs_buf)),
+ attrs_buf->len),
SILC_STR_END);
silc_buffer_free(attrs_buf);
attrs_buf = silc_sftp_attr_encode(attrs);
if (!attrs_buf)
return;
- len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
+ len = 4 + 4 + strlen(path) + attrs_buf->len;
silc_sftp_send_packet(client, req->type, len,
SILC_STR_UI_INT(req->id),
SILC_STR_UI_INT(strlen(path)),
SILC_STR_UI32_STRING(path),
SILC_STR_UI_XNSTRING(attrs_buf->data,
- silc_buffer_len(attrs_buf)),
+ attrs_buf->len),
SILC_STR_END);
silc_buffer_free(attrs_buf);
attrs_buf = silc_sftp_attr_encode(attrs);
if (!attrs_buf)
return;
- len = 4 + 4 + strlen(path) + silc_buffer_len(attrs_buf);
+ len = 4 + 4 + strlen(path) + attrs_buf->len;
silc_sftp_send_packet(client, req->type, len,
SILC_STR_UI_INT(req->id),
SILC_STR_UI_INT(strlen(path)),
SILC_STR_UI32_STRING(path),
SILC_STR_UI_XNSTRING(attrs_buf->data,
- silc_buffer_len(attrs_buf)),
+ attrs_buf->len),
SILC_STR_END);
silc_buffer_free(attrs_buf);
attrs_buf = silc_sftp_attr_encode(attrs);
if (!attrs_buf)
return;
- len = 4 + 4 + hdata_len + silc_buffer_len(attrs_buf);
+ len = 4 + 4 + hdata_len + attrs_buf->len;
silc_sftp_send_packet(client, req->type, len,
SILC_STR_UI_INT(req->id),
SILC_STR_UI_INT(hdata_len),
SILC_STR_UI_XNSTRING(hdata, hdata_len),
SILC_STR_UI_XNSTRING(attrs_buf->data,
- silc_buffer_len(attrs_buf)),
+ attrs_buf->len),
SILC_STR_END);
silc_buffer_free(attrs_buf);
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2004 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
/* $Id$ */
/* XXX TODO Win32 support */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcsftp.h"
#include "silcsftp_fs.h"
#include "sftp_util.h"
/* Add `entry' to directory `dir'. */
-static SilcBool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
- SilcBool check_perm)
+static bool mem_add_entry(MemFSEntry dir, MemFSEntry entry,
+ bool check_perm)
{
int i;
/* Removes entry `entry' and all entries under it recursively. */
-static SilcBool mem_del_entry(MemFSEntry entry, SilcBool check_perm)
+static bool mem_del_entry(MemFSEntry entry, bool check_perm)
{
int i;
/* Deletes entry by the name `name' from the directory `dir'. This does
not check subdirectories recursively. */
-static SilcBool mem_del_entry_name(MemFSEntry dir, const char *name,
- SilcUInt32 name_len, SilcBool check_perm)
+static bool mem_del_entry_name(MemFSEntry dir, const char *name,
+ SilcUInt32 name_len, bool check_perm)
{
MemFSEntry entry;
/* Deletes the handle and remove it from the open handle list. */
-static SilcBool mem_del_handle(MemFS fs, MemFSFileHandle handle)
+static bool mem_del_handle(MemFS fs, MemFSFileHandle handle)
{
if (handle->handle > fs->handles_count)
return FALSE;
fs->root_perm = perm;
fs->root->directory = TRUE;
fs->root->name = strdup(DIR_SEPARATOR);
- if (!fs->root->name) {
- silc_free(fs->root);
- silc_free(fs);
- }
filesystem = silc_calloc(1, sizeof(*filesystem));
if (!filesystem) {
- silc_free(fs->root->name);
silc_free(fs->root);
silc_free(fs);
return NULL;
return NULL;
entry->perm = perm;
+ entry->name = strdup(name);
entry->directory = TRUE;
entry->parent = dir ? dir : memfs->root;
- entry->name = strdup(name);
- if (!entry->name) {
- silc_free(entry);
- return NULL;
- }
- if (!mem_add_entry(dir ? dir : memfs->root, entry, FALSE)) {
- silc_free(entry->name);
- silc_free(entry);
+ if (!mem_add_entry(dir ? dir : memfs->root, entry, FALSE))
return NULL;
- }
return entry;
}
in memory file system. The filesystem does not allow removing directories
with remote access using the filesystem access function sftp_rmdir. */
-SilcBool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
+bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir)
{
MemFS memfs = (MemFS)fs->fs_context;
- SilcBool ret;
+ bool ret;
if (dir)
return mem_del_entry(dir, FALSE);
memfs->root->perm = memfs->root_perm;
memfs->root->directory = TRUE;
memfs->root->name = strdup(DIR_SEPARATOR);
- if (!memfs->root->name) {
- silc_free(memfs->root);
- memfs->root = NULL;
- return FALSE;
- }
return ret;
}
file and they work in POSIX style. Returns TRUE if the file was
added to the directory. */
-SilcBool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
- SilcSFTPFSMemoryPerm perm,
- const char *filename,
- const char *realpath)
+bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
+ SilcSFTPFSMemoryPerm perm,
+ const char *filename,
+ const char *realpath)
{
MemFS memfs = (MemFS)fs->fs_context;
MemFSEntry entry;
return FALSE;
entry->perm = perm;
- entry->directory = FALSE;
entry->name = strdup(filename);
entry->data = strdup(realpath);
- if (!entry->name || !entry->data) {
- silc_free(entry->name);
- silc_free(entry->data);
- silc_free(entry);
- return FALSE;
- }
+ entry->directory = FALSE;
return mem_add_entry(dir ? dir : memfs->root, entry, FALSE);
}
/* Removes a file indicated by the `filename' from the directory
indicated by the `dir'. Returns TRUE if the removing was success. */
-SilcBool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
- const char *filename)
+bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
+ const char *filename)
{
MemFS memfs = (MemFS)fs->fs_context;
void *callback_context)
{
MemFSFileHandle h = (MemFSFileHandle)handle;
- unsigned char data[32768];
+ unsigned char *data;
int ret;
if (len > 32768)
len = 32768;
- ret = lseek(h->fd, (off_t)offset, SEEK_SET);
- if (ret < 0) {
- if (!ret)
- (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
- else
- (*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
+ data = silc_malloc(len);
+ if (!data) {
+ (*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
return;
}
+ lseek(h->fd, (off_t)offset, SEEK_SET);
/* Attempt to read */
ret = silc_file_read(h->fd, data, len);
(*callback)(sftp, SILC_SFTP_STATUS_EOF, NULL, 0, callback_context);
else
(*callback)(sftp, silc_sftp_map_errno(errno), NULL, 0, callback_context);
+ silc_free(data);
return;
}
/* Return data */
(*callback)(sftp, SILC_SFTP_STATUS_OK, (const unsigned char *)data,
ret, callback_context);
+
+ silc_free(data);
}
void mem_write(void *context, SilcSFTP sftp,
filesize = sizeof(*entry);
memset(long_name, 0, sizeof(long_name));
- date = (char *)silc_time_string(entry->created);
+ date = (char *)silc_get_time(entry->created);
if (strrchr(date, ':'))
*strrchr(date, ':') = '\0';
/* Long name format is:
drwx------ 1 324210 Apr 8 08:40 mail/
1234567890 123 12345678 123456789012 */
- silc_snprintf(long_name, sizeof(long_name) - 1,
+ snprintf(long_name, sizeof(long_name) - 1,
"%c%c%c%c------ %3d %8llu %12s %s%s",
(entry->directory ? 'd' : '-'),
((entry->perm & SILC_SFTP_FS_PERM_READ) ? 'r' : '-'),
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 2004 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcsftp.h"
#include "silcsftp_fs.h"
#include "sftp_util.h"
/* SFTP Server context */
typedef struct {
- SilcStream stream;
- SilcSchedule schedule;
+ SilcSFTPSendPacketCallback send_packet;
+ void *send_context;
SilcSFTPMonitors monitors;
SilcSFTPMonitor monitor;
void *monitor_context;
SilcSFTPFilesystem fs;
SilcBuffer packet;
- SilcSFTPErrorCallback error;
- void *context;
} *SilcSFTPServer;
-static void silc_sftp_server_receive_process(SilcSFTP sftp, SilcBuffer buffer);
-
/* General routine to send SFTP packet to the SFTP client. */
static void silc_sftp_send_packet(SilcSFTPServer sftp,
{
SilcBuffer tmp;
va_list vp;
- int ret;
va_start(vp, len);
tmp = silc_sftp_packet_encode_vp(type, sftp->packet, len, vp);
return;
sftp->packet = tmp;
- SILC_LOG_HEXDUMP(("SFTP packet to client"), silc_buffer_data(sftp->packet),
- silc_buffer_len(sftp->packet));
+ SILC_LOG_HEXDUMP(("SFTP packet to client"), sftp->packet->data,
+ sftp->packet->len);
/* Send the packet */
- while (silc_buffer_len(sftp->packet) > 0) {
- ret = silc_stream_write(sftp->stream, silc_buffer_data(sftp->packet),
- silc_buffer_len(sftp->packet));
- if (ret == -2) {
- SILC_LOG_ERROR(("Error sending SFTP packet type %d", type));
- sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_NO_CONNECTION,
- sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
- if (ret == 0) {
- sftp->error((SilcSFTP)sftp, SILC_SFTP_STATUS_EOF, sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
- if (ret == -1)
- return;
-
- silc_buffer_pull(sftp->packet, ret);
- }
+ (*sftp->send_packet)(sftp->packet, sftp->send_context);
/* Clear packet */
- silc_buffer_reset(sftp->packet);
-}
-
-/* Handles stream I/O */
-
-static void silc_sftp_server_io(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SilcSFTPServer sftp = context;
- unsigned char inbuf[33792];
- SilcBufferStruct packet;
- int ret;
-
- switch (status) {
- case SILC_STREAM_CAN_READ:
- SILC_LOG_DEBUG(("Reading data from stream"));
-
- /* Read data from stream */
- ret = silc_stream_read(stream, inbuf, sizeof(inbuf));
- if (ret <= 0) {
- if (ret == 0)
- sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
- if (ret == -2)
- sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
- return;
- }
-
- /* Now process the SFTP packet */
- silc_buffer_set(&packet, inbuf, ret);
- silc_sftp_server_receive_process(context, &packet);
- break;
-
- case SILC_STREAM_CAN_WRITE:
- if (!silc_buffer_headlen(sftp->packet))
- return;
-
- SILC_LOG_DEBUG(("Writing pending data to stream"));
-
- /* Write pending data to stream */
- silc_buffer_push(sftp->packet, silc_buffer_headlen(sftp->packet));
- while (silc_buffer_len(sftp->packet) > 0) {
- ret = silc_stream_write(stream, sftp->packet->data,
- silc_buffer_len(sftp->packet));
- if (ret == 0) {
- sftp->error(context, SILC_SFTP_STATUS_EOF, sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
-
- if (ret == -2) {
- sftp->error(context, SILC_SFTP_STATUS_NO_CONNECTION, sftp->context);
- silc_buffer_reset(sftp->packet);
- return;
- }
-
- if (ret == -1)
- return;
-
- /* Wrote data */
- silc_buffer_pull(sftp->packet, ret);
- }
- break;
-
- default:
- break;
- }
+ sftp->packet->data = sftp->packet->tail = sftp->packet->head;
+ sftp->packet->len = 0;
}
/* Sends error to the client */
return;
}
- silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + silc_buffer_len(namebuf),
+ silc_sftp_send_packet(server, SILC_SFTP_NAME, 4 + namebuf->len,
SILC_STR_UI_INT(id),
- SILC_STR_DATA(silc_buffer_data(namebuf),
- silc_buffer_len(namebuf)),
+ SILC_STR_UI_XNSTRING(namebuf->data, namebuf->len),
SILC_STR_END);
}
return;
}
- silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + silc_buffer_len(attr_buf),
+ silc_sftp_send_packet(server, SILC_SFTP_ATTRS, 4 + attr_buf->len,
SILC_STR_UI_INT(id),
- SILC_STR_DATA(silc_buffer_data(attr_buf),
- silc_buffer_len(attr_buf)),
+ SILC_STR_UI_XNSTRING(attr_buf->data, attr_buf->len),
SILC_STR_END);
silc_buffer_free(attr_buf);
by the library when it needs to send a packet. The `fs' is the
structure containing filesystem access callbacks. */
-SilcSFTP silc_sftp_server_start(SilcStream stream,
- SilcSchedule schedule,
- SilcSFTPErrorCallback error_cb,
- void *context,
+SilcSFTP silc_sftp_server_start(SilcSFTPSendPacketCallback send_packet,
+ void *send_context,
SilcSFTPFilesystem fs)
{
SilcSFTPServer server;
server = silc_calloc(1, sizeof(*server));
if (!server)
return NULL;
- server->stream = stream;
- server->schedule = schedule;
- server->error = error_cb;
- server->context = context;
+ server->send_packet = send_packet;
+ server->send_context = send_context;
server->fs = fs;
- /* We handle the stream now */
- silc_stream_set_notifier(stream, schedule, silc_sftp_server_io, server);
-
SILC_LOG_DEBUG(("Starting SFTP server %p", server));
return (SilcSFTP)server;
SILC_LOG_DEBUG(("Stopping SFTP server %p", server));
- silc_stream_set_notifier(server->stream, server->schedule, NULL, NULL);
if (server->packet)
silc_buffer_free(server->packet);
silc_free(server);
}
/* Function that is called to process the incmoing SFTP packet. */
+/* XXX Some day this will go away and we have automatic receive callbacks
+ for SilcSocketConnection API or SilcPacketContext API. */
-static void silc_sftp_server_receive_process(SilcSFTP sftp, SilcBuffer buffer)
+void silc_sftp_server_receive_process(SilcSFTP sftp,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
SilcSFTPServer server = (SilcSFTPServer)sftp;
SilcSFTPPacket type;
char *filename = NULL, *path = NULL;
- unsigned char *payload = NULL;
+ const unsigned char *payload = NULL;
SilcUInt32 payload_len;
int ret;
SilcBufferStruct buf;
SILC_LOG_DEBUG(("Start"));
/* Parse the packet */
- type = silc_sftp_packet_decode(buffer, &payload, &payload_len);
- if (type <= 0)
+ type = silc_sftp_packet_decode(packet->buffer, (unsigned char **)&payload,
+ &payload_len);
+ if (!type)
return;
- silc_buffer_set(&buf, payload, payload_len);
+ silc_buffer_set(&buf, (unsigned char *)payload, payload_len);
memset(&mdata, 0, sizeof(mdata));
switch (type) {
- case SILC_SFTP_READ:
- {
- unsigned char *hdata;
- SilcUInt32 hdata_len;
- SilcUInt64 offset;
- SilcUInt32 len;
-
- SILC_LOG_DEBUG(("Read request"));
-
- ret = silc_buffer_unformat(&buf,
- SILC_STR_UI_INT(&id),
- SILC_STR_UI32_NSTRING(&hdata,
- &hdata_len),
- SILC_STR_UI_INT64(&offset),
- SILC_STR_UI_INT(&len),
- SILC_STR_END);
- if (ret < 0)
- goto failure;
-
- /* Get the handle */
- handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
- (const unsigned char *)hdata,
- hdata_len);
- if (!handle) {
- silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
- break;
- }
-
- /* Read operation */
- server->fs->fs->sftp_read(server->fs->fs_context, sftp,
- handle, offset, len,
- silc_sftp_server_data, SILC_32_TO_PTR(id));
-
- /* Call monitor */
- if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
- mdata.offset = offset;
- mdata.data_len = len;
- (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
- server->monitor_context);
- }
- }
- break;
-
- case SILC_SFTP_WRITE:
- {
- unsigned char *hdata;
- SilcUInt32 hdata_len;
- SilcUInt64 offset;
- unsigned char *data;
- SilcUInt32 data_len;
-
- SILC_LOG_DEBUG(("Read request"));
-
- ret = silc_buffer_unformat(&buf,
- SILC_STR_UI_INT(&id),
- SILC_STR_UI32_NSTRING(&hdata,
- &hdata_len),
- SILC_STR_UI_INT64(&offset),
- SILC_STR_UI32_NSTRING(&data,
- &data_len),
- SILC_STR_END);
- if (ret < 0)
- goto failure;
-
- /* Get the handle */
- handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
- (const unsigned char *)hdata,
- hdata_len);
- if (!handle) {
- silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
- break;
- }
-
- /* Write operation */
- server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset,
- (const unsigned char *)data, data_len,
- silc_sftp_server_status, SILC_32_TO_PTR(id));
-
- /* Call monitor */
- if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
- mdata.offset = offset;
- mdata.data_len = data_len;
- (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
- server->monitor_context);
- }
- }
- break;
-
case SILC_SFTP_INIT:
{
SilcSFTPVersion version;
}
break;
+ case SILC_SFTP_READ:
+ {
+ unsigned char *hdata;
+ SilcUInt32 hdata_len;
+ SilcUInt64 offset;
+ SilcUInt32 len;
+
+ SILC_LOG_DEBUG(("Read request"));
+
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&id),
+ SILC_STR_UI32_NSTRING(&hdata,
+ &hdata_len),
+ SILC_STR_UI_INT64(&offset),
+ SILC_STR_UI_INT(&len),
+ SILC_STR_END);
+ if (ret < 0)
+ goto failure;
+
+ /* Get the handle */
+ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
+ (const unsigned char *)hdata,
+ hdata_len);
+ if (!handle) {
+ silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
+ break;
+ }
+
+ /* Read operation */
+ server->fs->fs->sftp_read(server->fs->fs_context, sftp,
+ handle, offset, len,
+ silc_sftp_server_data, SILC_32_TO_PTR(id));
+
+ /* Call monitor */
+ if (server->monitors & SILC_SFTP_MONITOR_READ && server->monitor) {
+ mdata.offset = offset;
+ mdata.data_len = len;
+ (*server->monitor)(sftp, SILC_SFTP_MONITOR_READ, &mdata,
+ server->monitor_context);
+ }
+ }
+ break;
+
+ case SILC_SFTP_WRITE:
+ {
+ unsigned char *hdata;
+ SilcUInt32 hdata_len;
+ SilcUInt64 offset;
+ unsigned char *data;
+ SilcUInt32 data_len;
+
+ SILC_LOG_DEBUG(("Read request"));
+
+ ret = silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(&id),
+ SILC_STR_UI32_NSTRING(&hdata,
+ &hdata_len),
+ SILC_STR_UI_INT64(&offset),
+ SILC_STR_UI32_NSTRING(&data,
+ &data_len),
+ SILC_STR_END);
+ if (ret < 0)
+ goto failure;
+
+ /* Get the handle */
+ handle = server->fs->fs->sftp_get_handle(server->fs->fs_context, sftp,
+ (const unsigned char *)hdata,
+ hdata_len);
+ if (!handle) {
+ silc_sftp_send_error(server, SILC_SFTP_STATUS_NO_SUCH_FILE, id);
+ break;
+ }
+
+ /* Write operation */
+ server->fs->fs->sftp_write(server->fs->fs_context, sftp, handle, offset,
+ (const unsigned char *)data, data_len,
+ silc_sftp_server_status, SILC_32_TO_PTR(id));
+
+ /* Call monitor */
+ if (server->monitors & SILC_SFTP_MONITOR_WRITE && server->monitor) {
+ mdata.offset = offset;
+ mdata.data_len = data_len;
+ (*server->monitor)(sftp, SILC_SFTP_MONITOR_WRITE, &mdata,
+ server->monitor_context);
+ }
+ }
+ break;
+
case SILC_SFTP_REMOVE:
{
SILC_LOG_DEBUG(("Remove request"));
/* Setstat operation */
server->fs->fs->sftp_setstat(server->fs->fs_context, sftp, path, attrs,
- silc_sftp_server_status,
- SILC_32_TO_PTR(id));
+ silc_sftp_server_status, SILC_32_TO_PTR(id));
silc_sftp_attr_free(attrs);
silc_free(path);
/* Symlink operation */
server->fs->fs->sftp_symlink(server->fs->fs_context, sftp, path, target,
- silc_sftp_server_status,
- SILC_32_TO_PTR(id));
+ silc_sftp_server_status, SILC_32_TO_PTR(id));
silc_free(path);
silc_free(target);
data_len = 8 + strlen(request);
silc_buffer_pull(&buf, data_len);
ret = silc_buffer_unformat(&buf,
- SILC_STR_DATA(&data, silc_buffer_len(&buf)),
+ SILC_STR_UI_XNSTRING(&data, buf.len),
SILC_STR_END);
if (ret < 0)
goto failure;
- data_len = silc_buffer_len(&buf);
+ data_len = buf.len;
/* Call monitor */
if (server->monitors & SILC_SFTP_MONITOR_EXTENDED && server->monitor) {
/*
- sftp_util.c
+ sftp_util.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 - 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcsftp.h"
#include "sftp_util.h"
to that buffer instead of allocating new one. If the new data cannot
fit to `packet_buf' will be reallocated. */
-SilcBuffer silc_sftp_packet_encode(SilcSFTPPacket packet,
+SilcBuffer silc_sftp_packet_encode(SilcSFTPPacket packet,
SilcBuffer packet_buf, SilcUInt32 len, ...)
{
SilcBuffer buffer;
/* Same as silc_sftp_packet_encode but takes the variable argument list
pointer as argument. */
-SilcBuffer silc_sftp_packet_encode_vp(SilcSFTPPacket packet,
- SilcBuffer packet_buf, SilcUInt32 len,
+SilcBuffer silc_sftp_packet_encode_vp(SilcSFTPPacket packet,
+ SilcBuffer packet_buf, SilcUInt32 len,
va_list vp)
{
SilcBuffer buffer;
int ret;
if (packet_buf) {
- if (silc_buffer_truelen(packet_buf) < 4 + 1 + len) {
+ if (packet_buf->truelen < 4 + 1 + len) {
packet_buf = silc_buffer_realloc(packet_buf, 4 + 1 + len);
if (!packet_buf)
return NULL;
dyn = TRUE;
}
- silc_buffer_pull_tail(buffer, 4 + 1 + len);
- silc_buffer_format(buffer,
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+ silc_buffer_format(buffer,
SILC_STR_UI_INT(len),
SILC_STR_UI_CHAR(packet),
SILC_STR_END);
/* Decodes the SFTP packet data `packet' and return the SFTP packet type.
The payload of the packet is returned to the `payload' pointer. Returns
- 0 if error occurred during decoding and -1 if partial packet was
- received. */
+ 0 if error occurred during decoding. */
SilcSFTPPacket silc_sftp_packet_decode(SilcBuffer packet,
unsigned char **payload,
if (type < SILC_SFTP_INIT || type > SILC_SFTP_EXTENDED_REPLY)
return 0;
- if (len > (silc_buffer_len(packet) - 5))
- return -1;
+ if (len > (packet->len - 5))
+ return 0;
silc_buffer_pull(packet, 5);
- ret = silc_buffer_unformat(packet,
+ ret = silc_buffer_unformat(packet,
SILC_STR_UI_XNSTRING(payload, len),
SILC_STR_END);
if (ret < 0)
len += 4;
for (i = 0; i < attr->extended_count; i++) {
len += 8;
- len += silc_buffer_len(attr->extended_type[i]);
- len += silc_buffer_len(attr->extended_data[i]);
+ len += attr->extended_type[i]->len;
+ len += attr->extended_data[i]->len;
}
}
if (!buffer)
return NULL;
- silc_buffer_format(buffer,
- SILC_STR_UI_INT(attr->flags),
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT(attr->flags),
SILC_STR_END);
silc_buffer_pull(buffer, 4);
if (attr->flags & SILC_SFTP_ATTR_SIZE) {
- silc_buffer_format(buffer,
- SILC_STR_UI_INT64(attr->size),
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT64(attr->size),
SILC_STR_END);
silc_buffer_pull(buffer, 8);
}
if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
- silc_buffer_format(buffer,
- SILC_STR_UI_INT(attr->uid),
- SILC_STR_UI_INT(attr->gid),
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT(attr->uid),
+ SILC_STR_UI_INT(attr->gid),
SILC_STR_END);
silc_buffer_pull(buffer, 8);
}
if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
- silc_buffer_format(buffer,
- SILC_STR_UI_INT(attr->permissions),
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT(attr->permissions),
SILC_STR_END);
silc_buffer_pull(buffer, 4);
}
if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
- silc_buffer_format(buffer,
- SILC_STR_UI_INT(attr->atime),
- SILC_STR_UI_INT(attr->mtime),
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT(attr->atime),
+ SILC_STR_UI_INT(attr->mtime),
SILC_STR_END);
silc_buffer_pull(buffer, 8);
}
if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
- silc_buffer_format(buffer,
- SILC_STR_UI_INT(attr->extended_count),
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT(attr->extended_count),
SILC_STR_END);
silc_buffer_pull(buffer, 4);
for (i = 0; i < attr->extended_count; i++) {
- ret =
- silc_buffer_format(
- buffer,
- SILC_STR_UI_INT(silc_buffer_len(attr->extended_type[i])),
- SILC_STR_DATA(silc_buffer_data(attr->extended_type[i]),
- silc_buffer_len(attr->extended_type[i])),
- SILC_STR_UI_INT(silc_buffer_len(attr->extended_data[i])),
- SILC_STR_DATA(silc_buffer_data(attr->extended_data[i]),
- silc_buffer_len(attr->extended_data[i])),
- SILC_STR_END);
+ ret =
+ silc_buffer_format(buffer,
+ SILC_STR_UI_INT(attr->extended_type[i]->len),
+ SILC_STR_UI_XNSTRING(attr->extended_type[i]->data,
+ attr->extended_type[i]->len),
+ SILC_STR_UI_INT(attr->extended_data[i]->len),
+ SILC_STR_UI_XNSTRING(attr->extended_data[i]->data,
+ attr->extended_data[i]->len),
+ SILC_STR_END);
silc_buffer_pull(buffer, ret);
}
}
if (!attr)
return NULL;
- if (silc_buffer_unformat(buffer,
- SILC_STR_UI_INT(&attr->flags),
+ if (silc_buffer_unformat(buffer,
+ SILC_STR_UI_INT(&attr->flags),
SILC_STR_END) < 0)
goto out;
silc_buffer_pull(buffer, 4);
if (attr->flags & SILC_SFTP_ATTR_SIZE) {
- if (silc_buffer_unformat(buffer,
- SILC_STR_UI_INT64(&attr->size),
+ if (silc_buffer_unformat(buffer,
+ SILC_STR_UI_INT64(&attr->size),
SILC_STR_END) < 0)
goto out;
}
if (attr->flags & SILC_SFTP_ATTR_UIDGID) {
- if (silc_buffer_unformat(buffer,
- SILC_STR_UI_INT(&attr->uid),
- SILC_STR_UI_INT(&attr->gid),
+ if (silc_buffer_unformat(buffer,
+ SILC_STR_UI_INT(&attr->uid),
+ SILC_STR_UI_INT(&attr->gid),
SILC_STR_END) < 0)
goto out;
}
if (attr->flags & SILC_SFTP_ATTR_PERMISSIONS) {
- if (silc_buffer_unformat(buffer,
- SILC_STR_UI_INT(&attr->permissions),
+ if (silc_buffer_unformat(buffer,
+ SILC_STR_UI_INT(&attr->permissions),
SILC_STR_END) < 0)
goto out;
}
if (attr->flags & SILC_SFTP_ATTR_ACMODTIME) {
- if (silc_buffer_unformat(buffer,
- SILC_STR_UI_INT(&attr->atime),
- SILC_STR_UI_INT(&attr->mtime),
+ if (silc_buffer_unformat(buffer,
+ SILC_STR_UI_INT(&attr->atime),
+ SILC_STR_UI_INT(&attr->mtime),
SILC_STR_END) < 0)
goto out;
if (attr->flags & SILC_SFTP_ATTR_EXTENDED) {
int i;
- if (silc_buffer_unformat(buffer,
- SILC_STR_UI_INT(&attr->extended_count),
+ if (silc_buffer_unformat(buffer,
+ SILC_STR_UI_INT(&attr->extended_count),
SILC_STR_END) < 0)
goto out;
silc_buffer_pull(buffer, 4);
- attr->extended_type = silc_calloc(attr->extended_count,
+ attr->extended_type = silc_calloc(attr->extended_count,
sizeof(*attr->extended_type));
- attr->extended_data = silc_calloc(attr->extended_count,
+ attr->extended_data = silc_calloc(attr->extended_count,
sizeof(*attr->extended_data));
if (!attr->extended_type || !attr->extended_data)
return NULL;
unsigned char *tmp, *tmp2;
SilcUInt32 tmp_len, tmp2_len;
- if (silc_buffer_unformat(buffer,
+ if (silc_buffer_unformat(buffer,
SILC_STR_UI32_NSTRING(&tmp, &tmp_len),
SILC_STR_UI32_NSTRING(&tmp2, &tmp2_len),
SILC_STR_END) < 0)
{
name->filename = silc_realloc(name->filename, sizeof(*name->filename) *
(name->count + 1));
- name->long_filename = silc_realloc(name->long_filename,
+ name->long_filename = silc_realloc(name->long_filename,
sizeof(*name->long_filename) *
(name->count + 1));
name->attrs = silc_realloc(name->attrs, sizeof(*name->attrs) *
name->count++;
}
-/* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
+/* Encodes the SilcSFTPName to a buffer and returns the allocated buffer.
The caller must free the buffer. */
SilcBuffer silc_sftp_name_encode(SilcSFTPName name)
attr_buf[i] = silc_sftp_attr_encode(name->attrs[i]);
if (!attr_buf[i])
return NULL;
- len += silc_buffer_len(attr_buf[i]);
+ len += attr_buf[i]->len;
}
buffer = silc_buffer_alloc(len);
if (!buffer)
return NULL;
- silc_buffer_end(buffer);
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
silc_buffer_format(buffer,
SILC_STR_UI_INT(name->count),
SILC_STR_UI32_STRING(name->filename[i]),
SILC_STR_UI_INT(strlen(name->long_filename[i])),
SILC_STR_UI32_STRING(name->long_filename[i]),
- SILC_STR_DATA(silc_buffer_data(attr_buf[i]),
- silc_buffer_len(attr_buf[i])),
+ SILC_STR_UI_XNSTRING(attr_buf[i]->data,
+ attr_buf[i]->len),
SILC_STR_END);
silc_buffer_pull(buffer, len);
name->count = count;
for (i = 0; i < count; i++) {
- ret =
+ ret =
silc_buffer_unformat(buffer,
SILC_STR_UI32_STRING_ALLOC(&name->filename[i]),
SILC_STR_UI32_STRING_ALLOC(&name->long_filename[i]),
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 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
*
* DESCRIPTION
*
- * SILC SFTP Interface is the implementation of the Secure File Transfer
- * Protocol (or SSH File Transfer Protocol). The interface defines the SFTP
- * client and the SFTP server. The SFTP is the mandatory file transfer
- * protocol in the SILC protocol, and when used in SILC the SFTP packets are
- * encapsulated into SILC packets. The SFTP server implementation is
- * filesystem independent and generic interface is defined to represent
- * filesystem access.
+ * SILC SFTP Interface is the implementation of the Secure File Transfer
+ * Protocol. The interface defines the SFTP client and the SFTP server.
+ * The SFTP is the mandatory file transfer protocol in the SILC protocol.
+ * The SFTP server implementation is filesystem independent and generic
+ * interface is defined to represent filesystem access.
*
- * The SilcSFTP context is the actual SFTP client or SFTP server, and each
- * SFTP session should create its own SFTP context.
- *
- * The SILC SFTP library is a generic SFTP implementation and not directly
- * related to either SILC or SSH. It could be used for any general purpose
- * SFTP application.
+ * The SilcSFTP context is the actual SFTP client or SFTP server, and
+ * each SFTP session (associated to a socket connection) must create
+ * own SFTP context.
*
***/
*
* SFTP Version type.
*
- ***/
+ * SOURCE
+ */
typedef SilcUInt32 SilcSFTPVersion;
+/***/
/* SFTP protocol version */
#define SILC_SFTP_PROTOCOL_VERSION 3
SILC_SFTP_STATUS_PERMISSION_DENIED = 3, /* No sufficient permissions */
SILC_SFTP_STATUS_FAILURE = 4, /* Operation failed */
SILC_SFTP_STATUS_BAD_MESSAGE = 5, /* Bad message received */
- SILC_SFTP_STATUS_NO_CONNECTION = 6, /* No connection to remote */
+ SILC_SFTP_STATUS_NO_CONNECTION = 6, /* No connection to server */
SILC_SFTP_STATUS_CONNECTION_LOST = 7, /* Connection lost to server */
SILC_SFTP_STATUS_OP_UNSUPPORTED = 8, /* Operation unsupported */
SILC_SFTP_STATUS_INVALID_HANDLE = 9, /* Invalid file handle */
***/
typedef struct SilcSFTPHandleStruct *SilcSFTPHandle;
+/****f* silcsftp/SilcSFTPAPI/SilcSFTPSendPacketCallback
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcSFTPSendPacketCallback)(SilcBuffer packet,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Packet sending callback. The caller of this interface will provide this
+ * function for the library. The libary will call this function everytime
+ * it needs to send a packet to the remote host.
+ *
+ ***/
+typedef void (*SilcSFTPSendPacketCallback)(SilcBuffer packet, void *context);
+
/****f* silcsftp/SilcSFTPAPI/SilcSFTPVersionCallback
*
* SYNOPSIS
SilcSFTPVersion version,
void *context);
-/****f* silcsftp/SilcSFTPAPI/SilcSFTPErrorCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcSFTPErrorCallback)(SilcSFTP sftp,
- * SilcSFTPStatus status,
- * void *context);
- *
- * DESCRIPTION
- *
- * Error callback is called if a connection error occurs during SFTP
- * session. If the connection or stream is closed this callback is
- * called. Other errors are delivered in other callbacks. Only the
- * SILC_SFTP_STATUS_EOF or SILC_SFTP_STATUS_NO_CONNECTION is delivered
- * in this callback.
- *
- ***/
-typedef void (*SilcSFTPErrorCallback)(SilcSFTP sftp,
- SilcSFTPStatus status,
- void *context);
-
/****f* silcsftp/SilcSFTPAPI/SilcSFTPStatusCallback
*
* SYNOPSIS
*
* SYNOPSIS
*
- * SilcSFTP silc_sftp_client_start(SilcStream stream,
- * SilcSchedule schedule,
- * SilcSFTPVersionCallback version_cb,
- * SilcSFTPErrorCallback error_cb,
+ * SilcSFTP silc_sftp_client_start(SilcSFTPSendPacketCallback send_packet,
+ * void *send_context,
+ * SilcSFTPVersionCallback callback,
* void *context);
*
* DESCRIPTION
*
* Starts SFTP client and returns context to it. The version callback
- * indicated by the `version_cb' will be called after the SFTP session has
+ * indicated by the `callback' will be called after the SFTP session has
* been started and server has returned the version of the protocol. The
* SFTP client context is returned in the callback too. This returns the
- * allocated SFTP client context or NULL on error. The `stream' will be
- * used to read and write the SFTP packets. The `error_cb' will be called
- * in case a stream error occurs, such as end of stream.
+ * allocated SFTP client context or NULL on error. Each socket connection
+ * should allocate their own SFTP client by calling this function.
*
***/
-SilcSFTP silc_sftp_client_start(SilcStream stream,
- SilcSchedule schedule,
- SilcSFTPVersionCallback version_cb,
- SilcSFTPErrorCallback error_cb,
+SilcSFTP silc_sftp_client_start(SilcSFTPSendPacketCallback send_packet,
+ void *send_context,
+ SilcSFTPVersionCallback callback,
void *context);
/****f* silcsftp/SilcSFTPAPI/silc_sftp_client_shutdown
* DESCRIPTION
*
* Shutdown's the SFTP client. The caller is responsible of closing
- * the associated stream. The SFTP context is freed and is invalid after
- * this function returns.
+ * the associated socket connection. The SFTP context is freed and is
+ * invalid after this function returns.
*
***/
void silc_sftp_client_shutdown(SilcSFTP sftp);
+/* Function that is called to process the incmoing SFTP packet. */
+/* XXX Some day this will go away and we have automatic receive callbacks
+ for SilcSocketConnection API or SilcPacketContext API. */
+void silc_sftp_client_receive_process(SilcSFTP sftp,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+
/****f* silcsftp/SilcSFTPAPI/silc_sftp_open
*
* SYNOPSIS
*
* SYNOPSIS
*
- * SilcSFTP silc_sftp_server_start(SilcStream stream,
- * SilcSchedule schedule,
- * SilcSFTPErrorCallback error_cb,
- * void *context,
+ * SilcSFTP silc_sftp_server_start(SilcSFTPSendPacketCallback send_packet,
+ * void *send_context,
* SilcSFTPFilesystem fs);
*
* DESCRIPTION
*
* Starts SFTP server and returns a context to it. This function returns
- * the allocated SFTP server context or NULL on error. The `stream' is
- * the stream (connection) to the client. The `error_cb' will be called
- * when the `stream' is ended (SILC_SFTP_STATUS_EOF). The caller is
- * responsible of closing and destroying the `stream'. The `fs' is the
- * filesystem context allocated by the application.
+ * the allocated SFTP server context or NULL on error. The `send_packet'
+ * is called by the library when it needs to send a packet. The `fs' is the
+ * filesystem context allocated by the application. Each socket connection
+ * should start its own server by calling this function.
*
***/
-SilcSFTP silc_sftp_server_start(SilcStream stream,
- SilcSchedule schedule,
- SilcSFTPErrorCallback error_cb,
- void *context,
+SilcSFTP silc_sftp_server_start(SilcSFTPSendPacketCallback send_packet,
+ void *send_context,
SilcSFTPFilesystem fs);
/****f* silcsftp/SilcSFTPAPI/silc_sftp_server_shutdown
*
* DESCRIPTION
*
- * Shutdown the SFTP server. The caller is responsible of closing the
- * associated stream. The SFTP context is freed and is invalid after
- * this function returns.
+ * Shutdown's the SFTP server. The caller is responsible of closing
+ * the associated socket connection. The SFTP context is freed and is
+ * invalid after this function returns.
*
***/
void silc_sftp_server_shutdown(SilcSFTP sftp);
*
* This structure includes the monitor type specific data. The
* application can check what the client has requested from this
- * structure. See the comments below what data is available for what
- * monitor type.
+ * structure.
*
* SOURCE
*/
SilcSFTPMonitor monitor,
void *context);
+/* Function that is called to process the incmoing SFTP packet. */
+/* XXX Some day this will go away and we have automatic receive callbacks
+ for SilcSocketConnection API or SilcPacketContext API. */
+void silc_sftp_server_receive_process(SilcSFTP sftp,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+
#endif /* SILCSFTP_H */
/*
- silcsftp_fs.h
+ silcsftp_fs.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 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 directories cannot be removed from remote access using the
* filesystem access function sftp_rmdir. This is because the filesystem
- * is one-user filesystem and differentiating between users is not
+ * is one-user filesystem and differentiating between users is not
* possible. Thus, it would allow anyone to remove directories and
* their contents. Removing directories is possible only locally using
* the silc_sftp_fs_memory_del_dir function. The same thing is with
* the silc_sftp_fs_memory_del_file function. Also, files can not ever
* be executed from remote access.
*
- * Also some of the file operation flags are not supported, such as
+ * Also some of the file operation flags are not supported, such as
* SILC_SFTP_FXF_CREAT, SILC_SFTP_FXF_TRUNC and SILC_SFTP_FXF_EXCL
* since they would require access to a real filesystem file which does
* not exist yet, or would mean destroying the file. However, the
/****s* silcsftp/SilcSFTPFSAPI/SilcSFTPFilesystemOps
*
* NAME
- *
- * typedef struct SilcSFTPFilesystemOpsStruct { ... }
+ *
+ * typedef struct SilcSFTPFilesystemOpsStruct { ... }
* *SilcSFTPFilesystemOps;
*
* DESCRIPTION
* SOURCE
*/
typedef struct SilcSFTPFilesystemOpsStruct {
- /* Find a file handle by the file handle data indicated by the `data'.
+ /* Find a file handle by the file handle data indicated by the `data'.
If the handle is not found this returns NULL. */
SilcSFTPHandle (*sftp_get_handle)(void *context, SilcSFTP sftp,
const unsigned char *data,
/* Open a file indicated by the `filename' with flags indicated by the
`pflags', and with attributes indicated by the `attr'. Calls the
`callback' to return the opened file handle. */
- void (*sftp_open)(void *context, SilcSFTP sftp,
- const char *filename,
+ void (*sftp_open)(void *context, SilcSFTP sftp,
+ const char *filename,
SilcSFTPFileOperation pflags,
SilcSFTPAttributes attr,
SilcSFTPHandleCallback callback,
/* Closes the file indicated by the file handle `handle'. Calls the
`callback' to indicate the status of the closing. */
- void (*sftp_close)(void *context, SilcSFTP sftp,
+ void (*sftp_close)(void *context, SilcSFTP sftp,
SilcSFTPHandle handle,
SilcSFTPStatusCallback callback,
void *callback_context);
from the offset of `offset' at most `len' bytes. The `callback' is
called to return the read data. */
void (*sftp_read)(void *context, SilcSFTP sftp,
- SilcSFTPHandle handle,
- SilcUInt64 offset,
+ SilcSFTPHandle handle,
+ SilcUInt64 offset,
SilcUInt32 len,
SilcSFTPDataCallback callback,
void *callback_context);
/* Writes to a file indicated by the file handle `handle' starting from
- offset of `offset' at most `data_len' bytes of `data'. The `callback'
+ offset of `offset' at most `data_len' bytes of `data'. The `callback'
is called to indicate the status of the writing. */
void (*sftp_write)(void *context, SilcSFTP sftp,
SilcSFTPHandle handle,
SilcSFTPHandle handle,
SilcSFTPAttrCallback callback,
void *callback_context);
-
+
/* Sets a file attributes to a file indicated by the `path' with the
attributes indicated by the `attrs'. Calls the `callback' to indicate
the status of the setting. */
SilcSFTPNameCallback callback,
void *callback_context);
- /* Performs an extended operation indicated by the `request' with
+ /* Performs an extended operation indicated by the `request' with
optional extended operation data indicated by the `data'. The callback
is called to return any data associated with the extended request. */
void (*sftp_extended)(void *context, SilcSFTP sftp,
/****s* silcsftp/SilcSFTPFSAPI/SilcSFTPFilesystem
*
* NAME
- *
+ *
* typedef struct { ... } *SilcSFTPFilesystem;
*
* DESCRIPTION
/****d* silcsftp/SilcSFTPFSAPI/SilcSFTPFSMemoryPerm
*
* NAME
- *
+ *
* typedef enum { ... } SilcSFTPFSMemoryPerm;
*
* DESCRIPTION
* or new subdirectories under the directory. The `dir' is the parent
* directory of the directory to be added. If this directory is to be
* added to the root directory the `dir' is NULL. The `name' is the name
- * of the directory. If error occurs this returns NULL. The `perm' will
+ * of the directory. If error occurs this returns NULL. The `perm' will
* indicate the permissions for the directory and they work in POSIX
- * style.
+ * style.
*
***/
void *silc_sftp_fs_memory_add_dir(SilcSFTPFilesystem fs, void *dir,
*
* SYNOPSIS
*
- * SilcBool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir);
+ * bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir);
*
* DESCRIPTION
*
* access function sftp_rmdir.
*
***/
-SilcBool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir);
+bool silc_sftp_fs_memory_del_dir(SilcSFTPFilesystem fs, void *dir);
/****f* silcsftp/SilcSFTPFSAPI/silc_sftp_fs_memory_add_file
*
* SYNOPSIS
*
- * SilcBool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
- * SilcSFTPFSMemoryPerm perm,
- * const char *filename,
- * const char *realpath);
+ * bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
+ * SilcSFTPFSMemoryPerm perm,
+ * const char *filename,
+ * const char *realpath);
*
* DESCRIPTION
*
* was added to the directory.
*
***/
-SilcBool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
- SilcSFTPFSMemoryPerm perm,
- const char *filename,
- const char *realpath);
+bool silc_sftp_fs_memory_add_file(SilcSFTPFilesystem fs, void *dir,
+ SilcSFTPFSMemoryPerm perm,
+ const char *filename,
+ const char *realpath);
/****f* silcsftp/SilcSFTPFSAPI/silc_sftp_fs_memory_del_file
*
* SYNOPSIS
*
- * SilcBool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
- * const char *filename);
+ * bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
+ * const char *filename);
*
* DESCRIPTION
*
* access function sftp_remove.
*
***/
-SilcBool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
- const char *filename);
+bool silc_sftp_fs_memory_del_file(SilcSFTPFilesystem fs, void *dir,
+ const char *filename);
#endif /* SILCSFTP_FS_H */
AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
-bin_PROGRAMS = sftp_client sftp_server
+bin_PROGRAMS = sftp_server sftp_client
sftp_server_SOURCES = sftp_server.c
sftp_client_SOURCES = sftp_client.c
/*
- sftp_client.c
+ sftp_client.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 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
*/
-/* Tests:
- silc_sftp_client_start();
- silc_sftp_client_receive_process();
- silc_sftp_opendir();
- silc_sftp_readdir();
- silc_sftp_open();
- silc_sftp_read();
- silc_sftp_fstat();
- silc_sftp_lstat();
- silc_sftp_close();
-*/
-
-#include "silc.h"
+#include "silcincludes.h"
#include "silcsftp.h"
typedef struct {
SilcSchedule schedule;
- SilcStream stream;
+ SilcSocketConnection sock;
SilcSFTP sftp;
} *Client;
void *context);
static void end_test(void);
-static void sftp_status(SilcSFTP sftp, SilcSFTPStatus status,
- const char *message, const char *lang_tag,
- void *context)
+static void send_packet(SilcBuffer packet, void *context)
{
- fprintf(stderr, "Status %d\n", status);
- if (status != SILC_SFTP_STATUS_OK) {
- SILC_LOG_DEBUG(("Error status"));
- success = FALSE;
- end_test();
+ Client client = (Client)context;
+ SilcSocketConnection sock = client->sock;
+ SilcPacketContext packetdata;
+ const SilcBufferStruct p;
+ int ret;
+
+ memset(&packetdata, 0, sizeof(packetdata));
+ packetdata.type = SILC_PACKET_FTP;
+ packetdata.truelen = packet->len + SILC_PACKET_HEADER_LEN;
+ SILC_PACKET_PADLEN(packetdata.truelen, 0, packetdata.padlen);
+ silc_packet_assemble(&packetdata, NULL, NULL, NULL, sock,
+ packet->data, packet->len, (const SilcBuffer)&p);
+ ret = silc_packet_send(sock, TRUE);
+ if (ret != -2)
return;
- }
+
+ silc_schedule_set_listen_fd(client->schedule, sock->sock,
+ (SILC_TASK_READ | SILC_TASK_WRITE), FALSE);
+ SILC_SET_OUTBUF_PENDING(sock);
+}
- success = TRUE;
- end_test();
+static bool packet_parse(SilcPacketParserContext *parser, void *context)
+{
+ Client client = (Client)parser->context;
+ SilcSocketConnection sock = parser->sock;
+ SilcPacketContext *packet = parser->packet;
+ int ret;
+
+ ret = silc_packet_parse(packet, NULL);
+ assert(packet->type == SILC_PACKET_FTP);
+
+ silc_sftp_client_receive_process(client->sftp, sock, packet);
+
+ return TRUE;
}
-static void sftp_attr(SilcSFTP sftp, SilcSFTPStatus status,
- const SilcSFTPAttributes attrs, void *context)
+SILC_TASK_CALLBACK(packet_process)
{
- SilcSFTPHandle handle = (SilcSFTPHandle)context;
- int i;
+ Client client = (Client)context;
+ SilcSocketConnection sock = client->sock;
+ int ret;
- fprintf(stderr, "Status %d\n", status);
- if (status != SILC_SFTP_STATUS_OK) {
- SILC_LOG_DEBUG(("Error status"));
- success = FALSE;
- end_test();
+ if (type == SILC_TASK_WRITE) {
+ if (sock->outbuf->data - sock->outbuf->head)
+ silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
+
+ ret = silc_packet_send(sock, TRUE);
+ if (ret < 0)
+ return;
+
+ silc_schedule_set_listen_fd(client->schedule, fd, SILC_TASK_READ, FALSE);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
return;
+
}
+ if (type == SILC_TASK_READ) {
+ ret = silc_packet_receive(sock);
+ if (ret < 0)
+ return;
+
+ if (ret == 0) {
+ silc_net_close_connection(sock->sock);
+ silc_socket_free(sock);
+ exit(0);
+ }
- SILC_LOG_DEBUG(("Attr.flags: %d", attrs->flags));
- SILC_LOG_DEBUG(("Attr.size: %lu", attrs->size));
- SILC_LOG_DEBUG(("Attr.uid: %d", attrs->uid));
- SILC_LOG_DEBUG(("Attr.gid: %d", attrs->gid));
- SILC_LOG_DEBUG(("Attr.permissions: %d", attrs->permissions));
- SILC_LOG_DEBUG(("Attr.atime: %d", attrs->atime));
- SILC_LOG_DEBUG(("Attr.mtime: %d", attrs->mtime));
- SILC_LOG_DEBUG(("Attr.extended count: %d", attrs->extended_count));
- for (i = 0; i < attrs->extended_count; i++) {
- SILC_LOG_HEXDUMP(("Attr.extended_type[i]:", i),
- attrs->extended_type[i]->data,
- silc_buffer_len(attrs->extended_type[i]));
- SILC_LOG_HEXDUMP(("Attr.extended_data[i]:", i),
- attrs->extended_data[i]->data,
- silc_buffer_len(attrs->extended_data[i]));
- }
-
- if (!file) {
- fprintf(stderr, "Closing file\n");
- silc_sftp_close(sftp, handle, sftp_status, context);
- return;
+ silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
+ packet_parse, client);
}
-
- fprintf(stderr, "LStatting file %s\n", file);
- silc_sftp_lstat(sftp, file, sftp_attr, context);
- file = NULL;
}
static void sftp_data(SilcSFTP sftp, SilcSFTPStatus status,
void *context)
{
SilcSFTPHandle handle = (SilcSFTPHandle)context;
+ int debug = silc_debug;
if (status != SILC_SFTP_STATUS_OK) {
SilcSFTPAttributesStruct attrs;
end_test();
return;
}
-
+
if (!strcmp(file, "/sftp/sftp_server.c")) {
- fprintf(stderr, "FStatting file handle %s\n", file);
- silc_sftp_fstat(sftp, handle, sftp_attr, context);
+ success = TRUE;
+ end_test();
return;
}
-
+
/* Open another file */
opendir = FALSE;
memset(&attrs, 0, sizeof(attrs));
return;
}
+ if (!debug)
+ silc_debug = 1;
SILC_LOG_HEXDUMP(("data"), (unsigned char *)data, data_len);
+ silc_debug = debug;
offset += data_len;
end_test();
return;
}
-
+
fprintf(stderr, "Directory: %s\n", dir);
for (i = 0; i < name->count; i++) {
fprintf(stderr, "%s\n", name->long_filename[i]);
end_test();
return;
}
-
+
if (opendir) {
fprintf(stderr, "Reading %s\n", dir);
/* Readdir */
silc_sftp_opendir(sftp, dir, sftp_handle, client);
}
-static void sftp_error(SilcSFTP sftp, SilcSFTPStatus status,
- void *context)
-{
- Client client = context;
- SILC_LOG_DEBUG(("Error %d", status));
- silc_stream_destroy(client->stream);
- success = FALSE;
- end_test();
-}
-
-static void connect_callback(SilcNetStatus status, SilcStream stream,
- void *context)
-{
- Client client = context;
-
- if (!stream) {
- SILC_LOG_DEBUG(("Connect error"));
- success = FALSE;
- end_test();
- }
-
- /* Start SFTP session */
- client->stream = stream;
- client->sftp = silc_sftp_client_start(stream, client->schedule, sftp_version,
- sftp_error, client);
- if (!client->sftp) {
- success = FALSE;
- end_test();
- }
-}
-
int main(int argc, char **argv)
{
Client client = silc_calloc(1, sizeof(*client));
+ int sock;
gclient = client;
- if (argc > 1) {
- if (!strcmp(argv[1], "-d"))
- silc_log_debug(TRUE);
- if (argc > 2 && !strcmp(argv[2], "-x"))
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*");
+ if (argc > 1 && !strcmp(argv[1], "-d")) {
+ silc_debug = 1;
+ silc_debug_hexdump = 1;
+ silc_log_set_debug_string("*sftp*");
}
- client->schedule = silc_schedule_init(0, NULL);
+ client->schedule = silc_schedule_init(100, NULL);
if (!client->schedule)
return -1;
/* Connecto to server */
- silc_net_tcp_connect(NULL, "127.0.0.1", 5000, client->schedule,
- connect_callback, client);
+ sock = silc_net_create_connection(NULL, 5000, "127.0.0.1");
+ if (sock < 0)
+ return -1;
+ silc_socket_alloc(sock, 0, NULL, &client->sock);
+ silc_schedule_task_add(client->schedule, sock,
+ packet_process, client, 0, 0,
+ SILC_TASK_GENERIC, SILC_TASK_PRI_NORMAL);
+
+ /* Start SFTP session */
+ client->sftp = silc_sftp_client_start(send_packet, client,
+ sftp_version, client);
silc_schedule(client->schedule);
return 0;
/*
- sprp_server.c
+ sprp_server.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 Pekka Riikonen
+ Copyright (C) 2001 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
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "silcsftp.h"
-typedef struct ServerSessionStruct {
- SilcStream stream;
- SilcSFTP sftp;
+typedef struct {
+ SilcSocketConnection sock;
+ void *server;
} *ServerSession;
typedef struct {
SilcSchedule schedule;
- SilcNetListener listener;
+ int sock;
SilcSFTPFilesystem fs;
+ ServerSession sessions[100];
+ SilcSFTP sftp[100];
} *Server;
-static void error_cb(SilcSFTP sftp, SilcSFTPStatus status, void *context)
+static void send_packet(SilcBuffer packet, void *context)
{
ServerSession session = context;
+ Server server = session->server;
+ SilcPacketContext packetdata;
+ const SilcBufferStruct p;
+ int ret;
+
+ memset(&packetdata, 0, sizeof(packetdata));
+ packetdata.type = SILC_PACKET_FTP;
+ packetdata.truelen = packet->len + SILC_PACKET_HEADER_LEN;
+ SILC_PACKET_PADLEN(packetdata.truelen, 0, packetdata.padlen);
+ silc_packet_assemble(&packetdata, NULL, NULL, NULL, session->sock,
+ packet->data, packet->len, (const SilcBuffer)&p);
+ ret = silc_packet_send(session->sock, TRUE);
+ if (ret != -2)
+ return;
- if (status == SILC_SFTP_STATUS_EOF) {
- SILC_LOG_DEBUG(("Eof"));
- silc_stream_destroy(session->stream);
- silc_free(session);
- }
+ silc_schedule_set_listen_fd(server->schedule, session->sock->sock,
+ (SILC_TASK_READ | SILC_TASK_WRITE), FALSE);
+ SILC_SET_OUTBUF_PENDING(session->sock);
+}
- SILC_LOG_DEBUG(("Error %d", status));
+static bool packet_parse(SilcPacketParserContext *parser, void *context)
+{
+ Server server = (Server)parser->context;
+ SilcSocketConnection sock = parser->sock;
+ SilcPacketContext *packet = parser->packet;
+ int ret;
+
+ ret = silc_packet_parse(packet, NULL);
+ assert(packet->type == SILC_PACKET_FTP);
+
+ silc_sftp_server_receive_process(server->sftp[sock->sock], sock, packet);
+
+ return TRUE;
}
-static void net_callback(SilcNetStatus status, SilcStream stream,
- void *context)
+SILC_TASK_CALLBACK(packet_process)
{
Server server = context;
- ServerSession session;
+ ServerSession session = server->sessions[fd];
+ SilcSocketConnection sock;
+ int ret;
- SILC_LOG_DEBUG(("New connection"));
-
- session = silc_calloc(1, sizeof(*session));
if (!session)
return;
- session->stream = stream;
- session->sftp = silc_sftp_server_start(stream, server->schedule, error_cb,
- session, server->fs);
+ sock = session->sock;
+
+ if (type == SILC_TASK_WRITE) {
+ if (sock->outbuf->data - sock->outbuf->head)
+ silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
+
+ ret = silc_packet_send(sock, TRUE);
+ if (ret < 0)
+ return;
+
+ silc_schedule_set_listen_fd(server->schedule, fd, SILC_TASK_READ, FALSE);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
+ return;
+ }
+ if (type == SILC_TASK_READ) {
+ ret = silc_packet_receive(sock);
+ if (ret < 0)
+ return;
+
+ if (ret == 0) {
+ silc_net_close_connection(sock->sock);
+ silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+ silc_free(server->sessions[sock->sock]);
+ server->sessions[sock->sock] = NULL;
+ silc_socket_free(sock);
+ return;
+ }
+
+ silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, packet_parse,
+ server);
+ }
+}
+
+SILC_TASK_CALLBACK(accept_connection)
+{
+ Server server = (Server)context;
+ SilcSocketConnection sc;
+ int sock;
+
+ sock = silc_net_accept_connection(server->sock);
+ if (sock < 0)
+ exit(1);
+
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ silc_socket_alloc(sock, 0, NULL, &sc);
+ server->sessions[sock] = silc_calloc(1, sizeof(server->sessions[0]));
+ server->sessions[sock]->sock = sc;
+ server->sessions[sock]->server = server;
+ server->sftp[sock] =
+ silc_sftp_server_start(send_packet, server->sessions[sock],
+ server->fs);
+ silc_schedule_task_add(server->schedule, sock, packet_process,
+ server, 0, 0, SILC_TASK_GENERIC,
+ SILC_TASK_PRI_NORMAL);
}
int main()
{
Server server = silc_calloc(1, sizeof(*server));
void *dir;
- const char *ip = "127.0.0.1";
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
+ silc_debug = 1;
+ silc_debug_hexdump = 1;
silc_log_set_debug_string("*sftp*");
-
- server->schedule = silc_schedule_init(0, NULL);
+
+ server->schedule = silc_schedule_init(100, NULL);
if (!server->schedule)
return -1;
- server->listener = silc_net_tcp_create_listener(&ip, 1, 5000, FALSE,
- FALSE, server->schedule,
- net_callback, server);
- if (!server->listener)
+ server->sock = silc_net_create_server(5000, NULL);
+ if (server->sock < 0)
return -1;
/* Make test filesystem hierarchy */
silc_sftp_fs_memory_add_file(server->fs, NULL, SILC_SFTP_FS_PERM_EXEC,
"testi", "file://sftp_client.c");
+ silc_schedule_task_add(server->schedule, server->sock,
+ accept_connection, server, 0, 0,
+ SILC_TASK_FD, SILC_TASK_PRI_NORMAL);
silc_schedule(server->schedule);
return 0;
*/
-#include "silc.h"
+#include "silcincludes.h"
/*
SILC Module (SIM) Context.
*/
-#include "silc.h"
+#include "silcincludes.h"
#ifdef SILC_SIM /* SIM support enabled */
@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>
<br /><br />
@LINKS@
+
libsilcske_la_SOURCES = \
silcske.c \
payload.c \
- groups.c \
- silcconnauth.c
+ groups.c
#ifdef SILC_DIST_TOOLKIT
include_HEADERS = \
silcske_groups.h \
silcske_payload.h \
- silcske.h \
- silcske_i.h \
- silcconnauth.h
+ silcske_status.h \
+ silcske.h
#endif SILC_DIST_TOOLKIT
EXTRA_DIST = *.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2006 Pekka Riikonen
+ Copyright (C) 2000 - 2001 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "groups_internal.h"
/* Fixed and public Diffie Hellman Groups defined by the SKE
protocol. These are equivalent to the OAKLEY Key Determination
protocol groups (taken from RFC 2412). */
-const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[] =
+const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[] =
{
/* 1024 bits modulus (Mandatory group) */
{ 1, "diffie-hellman-group1",
silc_mp_set_str(&group->group, silc_ske_groups[i].group, 16);
silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 16);
silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 16);
-
+
*ret = group;
}
silc_mp_set_str(&group->group, silc_ske_groups[i].group, 16);
silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 16);
silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 16);
-
+
*ret = group;
}
len += strlen(silc_ske_groups[i].name);
list = silc_realloc(list, len + 1);
- memcpy(list + (len - strlen(silc_ske_groups[i].name)),
+ memcpy(list + (len - strlen(silc_ske_groups[i].name)),
silc_ske_groups[i].name, strlen(silc_ske_groups[i].name));
memcpy(list + len, ",", 1);
len++;
/*
- payload.c
+ payload.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2005 Pekka Riikonen
+ 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
*/
/* $Id$ */
-#include "silc.h"
-#include "silcske_i.h"
+#include "silcincludes.h"
/* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
to the other end. */
SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
- SilcSKEStartPayload payload,
+ SilcSKEStartPayload *payload,
SilcBuffer *return_buffer)
{
SilcBuffer buf;
SILC_STR_UI_CHAR(0), /* RESERVED field */
SILC_STR_UI_CHAR(payload->flags),
SILC_STR_UI_SHORT(payload->len),
- SILC_STR_UI_XNSTRING(payload->cookie,
+ SILC_STR_UI_XNSTRING(payload->cookie,
payload->cookie_len),
SILC_STR_UI_SHORT(payload->version_len),
- SILC_STR_UI_XNSTRING(payload->version,
+ SILC_STR_UI_XNSTRING(payload->version,
payload->version_len),
SILC_STR_UI_SHORT(payload->ke_grp_len),
SILC_STR_UI_XNSTRING(payload->ke_grp_list,
/* Return the encoded buffer */
*return_buffer = buf;
- SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, silc_buffer_len(buf));
+ SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len);
return SILC_SKE_STATUS_OK;
}
/* Parses the Key Exchange Start Payload. Parsed data is returned
to allocated payload structure. */
-SilcSKEStatus
+SilcSKEStatus
silc_ske_payload_start_decode(SilcSKE ske,
SilcBuffer buffer,
- SilcSKEStartPayload *return_payload)
+ SilcSKEStartPayload **return_payload)
{
- SilcSKEStartPayload payload;
+ SilcSKEStartPayload *payload;
SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
unsigned char tmp;
int ret;
SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
- SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data,
- silc_buffer_len(buffer));
+ SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len);
payload = silc_calloc(1, sizeof(*payload));
if (!payload)
payload->cookie_len = SILC_SKE_COOKIE_LEN;
/* Parse start of the payload */
- ret =
+ ret =
silc_buffer_unformat(buffer,
SILC_STR_UI_CHAR(&tmp), /* RESERVED Field */
SILC_STR_UI_CHAR(&payload->flags),
SILC_STR_UI_SHORT(&payload->len),
- SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie,
+ SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie,
payload->cookie_len),
SILC_STR_UI16_NSTRING_ALLOC(&payload->version,
&payload->version_len),
goto err;
}
- if (payload->len != silc_buffer_len(buffer)) {
+ if (payload->len != buffer->len) {
SILC_LOG_ERROR(("Garbage after KE Start Payload"));
status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
goto err;
/* Free's Start Payload */
-void silc_ske_payload_start_free(SilcSKEStartPayload payload)
+void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
{
if (payload) {
silc_free(payload->cookie);
end. */
SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
- SilcSKEKEPayload payload,
+ SilcSKEKEPayload *payload,
SilcBuffer *return_buffer)
{
SilcBuffer buf;
if (!payload)
return SILC_SKE_STATUS_ERROR;
- if (ske->start_payload &&
+ if (ske->start_payload &&
ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL &&
!payload->sign_data) {
SILC_LOG_DEBUG(("Signature data is missing"));
/* Allocate channel payload buffer. The length of the buffer
is 4 + public key + 2 + x + 2 + signature. */
- buf = silc_buffer_alloc_size(4 + payload->pk_len + 2 + x_len +
+ buf = silc_buffer_alloc_size(4 + payload->pk_len + 2 + x_len +
2 + payload->sign_len);
if (!buf)
return SILC_SKE_STATUS_OUT_OF_MEMORY;
/* Encode the payload */
- ret = silc_buffer_format(buf,
+ ret = silc_buffer_format(buf,
SILC_STR_UI_SHORT(payload->pk_len),
SILC_STR_UI_SHORT(payload->pk_type),
- SILC_STR_UI_XNSTRING(payload->pk_data,
+ SILC_STR_UI_XNSTRING(payload->pk_data,
payload->pk_len),
SILC_STR_UI_SHORT(x_len),
SILC_STR_UI_XNSTRING(x_str, x_len),
SILC_STR_UI_SHORT(payload->sign_len),
- SILC_STR_UI_XNSTRING(payload->sign_data,
+ SILC_STR_UI_XNSTRING(payload->sign_data,
payload->sign_len),
SILC_STR_END);
if (ret == -1) {
/* Return encoded buffer */
*return_buffer = buf;
- SILC_LOG_HEXDUMP(("KE Payload"), buf->data, silc_buffer_len(buf));
+ SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len);
memset(x_str, 'F', x_len);
silc_free(x_str);
SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
SilcBuffer buffer,
- SilcSKEKEPayload *return_payload)
+ SilcSKEKEPayload **return_payload)
{
SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
- SilcSKEKEPayload payload;
+ SilcSKEKEPayload *payload;
unsigned char *x = NULL;
SilcUInt16 x_len;
SilcUInt32 tot_len = 0, len2;
SILC_LOG_DEBUG(("Decoding Key Exchange Payload"));
- SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, silc_buffer_len(buffer));
+ SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len);
payload = silc_calloc(1, sizeof(*payload));
if (!payload)
return SILC_SKE_STATUS_OUT_OF_MEMORY;
- len2 = silc_buffer_len(buffer);
+ len2 = buffer->len;
/* Parse start of the payload */
ret = silc_buffer_unformat(buffer,
}
if (ske->start_payload &&
- ((payload->pk_type < SILC_SKE_PK_TYPE_SILC ||
+ ((payload->pk_type < SILC_SKE_PK_TYPE_SILC ||
payload->pk_type > SILC_SKE_PK_TYPE_SPKI) || !payload->pk_len)) {
SILC_LOG_ERROR(("Malformed public key in KE payload"));
status = SILC_SKE_STATUS_BAD_PAYLOAD;
SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
payload->pk_len),
SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len),
- SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data,
+ SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data,
&payload->sign_len),
SILC_STR_END);
if (ret == -1) {
goto err;
}
- if (ske->start_payload &&
+ if (ske->start_payload &&
(ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) &&
(payload->sign_len < 3 || !payload->sign_data)) {
SILC_LOG_ERROR(("The signature data is missing - both parties are "
status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
goto err;
}
-
+
/* Decode the binary data to integer */
silc_mp_init(&payload->x);
silc_mp_bin2mp(x, x_len, &payload->x);
/* Free's KE Payload */
-void silc_ske_payload_ke_free(SilcSKEKEPayload payload)
+void silc_ske_payload_ke_free(SilcSKEKEPayload *payload)
{
if (payload) {
silc_free(payload->pk_data);
+++ /dev/null
-/*
-
- silcconnauth.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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 "silcconnauth.h"
-
-/************************** Types and definitions ***************************/
-
-static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *app_context);
-
-/* Connection authentication context */
-struct SilcConnAuthStruct {
- SilcSKE ske;
- SilcFSM fsm;
- SilcAsyncOperationStruct op;
- SilcConnectionType conn_type;
- SilcAuthMethod auth_method;
- void *auth_data;
- SilcUInt32 auth_data_len;
- SilcConnAuthCompletion completion;
- SilcConnAuthGetAuthData get_auth_data;
- void *context;
- SilcDList public_keys;
- SilcSKRStatus skr_status;
- SilcUInt32 timeout_secs;
- SilcPacket packet;
- unsigned int aborted : 1;
- unsigned int success : 1;
-};
-
-/* Packet stream callbacks */
-static SilcPacketCallbacks silc_connauth_stream_cbs =
-{
- silc_connauth_packet_receive, NULL, NULL
-};
-
-
-/************************ Static utility functions **************************/
-
-/* Packet callback */
-
-static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *app_context)
-{
- SilcConnAuth connauth = callback_context;
- connauth->packet = packet;
- silc_fsm_continue(connauth->fsm);
- return TRUE;
-}
-
-/* Async operation abortion callback */
-
-static void silc_connauth_abort(SilcAsyncOperation op, void *context)
-{
- SilcConnAuth connauth = context;
- connauth->aborted = TRUE;
-}
-
-/* Generates signature for public key based authentication */
-
-static SilcBool silc_connauth_get_signature(SilcConnAuth connauth,
- unsigned char **auth_data,
- SilcUInt32 *auth_data_len)
-{
- int len;
- SilcSKE ske;
- SilcPrivateKey private_key;
- SilcBuffer auth;
-
- SILC_LOG_DEBUG(("Compute signature"));
-
- ske = connauth->ske;
- private_key = connauth->auth_data;
-
- /* Make the authentication data. Protocol says it is HASH plus
- KE Start Payload. */
- len = ske->hash_len + silc_buffer_len(ske->start_payload_copy);
- auth = silc_buffer_alloc_size(len);
- if (!auth)
- return FALSE;
- silc_buffer_format(auth,
- SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
- SILC_STR_UI_XNSTRING(
- ske->start_payload_copy->data,
- silc_buffer_len(ske->start_payload_copy)),
- SILC_STR_END);
-
- len = ((silc_pkcs_private_key_get_len(private_key) + 7) / 8) + 1;
- *auth_data = silc_calloc(len, sizeof(**auth_data));
- if (*auth_data == NULL) {
- silc_buffer_free(auth);
- return FALSE;
- }
-
- /* Compute signature */
- if (!silc_pkcs_sign(private_key, auth->data, silc_buffer_len(auth),
- *auth_data, len, auth_data_len, TRUE, ske->prop->hash)) {
- silc_free(*auth_data);
- silc_buffer_free(auth);
- return FALSE;
- }
-
- silc_buffer_free(auth);
- return TRUE;
-}
-
-/* Verifies digital signature */
-
-static SilcBool silc_connauth_verify_signature(SilcConnAuth connauth,
- SilcPublicKey pub_key,
- unsigned char *sign,
- SilcUInt32 sign_len)
-{
- int len;
- SilcBuffer auth;
- SilcSKE ske = connauth->ske;
-
- if (!pub_key || !sign)
- return FALSE;
-
- /* Make the authentication data. Protocol says it is HASH plus
- KE Start Payload. */
- len = ske->hash_len + silc_buffer_len(ske->start_payload_copy);
- auth = silc_buffer_alloc_size(len);
- if (!auth)
- return FALSE;
- silc_buffer_format(auth,
- SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
- SILC_STR_UI_XNSTRING(
- ske->start_payload_copy->data,
- silc_buffer_len(ske->start_payload_copy)),
- SILC_STR_END);
-
- /* Verify signature */
- if (!silc_pkcs_verify(pub_key, sign, sign_len, auth->data,
- silc_buffer_len(auth), ske->prop->hash)) {
- silc_buffer_free(auth);
- return FALSE;
- }
-
- silc_buffer_free(auth);
-
- return TRUE;
-}
-
-/* Timeout */
-
-SILC_TASK_CALLBACK(silc_connauth_timeout)
-{
- SilcConnAuth connauth = context;
- SILC_LOG_DEBUG(("Protocol timeout"));
- connauth->aborted = TRUE;
- silc_fsm_continue_sync(connauth->fsm);
-}
-
-/* SKR callback */
-
-static void silc_connauth_skr_callback(SilcSKR skr, SilcSKRFind find,
- SilcSKRStatus status,
- SilcDList results, void *context)
-{
- SilcConnAuth connauth = context;
-
- silc_skr_find_free(find);
-
- connauth->public_keys = results;
- connauth->skr_status = status;
-
- SILC_FSM_CALL_CONTINUE(connauth->fsm);
-}
-
-/* FSM destructor */
-
-static void silc_connauth_fsm_destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
-{
- silc_fsm_free(fsm);
-}
-
-
-/******************************* Protocol API *******************************/
-
-/* Allocate connection authentication context */
-
-SilcConnAuth silc_connauth_alloc(SilcSchedule schedule,
- SilcSKE ske,
- SilcUInt32 timeout_secs)
-{
- SilcConnAuth connauth;
-
- if (!schedule || !ske)
- return NULL;
-
- connauth = silc_calloc(1, sizeof(*connauth));
- if (!connauth)
- return NULL;
-
- connauth->fsm = silc_fsm_alloc(connauth, silc_connauth_fsm_destructor,
- NULL, schedule);
- if (!connauth->fsm) {
- silc_connauth_free(connauth);
- return NULL;
- }
-
- connauth->timeout_secs = timeout_secs;
- connauth->ske = ske;
- ske->refcnt++;
-
- return connauth;
-}
-
-/* Free connection authentication context */
-
-void silc_connauth_free(SilcConnAuth connauth)
-{
- if (connauth->public_keys)
- silc_dlist_uninit(connauth->public_keys);
-
- /* Free reference */
- silc_ske_free(connauth->ske);
-
- silc_free(connauth);
-}
-
-/* Return associated SKE context */
-
-SilcSKE silc_connauth_get_ske(SilcConnAuth connauth)
-{
- return connauth->ske;
-}
-
-
-/******************************** Initiator *********************************/
-
-SILC_FSM_STATE(silc_connauth_st_initiator_start);
-SILC_FSM_STATE(silc_connauth_st_initiator_result);
-SILC_FSM_STATE(silc_connauth_st_initiator_failure);
-
-SILC_FSM_STATE(silc_connauth_st_initiator_start)
-{
- SilcConnAuth connauth = fsm_context;
- SilcBuffer packet;
- int payload_len = 0;
- unsigned char *auth_data = NULL;
- SilcUInt32 auth_data_len = 0;
- SilcPacketFlags flags = 0;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (connauth->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
- return SILC_FSM_CONTINUE;
- }
-
- /* Start timeout */
- if (connauth->timeout_secs)
- silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
- silc_connauth_timeout, connauth,
- connauth->timeout_secs, 0);
-
- switch (connauth->auth_method) {
- case SILC_AUTH_NONE:
- /* No authentication required */
- break;
-
- case SILC_AUTH_PASSWORD:
- auth_data = silc_memdup(connauth->auth_data, connauth->auth_data_len);
- if (!auth_data) {
- /** Out of memory */
- silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
- return SILC_FSM_CONTINUE;
- }
- auth_data_len = connauth->auth_data_len;
- flags = SILC_PACKET_FLAG_LONG_PAD;
- break;
-
- case SILC_AUTH_PUBLIC_KEY:
- if (!silc_connauth_get_signature(connauth, &auth_data, &auth_data_len)) {
- /** Error computing signature */
- silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
- return SILC_FSM_CONTINUE;
- }
- break;
- }
-
- payload_len = 4 + auth_data_len;
- packet = silc_buffer_alloc_size(payload_len);
- if (!packet) {
- /** Out of memory */
- silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
- return SILC_FSM_CONTINUE;
- }
-
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(payload_len),
- SILC_STR_UI_SHORT(connauth->conn_type),
- SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
- SILC_STR_END);
-
- /* Send the packet */
- if (!silc_packet_send(connauth->ske->stream, SILC_PACKET_CONNECTION_AUTH,
- flags, packet->data, silc_buffer_len(packet))) {
- /** Error sending packet */
- silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
- return SILC_FSM_CONTINUE;
- }
-
- if (auth_data) {
- memset(auth_data, 0, auth_data_len);
- silc_free(auth_data);
- }
- silc_buffer_free(packet);
-
- /** Wait for responder */
- silc_fsm_next(fsm, silc_connauth_st_initiator_result);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(silc_connauth_st_initiator_result)
-{
- SilcConnAuth connauth = fsm_context;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (connauth->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
- return SILC_FSM_CONTINUE;
- }
-
- /* Check the status of authentication */
- if (connauth->packet->type == SILC_PACKET_SUCCESS) {
- SILC_LOG_DEBUG(("Authentication successful"));
- connauth->success = TRUE;
- } else {
- SILC_LOG_DEBUG(("Authentication failed"));
- connauth->success = FALSE;
- }
- silc_packet_free(connauth->packet);
-
- silc_packet_stream_unlink(connauth->ske->stream,
- &silc_connauth_stream_cbs, connauth);
- silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
-
- /* Call completion callback */
- connauth->completion(connauth, connauth->success, connauth->context);
-
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(silc_connauth_st_initiator_failure)
-{
- SilcConnAuth connauth = fsm_context;
- unsigned char error[4];
-
- SILC_LOG_DEBUG(("Start"));
-
- if (!connauth->aborted) {
- /* Send FAILURE packet */
- SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
- silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
-
- /* Call completion callback */
- connauth->completion(connauth, FALSE, connauth->context);
- }
-
- silc_packet_stream_unlink(connauth->ske->stream,
- &silc_connauth_stream_cbs, connauth);
- silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
-
- return SILC_FSM_FINISH;
-}
-
-SilcAsyncOperation
-silc_connauth_initiator(SilcConnAuth connauth,
- SilcConnectionType conn_type,
- SilcAuthMethod auth_method, void *auth_data,
- SilcUInt32 auth_data_len,
- SilcConnAuthCompletion completion,
- void *context)
-{
- SILC_LOG_DEBUG(("Connection authentication as initiator"));
-
- if (auth_method == SILC_AUTH_PASSWORD && !auth_data) {
- completion(connauth, FALSE, context);
- return NULL;
- }
-
- if (auth_method == SILC_AUTH_PUBLIC_KEY && !auth_data) {
- completion(connauth, FALSE, context);
- return NULL;
- }
-
- connauth->conn_type = conn_type;
- connauth->auth_method = auth_method;
- connauth->auth_data = auth_data;
- connauth->auth_data_len = auth_data_len;
- connauth->completion = completion;
- connauth->context = context;
-
- /* Link to packet stream to get packets */
- silc_packet_stream_link(connauth->ske->stream,
- &silc_connauth_stream_cbs, connauth, 1000000,
- SILC_PACKET_SUCCESS,
- SILC_PACKET_FAILURE, -1);
-
- /* Start the protocol */
- silc_async_init(&connauth->op, silc_connauth_abort, NULL, connauth);
- silc_fsm_start(connauth->fsm, silc_connauth_st_initiator_start);
-
- return &connauth->op;
-}
-
-
-/******************************** Responder *********************************/
-
-SILC_FSM_STATE(silc_connauth_st_responder_start);
-SILC_FSM_STATE(silc_connauth_st_responder_authenticate);
-SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk);
-SILC_FSM_STATE(silc_connauth_st_responder_success);
-SILC_FSM_STATE(silc_connauth_st_responder_failure);
-
-SILC_FSM_STATE(silc_connauth_st_responder_start)
-{
- SilcConnAuth connauth = fsm_context;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (connauth->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- /* Start timeout */
- if (connauth->timeout_secs)
- silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
- silc_connauth_timeout, connauth,
- connauth->timeout_secs, 0);
-
- /** Wait for initiator */
- silc_fsm_next(fsm, silc_connauth_st_responder_authenticate);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(silc_connauth_st_responder_authenticate)
-{
- SilcConnAuth connauth = fsm_context;
- SilcUInt16 payload_len;
- SilcUInt16 conn_type;
- unsigned char *auth_data = NULL, *passphrase = NULL;
- SilcUInt32 passphrase_len;
- SilcSKR repository = NULL;
- int ret;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (connauth->aborted) {
- /** Aborted */
- silc_packet_free(connauth->packet);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- if (connauth->packet->type != SILC_PACKET_CONNECTION_AUTH) {
- /** Protocol failure */
- silc_packet_free(connauth->packet);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- /* Parse the received authentication data packet. The received
- payload is Connection Auth Payload. */
- ret = silc_buffer_unformat(&connauth->packet->buffer,
- SILC_STR_UI_SHORT(&payload_len),
- SILC_STR_UI_SHORT(&conn_type),
- SILC_STR_END);
- if (ret == -1) {
- /** Bad payload */
- SILC_LOG_ERROR(("Bad payload in authentication packet"));
- silc_packet_free(connauth->packet);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- if (payload_len != silc_buffer_len(&connauth->packet->buffer)) {
- /** Bad payload length */
- SILC_LOG_ERROR(("Bad payload length in authentication packet"));
- silc_packet_free(connauth->packet);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- payload_len -= 4;
-
- if (conn_type < SILC_CONN_CLIENT || conn_type > SILC_CONN_ROUTER) {
- /** Bad connection type */
- SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet",
- conn_type));
- silc_packet_free(connauth->packet);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- if (payload_len > 0) {
- /* Get authentication data */
- ret = silc_buffer_unformat(&connauth->packet->buffer,
- SILC_STR_OFFSET(4),
- SILC_STR_UI_XNSTRING(&auth_data,
- payload_len),
- SILC_STR_END);
- if (ret == -1) {
- /** Bad payload */
- SILC_LOG_DEBUG(("Bad payload in authentication payload"));
- silc_packet_free(connauth->packet);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
- }
- silc_packet_free(connauth->packet);
-
- SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
-
- /* Get authentication data */
- if (!connauth->get_auth_data(connauth, conn_type, &passphrase,
- &passphrase_len, &repository,
- connauth->context)) {
- /** Connection not configured */
- SILC_LOG_ERROR(("Remote connection not configured"));
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- /* Verify */
-
- /* Passphrase authentication */
- if (passphrase && passphrase_len) {
- SILC_LOG_DEBUG(("Passphrase authentication"));
- if (!memcmp(auth_data, passphrase, passphrase_len)) {
- /** Authentication failed */
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
- } else if (repository) {
- /* Digital signature */
- SilcSKRFind find;
-
- SILC_LOG_DEBUG(("Digital signature authentication"));
-
- connauth->auth_data = silc_memdup(auth_data, payload_len);
- connauth->auth_data_len = payload_len;
-
- /* Allocate search constraints for finding the key */
- find = silc_skr_find_alloc();
-
- if (!find || !connauth->auth_data) {
- /** Out of memory */
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- silc_skr_find_set_pkcs_type(find, connauth->ske->pk_type);
- silc_skr_find_set_public_key(find, connauth->ske->public_key);
- silc_skr_find_set_usage(find, (SILC_SKR_USAGE_AUTH |
- SILC_SKR_USAGE_KEY_AGREEMENT));
-
- /** Find public key */
- silc_fsm_next(fsm, silc_connauth_st_responder_authenticate_pk);
- SILC_FSM_CALL(silc_skr_find(repository, find, silc_connauth_skr_callback,
- connauth));
- /* NOT REACHED */
- }
-
- /* Passphrase auth Ok, or no authentication required */
-
- /** Authentication successful */
- silc_fsm_next(fsm, silc_connauth_st_responder_success);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk)
-{
- SilcConnAuth connauth = fsm_context;
- SilcSKRKey key;
-
- if (connauth->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- if (connauth->skr_status != SILC_SKR_OK) {
- /** Public key not found */
- SILC_LOG_DEBUG(("Public key not found, error %d", connauth->skr_status));
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- SILC_LOG_DEBUG(("Found %d public keys",
- silc_dlist_count(connauth->public_keys)));
-
- /* Verify signature */
- key = silc_dlist_get(connauth->public_keys);
- if (!silc_connauth_verify_signature(connauth, key->key,
- connauth->auth_data,
- connauth->auth_data_len)) {
- /** Invalid signature */
- SILC_LOG_DEBUG(("Invalid signature"));
- silc_free(connauth->auth_data);
- silc_fsm_next(fsm, silc_connauth_st_responder_failure);
- return SILC_FSM_CONTINUE;
- }
-
- silc_free(connauth->auth_data);
-
- /** Authentication successful */
- silc_fsm_next(fsm, silc_connauth_st_responder_success);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(silc_connauth_st_responder_success)
-{
- SilcConnAuth connauth = fsm_context;
- unsigned char tmp[4];
-
- SILC_LOG_DEBUG(("Authentication successful"));
-
- /* Send FAILURE packet */
- SILC_PUT32_MSB(SILC_AUTH_OK, tmp);
- silc_packet_send(connauth->ske->stream, SILC_PACKET_SUCCESS, 0, tmp, 4);
-
- /* Call completion callback */
- connauth->completion(connauth, TRUE, connauth->context);
-
- silc_packet_stream_unlink(connauth->ske->stream,
- &silc_connauth_stream_cbs, connauth);
- silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
-
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(silc_connauth_st_responder_failure)
-{
- SilcConnAuth connauth = fsm_context;
- unsigned char error[4];
-
- SILC_LOG_ERROR(("Authentication failed"));
-
- if (!connauth->aborted) {
- /* Send FAILURE packet */
- SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
- silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
-
- /* Call completion callback */
- connauth->completion(connauth, FALSE, connauth->context);
- }
-
- silc_packet_stream_unlink(connauth->ske->stream,
- &silc_connauth_stream_cbs, connauth);
- silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
-
- return SILC_FSM_FINISH;
-}
-
-SilcAsyncOperation
-silc_connauth_responder(SilcConnAuth connauth,
- SilcConnAuthGetAuthData get_auth_data,
- SilcConnAuthCompletion completion,
- void *context)
-{
- SILC_LOG_DEBUG(("Connection authentication as responder"));
-
- connauth->get_auth_data = get_auth_data;
- connauth->completion = completion;
- connauth->context = context;
-
- /* Link to packet stream to get packets */
- silc_packet_stream_link(connauth->ske->stream,
- &silc_connauth_stream_cbs, connauth, 1000000,
- SILC_PACKET_CONNECTION_AUTH,
- SILC_PACKET_FAILURE, -1);
-
- /* Start the protocol */
- silc_async_init(&connauth->op, silc_connauth_abort, NULL, connauth);
- silc_fsm_start(connauth->fsm, silc_connauth_st_responder_start);
-
- return &connauth->op;
-}
+++ /dev/null
-/*
-
- silcconnauth.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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/SILC Connection Authentication
- *
- * DESCRIPTION
- *
- * SILC Connection Authenetication protocol API is used to perform the
- * connection authentication after successful SILC Key Exchange protocol.
- * The interface supports authentication based on passphrases and digital
- * signatures. It is also possible to have no authentication at all.
- *
- ***/
-
-#ifndef SILCCONNAUTH_H
-#define SILCCONNAUTH_H
-
-/****s* silcske/SilcConnAuthAPI/SilcConnAuth
- *
- * NAME
- *
- * typedef struct SilcConnAuthStruct *SilcConnAuth;
- *
- * DESCRIPTION
- *
- * The connection authentication context allocated by silc_connauth_alloc
- * and given as arguments to all silc_connauth_* functions. It is freed
- * by silc_connauth_free.
- *
- ***/
-typedef struct SilcConnAuthStruct *SilcConnAuth;
-
-/****d* silcske/SilcConnAuthAPI/SilcConnectionType
- *
- * NAME
- *
- * typedef enum { ... } SilcConnectionType;
- *
- * DESCRIPTION
- *
- * The type of the connection.
- *
- * SOURCE
- */
-typedef enum {
- SILC_CONN_UNKNOWN = 0, /* Unknown type, cannot be sent */
- SILC_CONN_CLIENT = 1, /* Client connection */
- SILC_CONN_SERVER = 2, /* Server connection */
- SILC_CONN_ROUTER = 3 /* Router connection */
-} SilcConnectionType;
-/***/
-
-/****f* silcske/SilcConnAuthAPI/SilcConnAuthGetAuthData
- *
- * SYNOPSIS
- *
- * typedef SilcBool
- * (*SilcConnAuthGetAuthData)(SilcConnAuth connauth,
- * SilcConnectionType conn_type,
- * unsigned char **passphrase,
- * SilcUInt32 *passphrase_len,
- * SilcSKR *repository,
- * void *context);
- *
- * DESCRIPTION
- *
- * Authentication callback to retrieve the authentication data from the
- * application. This is responder callback. If the authentication
- * method is passphrase it must be returned to `passphrase' pointer.
- * If it is digital signatures the key repository pointer must be
- * returned into `repository' pointer, which the library will use to
- * find the correct public key to verify the digital signature.
- *
- * If this connection is not configured at all this returns FALSE which
- * will result into authentication failure. Otherwise TRUE must be
- * returned.
- *
- ***/
-typedef SilcBool (*SilcConnAuthGetAuthData)(SilcConnAuth connauth,
- SilcConnectionType conn_type,
- unsigned char **passphrase,
- SilcUInt32 *passphrase_len,
- SilcSKR *repository,
- void *context);
-
-/****f* silcske/SilcConnAuthAPI/SilcConnAuthCompletion
- *
- * SYNOPSIS
- *
- * typedef void (*SilcConnAuthCompletion)(SilcConnAuth connauth,
- * SilcBool success,
- * void *context);
- *
- * DESCRIPTION
- *
- * Completion callback called to indicated the result of the connection
- * authentication protocol. If the `success' is FALSE the authentication
- * was a failure. The authentication protocol is over after this callback
- * is called.
- *
- ***/
-typedef void (*SilcConnAuthCompletion)(SilcConnAuth connauth,
- SilcBool success,
- void *context);
-
-/****f* silcske/SilcConnAuthAPI/silc_connauth_alloc
- *
- * SYNOPSIS
- *
- * SilcConnAuth silc_connauth_alloc(SilcSchedule schedule, SilcSKE ske,
- * SilcUInt32 timeout_secs);
- *
- * DESCRIPTION
- *
- * Allocates the connection authentication protocol context. The `ske'
- * is the successfully completed key exchange context. The `timeout_secs'
- * is the maximum time we are waiting for the protocol to finish before
- * it is timedout. Returns NULL on error.
- *
- ***/
-SilcConnAuth silc_connauth_alloc(SilcSchedule schedule, SilcSKE ske,
- SilcUInt32 timeout_secs);
-
-/****f* silcske/SilcConnAuthAPI/silc_connauth_free
- *
- * SYNOPSIS
- *
- * void silc_connauth_free(SilcConnAuth connauth);
- *
- * DESCRIPTION
- *
- * Frees the connection authentication protocol context `connauth'.
- *
- ***/
-void silc_connauth_free(SilcConnAuth connauth);
-
-/****f* silcske/SilcConnAuthAPI/silc_connauth_get_ske
- *
- * SYNOPSIS
- *
- * SilcSKE silc_connauth_get_ske(SilcConnAuth connauth);
- *
- * DESCRIPTION
- *
- * Returns the associated SilcSKE context from the `connauth'. It is the
- * pointer given as argument to silc_connauth_alloc.
- *
- ***/
-SilcSKE silc_connauth_get_ske(SilcConnAuth connauth);
-
-/****f* silcske/SilcConnAuthAPI/silc_connauth_initiator
- *
- * SYNOPSIS
- *
- * SilcAsyncOperation
- * silc_connauth_initiator(SilcConnAuth connauth,
- * SilcConnectionType conn_type,
- * SilcAuthMethod auth_method, void *auth_data,
- * SilcUInt32 auth_data_len,
- * SilcConnAuthCompletion completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Starts the connection authentication protocol as initiator. The
- * `conn_type' is the type of connection we are. The `auth_method' is
- * the authentication method. If it is SILC_AUTH_PASSWORD the `auth_data'
- * and `auth_data_len' is the passphrase and its length, respectively.
- * If it is SILC_AUTH_PUBLIC_KEY the `auth_data' is the SilcPrivateKey
- * used to produce the digital signature. The `auth_data_len' is 0.
- * The `completion' with `context' will be called after the protocol
- * has completed.
- *
- * This returns SilcAsyncOperation context which can be used to abort
- * the protocol before it is completed. Returns NULL on error.
- *
- ***/
-SilcAsyncOperation
-silc_connauth_initiator(SilcConnAuth connauth,
- SilcConnectionType conn_type,
- SilcAuthMethod auth_method, void *auth_data,
- SilcUInt32 auth_data_len,
- SilcConnAuthCompletion completion,
- void *context);
-
-/****f* silcske/SilcConnAuthAPI/silc_connauth_responder
- *
- * SYNOPSIS
- *
- * SilcAsyncOperation
- * silc_connauth_responder(SilcConnAuth connauth,
- * SilcConnAuthGetAuthData get_auth_data,
- * SilcConnAuthCompletion completion,
- * void *context);
- *
- * DESCRIPTION
- *
- * Starts the connection authentication protocol as responder. The
- * `get_auth_data' is called to retrieve the authentication data for
- * this connection. The `completion' will be called after the protocol
- * has completed.
- *
- * This returns SilcAsyncOperation context which can be used to abort
- * the protocol before it is completed. Returns NULL on error.
- *
- ***/
-SilcAsyncOperation
-silc_connauth_responder(SilcConnAuth connauth,
- SilcConnAuthGetAuthData get_auth_data,
- SilcConnAuthCompletion completion,
- void *context);
-
-#endif /* SILCCONNAUTH_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcske.h"
#include "groups_internal.h"
-/************************** Types and definitions ***************************/
+/* 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);
/* Structure to hold all SKE callbacks. */
struct SilcSKECallbacksStruct {
+ SilcSKESendPacketCb send_packet;
+ SilcSKECb payload_receive;
SilcSKEVerifyCb verify_key;
- SilcSKECompletionCb completed;
+ SilcSKECb proto_continue;
+ SilcSKECheckVersion check_version;
void *context;
};
-/************************ Static utility functions **************************/
-
-/* States */
-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);
-SILC_FSM_STATE(silc_ske_st_initiator_failure);
-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_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);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_start);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_done);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_end);
-SILC_TASK_CALLBACK(silc_ske_packet_send_retry);
-
-SilcSKEKeyMaterial
-silc_ske_process_key_material(SilcSKE ske,
- SilcUInt32 req_iv_len,
- SilcUInt32 req_enc_key_len,
- SilcUInt32 req_hmac_key_len,
- SilcSKERekeyMaterial *rekey);
-static SilcBool silc_ske_packet_send(SilcSKE ske,
- SilcPacketType type,
- SilcPacketFlags flags,
- const unsigned char *data,
- SilcUInt32 data_len);
-
-/* Packet callback */
-
-static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
- SilcPacketStream stream,
- SilcPacket packet,
- void *callback_context,
- void *app_context)
+/* Allocates new SKE object. */
+
+SilcSKE silc_ske_alloc(SilcRng rng, void *context)
{
- SilcSKE ske = callback_context;
+ SilcSKE ske;
- /* Clear retransmission */
- ske->retry_timer = SILC_SKE_RETRY_MIN;
- ske->retry_count = 0;
- silc_schedule_task_del_by_callback(ske->schedule,
- silc_ske_packet_send_retry);
+ SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
- /* Signal for new packet */
- ske->packet = packet;
+ ske = silc_calloc(1, sizeof(*ske));
+ if (!ske)
+ return NULL;
+ ske->status = SILC_SKE_STATUS_OK;
+ ske->rng = rng;
+ ske->user_data = context;
+ ske->users = 1;
- /* Check if we were aborted */
- if (ske->aborted) {
- silc_packet_free(packet);
- ske->packet = NULL;
+ return ske;
+}
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_aborted);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_aborted);
+/* Free's SKE object. */
- silc_fsm_continue_sync(&ske->fsm);
- return TRUE;
+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;
}
- /* See if received failure from remote */
- if (packet->type == SILC_PACKET_FAILURE) {
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
- }
+ SILC_LOG_DEBUG(("Freeing Key Exchange object"));
- /* Handle rekey and SUCCESS packets synchronously. After SUCCESS packets
- they keys are taken into use immediately, hence the synchronous
- processing to get the keys in use as soon as possible. */
- if (ske->rekeying || packet->type == SILC_PACKET_SUCCESS)
- silc_fsm_continue_sync(&ske->fsm);
- else
- silc_fsm_continue(&ske->fsm);
+ 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);
- return TRUE;
+ memset(ske, 'F', sizeof(*ske));
+ silc_free(ske);
+ }
}
-/* Packet stream callbacks */
-static SilcPacketCallbacks silc_ske_stream_cbs =
-{
- silc_ske_packet_receive, NULL, NULL
-};
+/* Sets the callback functions for the SKE session.
-/* Aborts SKE protocol */
+ The `send_packet' callback is a function that sends the packet to
+ network. The SKE library will call it at any time packet needs to
+ be sent to the remote host.
-static void silc_ske_abort(SilcAsyncOperation op, void *context)
-{
- SilcSKE ske = context;
- ske->aborted = TRUE;
-}
+ The `payload_receive' callback is called when the remote host's Key
+ Exchange Start Payload has been processed. The payload is saved
+ to ske->start_payload if the application would need it. The application
+ must also provide the payload to the next state of the SKE.
+
+ The `verify_key' callback is called to verify the received public key
+ or certificate. The verification process is most likely asynchronous.
+ That is why the application must call the completion callback when the
+ verification process has been completed. The library then calls the user
+ callback (`proto_continue'), if it is provided to indicate that the SKE
+ protocol may continue.
+
+ The `proto_continue' callback is called to indicate that it is
+ safe to continue the execution of the SKE protocol after executing
+ an asynchronous operation, such as calling the `verify_key' callback
+ function, which is asynchronous. The application should check the
+ ske->status in this function to check whether it is Ok to continue
+ the execution of the protocol.
+
+ 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.
-/* Public key verification completion callback */
+ The `context' is passed as argument to all of the above callback
+ functions. */
-static void silc_ske_pk_verified(SilcSKE ske, SilcSKEStatus status,
- void *completion_context)
+void silc_ske_set_callbacks(SilcSKE ske,
+ SilcSKESendPacketCb send_packet,
+ SilcSKECb payload_receive,
+ SilcSKEVerifyCb verify_key,
+ SilcSKECb proto_continue,
+ SilcSKECheckVersion check_version,
+ void *context)
{
- ske->status = status;
- SILC_FSM_CALL_CONTINUE(&ske->fsm);
+ if (ske->callbacks)
+ silc_free(ske->callbacks);
+ ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
+ if (!ske->callbacks)
+ return;
+ ske->callbacks->send_packet = send_packet;
+ ske->callbacks->payload_receive = payload_receive;
+ ske->callbacks->verify_key = verify_key;
+ ske->callbacks->proto_continue = proto_continue;
+ ske->callbacks->check_version = check_version;
+ ske->callbacks->context = context;
}
-/* SKR find callback */
-
-static void silc_ske_skr_callback(SilcSKR repository,
- SilcSKRFind find,
- SilcSKRStatus status,
- SilcDList keys, void *context)
+/* Starts the SILC Key Exchange protocol for initiator. The connection
+ to the remote end must be established before calling this function
+ and the connecting socket must be sent as argument. This function
+ creates the Key Exchange Start Payload which includes all our
+ configured security properties. This payload is then sent to the
+ remote end for further processing. This payload must be sent as
+ argument to the function, however, it must not be encoded
+ already, it is done by this function. The caller must not free
+ the `start_payload' since the SKE library will save it.
+
+ The packet sending is done by calling a callback function. Caller
+ must provide a routine to send the packet. */
+
+SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ SilcSKEStartPayload *start_payload)
{
- SilcSKE ske = context;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
- silc_skr_find_free(find);
+ SILC_LOG_DEBUG(("Start"));
- if (status != SILC_SKR_OK) {
- if (ske->callbacks->verify_key) {
- /* Verify from application */
- ske->callbacks->verify_key(ske, ske->prop->public_key,
- ske->callbacks->context,
- silc_ske_pk_verified, NULL);
- return;
- }
- }
+ ske->sock = sock;
+ ske->rng = rng;
- if (keys)
- silc_dlist_uninit(keys);
+ /* Encode the payload */
+ status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
- /* Continue */
- ske->status = (status == SILC_SKR_OK ? SILC_SKE_STATUS_OK :
- SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY);
- SILC_FSM_CALL_CONTINUE(&ske->fsm);
-}
+ /* Send the packet. */
+ if (ske->callbacks->send_packet)
+ (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
+ ske->callbacks->context);
-/* Checks remote and local versions */
+ /* Save the the payload buffer for future use. It is later used to
+ compute the HASH value. */
+ ske->start_payload_copy = payload_buf;
+ ske->start_payload = start_payload;
-static SilcSKEStatus silc_ske_check_version(SilcSKE ske)
-{
- SilcUInt32 r_software_version = 0;
+ return status;
+}
- if (!ske->remote_version || !ske->version)
- return SILC_SKE_STATUS_BAD_VERSION;
+/* Function called after ske_initiator_start fuction. This receives
+ the remote ends Key Exchange Start payload which includes the
+ security properties selected by the responder from our payload
+ sent in the silc_ske_initiator_start function. */
- if (!silc_parse_version_string(ske->remote_version, NULL, NULL,
- &r_software_version, NULL, NULL))
- return SILC_SKE_STATUS_BAD_VERSION;
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
+ SilcBuffer start_payload)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEStartPayload *payload;
+ SilcSKESecurityProperties prop;
+ SilcSKEDiffieHellmanGroup group;
- /* Backwards compatibility checks */
+ SILC_LOG_DEBUG(("Start"));
- /* Old server versions requires "valid" looking Source ID in the SILC
- packets during initial key exchange. All version before 1.1.0. */
- if (r_software_version < 110) {
- SilcClientID id;
- memset(&id, 0, sizeof(id));
- id.ip.data_len = 4;
- SILC_LOG_DEBUG(("Remote is old version, add dummy Source ID to packets"));
- silc_packet_set_ids(ske->stream, SILC_ID_CLIENT, &id, 0, NULL);
+ /* Decode the payload */
+ status = silc_ske_payload_start_decode(ske, start_payload, &payload);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ silc_ske_payload_start_free(ske->start_payload);
+ return status;
}
- return SILC_SKE_STATUS_OK;
-}
+ /* Check that the cookie is returned unmodified */
+ if (memcmp(ske->start_payload->cookie, payload->cookie,
+ ske->start_payload->cookie_len)) {
+ SILC_LOG_ERROR(("Responder modified our cookie and it must not do it"));
+ ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
+ silc_ske_payload_start_free(ske->start_payload);
+ return status;
+ }
-/* Selects the supported security properties from the initiator's Key
- Exchange Start Payload. A responder function. Saves our reply
- start payload to ske->start_payload. */
+ /* 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) {
+ ske->status = status;
+ silc_ske_payload_start_free(ske->start_payload);
+ return status;
+ }
+ }
-static SilcSKEStatus
-silc_ske_select_security_properties(SilcSKE ske,
- SilcSKEStartPayload remote_payload,
- SilcSKESecurityProperties *prop)
-{
- SilcSKEStatus status;
- SilcSKEStartPayload rp, payload;
- char *cp;
- int len;
+ /* Free our KE Start Payload context, we don't need it anymore. */
+ silc_ske_payload_start_free(ske->start_payload);
- SILC_LOG_DEBUG(("Parsing KE Start Payload"));
+ /* Take the selected security properties into use while doing
+ the key exchange. This is used only while doing the key
+ exchange. The same data is returned to upper levels by calling
+ the callback function. */
+ 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;
- rp = remote_payload;
+ prop->group = group;
- /* Check for mandatory fields */
- if (!rp->ke_grp_len) {
- SILC_LOG_DEBUG(("KE group not defined in payload"));
- return SILC_SKE_STATUS_BAD_PAYLOAD;
- }
- if (!rp->pkcs_alg_len) {
- SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
- return SILC_SKE_STATUS_BAD_PAYLOAD;
+ if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+ goto err;
}
- if (!rp->enc_alg_len) {
- SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
- return SILC_SKE_STATUS_BAD_PAYLOAD;
+
+ if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+ goto err;
}
- if (!rp->hash_alg_len) {
- SILC_LOG_DEBUG(("Hash alg not defined in payload"));
- return SILC_SKE_STATUS_BAD_PAYLOAD;
+
+ if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+ goto err;
}
- if (!rp->hmac_alg_len) {
- SILC_LOG_DEBUG(("HMAC not defined in payload"));
- return SILC_SKE_STATUS_BAD_PAYLOAD;
+
+ if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HMAC;
+ goto err;
}
- /* Allocate security properties */
- *prop = silc_calloc(1, sizeof(**prop));
- if (!(*prop))
- return SILC_SKE_STATUS_OUT_OF_MEMORY;
+ /* Save remote's KE Start Payload */
+ ske->start_payload = payload;
- /* Allocate our reply start payload */
- payload = silc_calloc(1, sizeof(*payload));
- if (!payload) {
- silc_free(*prop);
- return SILC_SKE_STATUS_OUT_OF_MEMORY;
- }
+ /* Return the received payload by calling the callback function. */
+ if (ske->callbacks->payload_receive)
+ (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
- /* 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) {
- ske->status = status;
- return status;
- }
+ return status;
- /* Flags are returned unchanged. */
- (*prop)->flags = payload->flags = rp->flags;
+ err:
+ if (payload)
+ silc_ske_payload_start_free(payload);
- /* Take cookie, we must return it to sender unmodified. */
- payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
- if (!payload->cookie) {
+ silc_ske_group_free(group);
+
+ 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 (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ ske->status = status;
+ return status;
+}
+
+/* This function creates random number x, such that 1 < x < q and
+ computes e = g ^ x mod p and sends the result to the remote end in
+ Key Exchange Payload. */
+
+SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcSKEPKType pk_type)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+ SilcMPInt *x;
+ SilcSKEKEPayload *payload;
+ SilcUInt32 pk_len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Create the random number x, 1 < x < q. */
+ x = silc_calloc(1, sizeof(*x));
+ if (!x){
ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ return ske->status;
+ }
+ 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) {
+ silc_mp_uninit(x);
+ silc_free(x);
+ ske->status = status;
return status;
}
- payload->cookie_len = SILC_SKE_COOKIE_LEN;
- memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
-
- /* In case IV included flag and session port is set the first 16-bits of
- cookie will include our session port. */
- if (rp->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port) {
- /* Take remote port */
- SILC_GET16_MSB((*prop)->remote_port, payload->cookie);
- /* Put out port */
- SILC_PUT16_MSB(ske->session_port, payload->cookie);
- }
+ /* Encode the result to Key Exchange Payload. */
- /* Put our version to our reply */
- payload->version = strdup(ske->version);
- if (!payload->version) {
+ payload = silc_calloc(1, sizeof(*payload));
+ if (!payload) {
+ silc_mp_uninit(x);
+ silc_free(x);
ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
- return status;
+ return ske->status;
}
- payload->version_len = strlen(ske->version);
+ ske->ke1_payload = payload;
- /* Get supported Key Exchange groups */
- cp = rp->ke_grp_list;
- if (cp && strchr(cp, ',')) {
- while(cp) {
- char *item;
+ SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
- 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);
+ /* 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);
- SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
+ /* Get public key */
+ if (public_key) {
+ payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
+ if (!payload->pk_data) {
+ silc_mp_uninit(x);
+ silc_free(x);
+ silc_mp_uninit(&payload->x);
+ silc_free(payload);
+ ske->ke1_payload = NULL;
+ ske->status = SILC_SKE_STATUS_OK;
+ return ske->status;
+ }
+ payload->pk_len = pk_len;
+ }
+ payload->pk_type = pk_type;
- if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
- SILC_LOG_DEBUG(("Found KE group `%s'", item));
+ /* Compute signature data if we are doing mutual authentication */
+ if (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;
- payload->ke_grp_len = len;
- payload->ke_grp_list = item;
- break;
- }
+ SILC_LOG_DEBUG(("We are doing mutual authentication"));
+ SILC_LOG_DEBUG(("Computing HASH_i value"));
- cp += len;
- if (strlen(cp) == 0)
- cp = NULL;
- else
- cp++;
+ /* Compute the hash value */
+ memset(hash, 0, sizeof(hash));
+ silc_ske_make_hash(ske, hash, &hash_len, TRUE);
- if (item)
- silc_free(item);
- }
+ SILC_LOG_DEBUG(("Signing HASH_i value"));
- if (!payload->ke_grp_len && !payload->ke_grp_list) {
- SILC_LOG_DEBUG(("Could not find supported KE group"));
+ /* Sign the hash value */
+ silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
+ 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)) {
+ silc_mp_uninit(x);
+ silc_free(x);
+ silc_mp_uninit(&payload->x);
+ silc_free(payload->pk_data);
silc_free(payload);
- return SILC_SKE_STATUS_UNKNOWN_GROUP;
+ ske->ke1_payload = NULL;
+ ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+ return ske->status;
}
- } else {
- SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
- SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
-
- payload->ke_grp_len = rp->ke_grp_len;
- payload->ke_grp_list = strdup(rp->ke_grp_list);
+ payload->sign_data = silc_memdup(sign, sign_len);
+ payload->sign_len = sign_len;
+ memset(sign, 0, sizeof(sign));
}
- /* Save group to security properties */
- status = silc_ske_group_get_by_name(payload->ke_grp_list, &(*prop)->group);
+ status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
if (status != SILC_SKE_STATUS_OK) {
- silc_free(payload);
- return SILC_SKE_STATUS_UNKNOWN_GROUP;
- }
-
- /* Get supported PKCS algorithms */
- cp = rp->pkcs_alg_list;
- if (cp && strchr(cp, ',')) {
- while(cp) {
- char *item;
-
- 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(("Proposed PKCS alg `%s'", item));
-
- if (silc_pkcs_find_algorithm(item, NULL)) {
- SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
-
- payload->pkcs_alg_len = len;
- payload->pkcs_alg_list = item;
- break;
- }
-
- cp += len;
- if (strlen(cp) == 0)
- cp = NULL;
- else
- cp++;
-
- if (item)
- silc_free(item);
- }
-
- 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 {
- 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);
- }
-
- /* Get supported encryption algorithms */
- cp = rp->enc_alg_list;
- if (cp && strchr(cp, ',')) {
- while(cp) {
- char *item;
-
- 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(("Proposed encryption alg `%s'", item));
-
- if (silc_cipher_is_supported(item) == TRUE) {
- SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
-
- 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);
- return SILC_SKE_STATUS_UNKNOWN_CIPHER;
- }
- } else {
- SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
- rp->enc_alg_list));
-
- payload->enc_alg_len = rp->enc_alg_len;
- payload->enc_alg_list = strdup(rp->enc_alg_list);
- }
-
- /* Save selected cipher to security properties */
- if (silc_cipher_alloc(payload->enc_alg_list, &(*prop)->cipher) == FALSE) {
- silc_free(payload->ke_grp_list);
- silc_free(payload->pkcs_alg_list);
- silc_free(payload);
- return SILC_SKE_STATUS_UNKNOWN_CIPHER;
- }
-
- /* Get supported hash algorithms */
- cp = rp->hash_alg_list;
- if (cp && strchr(cp, ',')) {
- while(cp) {
- char *item;
-
- 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(("Proposed hash alg `%s'", item));
-
- if (silc_hash_is_supported(item) == TRUE) {
- SILC_LOG_DEBUG(("Found hash alg `%s'", item));
-
- payload->hash_alg_len = len;
- payload->hash_alg_list = item;
- break;
- }
-
- cp += len;
- if (strlen(cp) == 0)
- cp = NULL;
- else
- cp++;
-
- if (item)
- silc_free(item);
- }
-
- 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 {
- 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);
- }
-
- /* Save selected hash algorithm to security properties */
- if (silc_hash_alloc(payload->hash_alg_list, &(*prop)->hash) == FALSE) {
- 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;
- }
-
- /* Get supported HMACs */
- cp = rp->hmac_alg_list;
- if (cp && strchr(cp, ',')) {
- while(cp) {
- char *item;
-
- 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(("Proposed HMAC `%s'", item));
-
- 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 {
- 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);
- }
-
- /* Save selected HMACc to security properties */
- if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &(*prop)->hmac) == FALSE) {
- 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;
- }
-
- /* Get supported compression algorithms */
- cp = rp->comp_alg_list;
- if (cp && strchr(cp, ',')) {
- while(cp) {
- char *item;
-
- 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(("Proposed Compression `%s'", item));
-
-#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
-
- 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;
-
- /* Save our reply payload */
- ske->start_payload = payload;
-
- return SILC_SKE_STATUS_OK;
-}
-
-/* Creates random number such that 1 < rnd < n and at most length
- of len bits. The rnd sent as argument must be initialized. */
-
-static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
- SilcUInt32 len,
- SilcMPInt *rnd)
-{
- SilcSKEStatus status = SILC_SKE_STATUS_OK;
- unsigned char *string;
- SilcUInt32 l;
-
- if (!len)
- return SILC_SKE_STATUS_ERROR;
-
- SILC_LOG_DEBUG(("Creating random number"));
-
- l = ((len - 1) / 8);
-
- /* Get the random number as string */
- string = silc_rng_get_rn_data(ske->rng, l);
- if (!string)
- return SILC_SKE_STATUS_OUT_OF_MEMORY;
-
- /* Decode the string into a MP integer */
- silc_mp_bin2mp(string, l, rnd);
- silc_mp_mod_2exp(rnd, rnd, len);
-
- /* 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;
-
- memset(string, 'F', l);
- silc_free(string);
-
- return status;
-}
-
-/* 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. */
-
-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_LOG_DEBUG(("Start"));
-
- 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);
-
- /* 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;
-
- /* 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;
- }
-
- 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);
-
- 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;
-
- /* 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;
- }
-
- SILC_LOG_HEXDUMP(("hash buf"), buf->data, silc_buffer_len(buf));
-
- memset(e, 0, e_len);
- silc_free(e);
- }
-
- /* 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 (initiator == FALSE) {
- SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
- } else {
- SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
- }
-
- silc_buffer_free(buf);
-
- return status;
-}
-
-/* Generate rekey material */
-
-static SilcSKERekeyMaterial
-silc_ske_make_rekey_material(SilcSKE ske, SilcSKEKeyMaterial keymat)
-{
- SilcSKERekeyMaterial rekey;
- const char *hash;
-
- /* Create rekey material */
- rekey = silc_calloc(1, sizeof(*rekey));
- if (!rekey)
- return NULL;
-
- if (ske->prop) {
- if (ske->prop->group)
- rekey->ske_group = silc_ske_group_get_number(ske->prop->group);
- rekey->pfs = (ske->prop->flags & SILC_SKE_SP_FLAG_PFS ? TRUE : FALSE);
- hash = silc_hash_get_name(ske->prop->hash);
- rekey->hash = silc_memdup(hash, strlen(hash));
- if (!rekey->hash)
- return NULL;
- }
-
- if (rekey->pfs == FALSE) {
- rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
- keymat->enc_key_len / 8);
- if (!rekey->send_enc_key) {
- silc_free(rekey);
- return NULL;
- }
- rekey->enc_key_len = keymat->enc_key_len;
- }
-
- return rekey;
-}
-
-/* Assembles security properties */
-
-static SilcSKEStartPayload
-silc_ske_assemble_security_properties(SilcSKE ske,
- SilcSKESecurityPropertyFlag flags,
- const char *version)
-{
- SilcSKEStartPayload rp;
- int i;
-
- SILC_LOG_DEBUG(("Assembling KE Start Payload"));
-
- rp = silc_calloc(1, sizeof(*rp));
-
- /* Set flags */
- rp->flags = (unsigned char)flags;
-
- /* 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;
-
- /* In case IV included flag and session port is set the first 16-bits of
- cookie will include our session port. */
- if (flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port)
- SILC_PUT16_MSB(ske->session_port, rp->cookie);
-
- /* Put version */
- rp->version = strdup(version);
- rp->version_len = strlen(version);
-
- /* Get supported Key Exhange groups */
- rp->ke_grp_list = silc_ske_get_supported_groups();
- rp->ke_grp_len = strlen(rp->ke_grp_list);
-
- /* Get supported PKCS algorithms */
- rp->pkcs_alg_list = silc_pkcs_get_supported();
- rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
-
- /* Get supported encryption algorithms */
- rp->enc_alg_list = silc_cipher_get_supported();
- rp->enc_alg_len = strlen(rp->enc_alg_list);
-
- /* Get supported hash algorithms */
- rp->hash_alg_list = silc_hash_get_supported();
- rp->hash_alg_len = strlen(rp->hash_alg_list);
-
- /* Get supported HMACs */
- rp->hmac_alg_list = silc_hmac_get_supported();
- rp->hmac_alg_len = strlen(rp->hmac_alg_list);
-
- /* XXX */
- /* Get supported compression algorithms */
- rp->comp_alg_list = strdup("none");
- rp->comp_alg_len = strlen("none");
-
- 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;
-}
-
-/* Packet retransmission callback. */
-
-SILC_TASK_CALLBACK(silc_ske_packet_send_retry)
-{
- SilcSKE ske = context;
-
- if (ske->retry_count++ >= SILC_SKE_RETRY_COUNT ||
- ske->aborted) {
- SILC_LOG_DEBUG(("Retransmission limit reached, packet was lost"));
- ske->retry_count = 0;
- ske->retry_timer = SILC_SKE_RETRY_MIN;
- silc_free(ske->retrans.data);
- ske->retrans.data = NULL;
- ske->status = SILC_SKE_STATUS_TIMEOUT;
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
- silc_fsm_continue_sync(&ske->fsm);
- return;
- }
-
- SILC_LOG_DEBUG(("Retransmitting packet"));
- silc_ske_packet_send(ske, ske->retrans.type, ske->retrans.flags,
- ske->retrans.data, ske->retrans.data_len);
-}
-
-/* Install retransmission timer */
-
-static void silc_ske_install_retransmission(SilcSKE ske)
-{
- if (!silc_packet_stream_is_udp(ske->stream))
- return;
-
- if (ske->retrans.data) {
- SILC_LOG_DEBUG(("Installing retransmission timer %d secs",
- ske->retry_timer));
- silc_schedule_task_add_timeout(ske->schedule, silc_ske_packet_send_retry,
- ske, ske->retry_timer, 0);
- }
- ske->retry_timer = ((ske->retry_timer * SILC_SKE_RETRY_MUL) +
- (silc_rng_get_rn16(ske->rng) % SILC_SKE_RETRY_RAND));
-}
-
-/* Sends SILC packet. Handles retransmissions with UDP streams. */
-
-static SilcBool silc_ske_packet_send(SilcSKE ske,
- SilcPacketType type,
- SilcPacketFlags flags,
- const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcBool ret;
-
- /* Send the packet */
- ret = silc_packet_send(ske->stream, type, flags, data, data_len);
-
- if (silc_packet_stream_is_udp(ske->stream) &&
- type != SILC_PACKET_FAILURE && type != SILC_PACKET_REKEY) {
- silc_free(ske->retrans.data);
- ske->retrans.type = type;
- ske->retrans.flags = flags;
- ske->retrans.data = silc_memdup(data, data_len);
- ske->retrans.data_len = data_len;
- silc_ske_install_retransmission(ske);
- }
-
- return ret;
-}
-
-/* Calls completion callback. Completion is called always in this function
- and must not be called anywhere else. */
-
-static void silc_ske_completion(SilcSKE ske)
-{
- /* Call the completion callback */
- if (!ske->freed && !ske->aborted && ske->callbacks->completed) {
- if (ske->status != SILC_SKE_STATUS_OK)
- ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
- ske->callbacks->context);
- else
- ske->callbacks->completed(ske, ske->status, ske->prop, ske->keymat,
- ske->rekey, ske->callbacks->context);
- }
-}
-
-/* SKE FSM destructor. */
-
-static void silc_ske_finished(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
-{
- SilcSKE ske = fsm_context;
- ske->running = FALSE;
- if (ske->freed)
- silc_ske_free(ske);
-}
-
-/* Key exchange timeout task callback */
-
-SILC_TASK_CALLBACK(silc_ske_timeout)
-{
- SilcSKE ske = context;
-
- SILC_LOG_DEBUG(("Timeout"));
-
- ske->packet = NULL;
- ske->status = SILC_SKE_STATUS_TIMEOUT;
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-
- silc_fsm_continue_sync(&ske->fsm);
-}
-
-/******************************* Protocol API *******************************/
-
-/* Allocates new SKE object. */
-
-SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
- SilcSKR repository, SilcPublicKey public_key,
- SilcPrivateKey private_key, void *context)
-{
- SilcSKE ske;
-
- SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
-
- if (!rng || !schedule)
- return NULL;
-
- if (!public_key) {
- SILC_LOG_ERROR(("Public key must be given to silc_ske_alloc"));
- return NULL;
- }
-
- ske = silc_calloc(1, sizeof(*ske));
- if (!ske)
- return NULL;
- ske->status = SILC_SKE_STATUS_OK;
- ske->rng = rng;
- ske->repository = repository;
- ske->user_data = context;
- ske->schedule = schedule;
- ske->public_key = public_key;
- ske->private_key = private_key;
- ske->retry_timer = SILC_SKE_RETRY_MIN;
- ske->refcnt = 1;
-
- return ske;
-}
-
-/* Free's SKE object. */
-
-void silc_ske_free(SilcSKE ske)
-{
- SILC_LOG_DEBUG(("Freeing Key Exchange object"));
-
- if (!ske)
- return;
-
- if (ske->running) {
- ske->freed = TRUE;
-
- if (ske->aborted) {
- /* If already aborted, destroy the session immediately */
- ske->packet = NULL;
- ske->status = SILC_SKE_STATUS_ERROR;
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
- silc_fsm_continue_sync(&ske->fsm);
- }
- return;
- }
-
- ske->refcnt--;
- if (ske->refcnt > 0)
- return;
-
- /* 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->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);
- if (ske->prop->public_key)
- silc_pkcs_public_key_free(ske->prop->public_key);
- silc_free(ske->prop);
- }
- if (ske->keymat)
- silc_ske_free_key_material(ske->keymat);
- 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->retrans.data);
- silc_free(ske->hash);
- silc_free(ske->callbacks);
-
- memset(ske, 'F', sizeof(*ske));
- silc_free(ske);
-}
-
-/* Return user context */
-
-void *silc_ske_get_context(SilcSKE ske)
-{
- return ske->user_data;
-}
-
-/* Sets protocol callbacks */
-
-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;
-}
-
-
-/******************************** Initiator *********************************/
-
-/* Start protocol. Send our proposal */
-
-SILC_FSM_STATE(silc_ske_st_initiator_start)
-{
- SilcSKE ske = fsm_context;
- SilcBuffer payload_buf;
- SilcStatus status;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (ske->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
- return SILC_FSM_CONTINUE;
- }
-
- /* 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;
- }
-
- /* Save the the payload buffer for future use. It is later used to
- compute the HASH value. */
- ske->start_payload_copy = payload_buf;
-
- /* Send the packet. */
- if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE, 0,
- silc_buffer_data(payload_buf),
- silc_buffer_len(payload_buf))) {
- /** Error sending packet */
- SILC_LOG_DEBUG(("Error sending packet"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Add key exchange timeout */
- silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
- ske, ske->timeout, 0);
-
- /** Wait for responder proposal */
- SILC_LOG_DEBUG(("Waiting for responder proposal"));
- silc_fsm_next(fsm, silc_ske_st_initiator_phase1);
- return SILC_FSM_WAIT;
-}
-
-/* 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 = NULL;
- SilcBuffer packet_buf = &ske->packet->buffer;
- SilcUInt16 remote_port = 0;
- SilcID id;
- int coff = 0;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (ske->packet->type != SILC_PACKET_KEY_EXCHANGE) {
- SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
- silc_ske_install_retransmission(ske);
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- return SILC_FSM_WAIT;
- }
-
- /* Decode the payload */
- status = silc_ske_payload_start_decode(ske, packet_buf, &payload);
- if (status != SILC_SKE_STATUS_OK) {
- /** Error decoding Start Payload */
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Get remote ID and set it to stream */
- if (ske->packet->src_id_len) {
- silc_id_str2id(ske->packet->src_id, ske->packet->src_id_len,
- ske->packet->src_id_type,
- (ske->packet->src_id_type == SILC_ID_SERVER ?
- (void *)&id.u.server_id : (void *)&id.u.client_id),
- (ske->packet->src_id_type == SILC_ID_SERVER ?
- sizeof(id.u.server_id) : sizeof(id.u.client_id)));
- silc_packet_set_ids(ske->stream, 0, NULL, ske->packet->src_id_type,
- (ske->packet->src_id_type == SILC_ID_SERVER ?
- (void *)&id.u.server_id : (void *)&id.u.client_id));
- }
-
- silc_packet_free(ske->packet);
- ske->packet = NULL;
-
- /* Check that the cookie is returned unmodified. In case IV included
- flag and session port has been set, the first two bytes of cookie
- are the session port and we ignore them in this check. */
- if (payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port) {
- /* Take remote port */
- SILC_GET16_MSB(remote_port, ske->start_payload->cookie);
- coff = 2;
- }
- if (memcmp(ske->start_payload->cookie + coff, payload->cookie + coff,
- SILC_SKE_COOKIE_LEN - coff)) {
- /** Invalid cookie */
- SILC_LOG_ERROR(("Invalid cookie, modified or unsupported feature"));
- ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* 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;
- }
-
- /* Free our KE Start Payload context, we don't need it anymore. */
- silc_ske_payload_start_free(ske->start_payload);
- ske->start_payload = NULL;
-
- /* 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;
-
- prop->group = group;
- prop->remote_port = remote_port;
-
- if (silc_pkcs_find_algorithm(payload->pkcs_alg_list, NULL) == NULL) {
- 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;
- }
-
- /* Save remote's KE Start Payload */
- ske->start_payload = payload;
-
- /** Send KE Payload */
- silc_fsm_next(fsm, silc_ske_st_initiator_phase2);
- return SILC_FSM_CONTINUE;
-
- err:
- if (payload)
- silc_ske_payload_start_free(payload);
- if (group)
- silc_ske_group_free(group);
- 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 (status == SILC_SKE_STATUS_OK)
- status = SILC_SKE_STATUS_ERROR;
-
- /** Error */
- ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
-}
-
-/* Phase-2. Send KE payload */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase2)
-{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- SilcBuffer payload_buf;
- SilcMPInt *x;
- SilcSKEKEPayload payload;
- SilcUInt32 pk_len;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* 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;
- }
-
- /* Encode the result to Key Exchange 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 */
- 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 = silc_pkcs_get_type(ske->public_key);
-
- /* Compute signature data if we are doing mutual authentication */
- if (ske->private_key && ske->prop->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"));
-
- /* 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 */
- if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
- sizeof(sign) - 1, &sign_len, FALSE, ske->prop->hash)) {
- /** 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);
- if (payload->sign_data)
- payload->sign_len = sign_len;
- memset(sign, 0, sizeof(sign));
- }
-
- 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);
ske->ke1_payload = NULL;
ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
+ return status;
}
ske->x = x;
- /* Check for backwards compatibility */
-
/* Send the packet. */
- if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE_1, 0,
- silc_buffer_data(payload_buf),
- silc_buffer_len(payload_buf))) {
- /** Error sending packet */
- SILC_LOG_DEBUG(("Error sending packet"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ if (ske->callbacks->send_packet)
+ (*ske->callbacks->send_packet)(ske, payload_buf,
+ SILC_PACKET_KEY_EXCHANGE_1,
+ ske->callbacks->context);
silc_buffer_free(payload_buf);
- /** Waiting responder's KE payload */
- silc_fsm_next(fsm, silc_ske_st_initiator_phase3);
- return SILC_FSM_WAIT;
+ return status;
}
-/* Phase-3. Process responder's KE payload */
+/* An initiator finish final callback that is called to indicate that
+ the SKE protocol may continue. */
-SILC_FSM_STATE(silc_ske_st_initiator_phase3)
+static void silc_ske_initiator_finish_final(SilcSKE ske,
+ SilcSKEStatus status,
+ void *context)
{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- SilcSKEKEPayload payload;
- SilcMPInt *KEY;
- SilcBuffer packet_buf = &ske->packet->buffer;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (ske->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
- SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
- silc_ske_install_retransmission(ske);
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- return SILC_FSM_WAIT;
- }
-
- /* Decode the payload */
- status = silc_ske_payload_ke_decode(ske, packet_buf, &payload);
- if (status != SILC_SKE_STATUS_OK) {
- /** Error decoding KE payload */
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- ske->ke2_payload = payload;
+ SilcSKEKEPayload *payload;
+ unsigned char hash[SILC_HASH_MAXLEN];
+ SilcUInt32 hash_len;
+ SilcPublicKey public_key = NULL;
- if (!payload->pk_data && (ske->callbacks->verify_key || ske->repository)) {
- 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 the SKE was freed during the async call then free it really now,
+ otherwise just decrement the reference counter. */
+ if (ske->status == SILC_SKE_STATUS_FREED) {
+ silc_ske_free(ske);
+ return;
}
- SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
+ /* If the caller returns PENDING status SKE library will assume that
+ the caller will re-call this callback when it is not anymore in
+ PENDING status. */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
- /* 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;
+ ske->users--;
+ payload = ske->ke2_payload;
- /* Decode the remote's public key */
- if (payload->pk_data &&
- !silc_pkcs_public_key_alloc(payload->pk_type,
- payload->pk_data, payload->pk_len,
- &ske->prop->public_key)) {
- SILC_LOG_ERROR(("Unsupported/malformed public key received"));
- status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
- goto err;
+ /* If the status is an error then the public key that was verified
+ by the caller is not authentic. */
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
}
- if (ske->prop->public_key && (ske->callbacks->verify_key ||
- ske->repository)) {
- SILC_LOG_DEBUG(("Verifying public key"));
-
- /** Waiting public key verification */
- silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
-
- /* If repository is provided, verify the key from there. */
- if (ske->repository) {
- SilcSKRFind find;
-
- find = silc_skr_find_alloc();
- if (!find) {
- status = SILC_SKE_STATUS_OUT_OF_MEMORY;
- goto err;
- }
- silc_skr_find_set_pkcs_type(find,
- silc_pkcs_get_type(ske->prop->public_key));
- silc_skr_find_set_public_key(find, ske->prop->public_key);
- silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT);
-
- /* Find key from repository */
- SILC_FSM_CALL(silc_skr_find(ske->repository, find,
- silc_ske_skr_callback, ske));
- } else {
- /* Verify from application */
- SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key,
- ske->callbacks->context,
- silc_ske_pk_verified, NULL));
+ if (payload->pk_data) {
+ /* Decode the public key */
+ if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
+ &public_key)) {
+ status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+ SILC_LOG_ERROR(("Unsupported/malformed public key received"));
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
}
- /* NOT REACHED */
- }
-
- /** 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;
-}
-
-/* Process key material */
-
-SILC_FSM_STATE(silc_ske_st_initiator_phase4)
-{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- SilcSKEKEPayload payload;
- unsigned char hash[SILC_HASH_MAXLEN];
- SilcUInt32 hash_len;
- int key_len, block_len;
-
- if (ske->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
- return SILC_FSM_CONTINUE;
- }
-
- /* 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;
- }
-
- payload = ske->ke2_payload;
- if (ske->prop->public_key) {
SILC_LOG_DEBUG(("Public key is authentic"));
/* Compute the hash value */
if (status != SILC_SKE_STATUS_OK)
goto err;
+ ske->hash = silc_memdup(hash, hash_len);
+ ske->hash_len = hash_len;
+
SILC_LOG_DEBUG(("Verifying signature (HASH)"));
/* Verify signature */
- if (!silc_pkcs_verify(ske->prop->public_key, payload->sign_data,
- payload->sign_len, hash, hash_len, NULL)) {
+ 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;
SILC_LOG_DEBUG(("Signature is Ok"));
- ske->hash = silc_memdup(hash, hash_len);
- ske->hash_len = hash_len;
+ silc_pkcs_public_key_free(public_key);
memset(hash, 'F', hash_len);
}
ske->status = SILC_SKE_STATUS_OK;
- /* In case we are doing rekey move to finish it. */
- if (ske->rekey) {
- /** Finish rekey */
- silc_fsm_next(fsm, silc_ske_st_rekey_initiator_done);
- return SILC_FSM_CONTINUE;
- }
-
- /* Process key material */
- key_len = silc_cipher_get_key_len(ske->prop->cipher);
- block_len = silc_cipher_get_block_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,
- &ske->rekey);
- if (!ske->keymat) {
- SILC_LOG_ERROR(("Error processing key material"));
- status = SILC_SKE_STATUS_ERROR;
- goto err;
- }
-
- /* Send SUCCESS packet */
- SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, hash);
- if (!silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, hash, 4)) {
- /** Error sending packet */
- SILC_LOG_DEBUG(("Error sending packet"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ /* Call the callback. The caller may now continue the SKE protocol. */
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
- /** Waiting completion */
- silc_fsm_next(fsm, silc_ske_st_initiator_end);
- return SILC_FSM_WAIT;
+ return;
err:
memset(hash, 'F', sizeof(hash));
silc_free(ske->KEY);
ske->KEY = NULL;
+ if (public_key)
+ silc_pkcs_public_key_free(public_key);
+
if (ske->hash) {
memset(ske->hash, 'F', hash_len);
silc_free(ske->hash);
}
if (status == SILC_SKE_STATUS_OK)
- status = SILC_SKE_STATUS_ERROR;
+ ske->status = SILC_SKE_STATUS_ERROR;
- /** Error */
ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
-}
-/* Protocol completed */
+ /* Call the callback. */
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+}
-SILC_FSM_STATE(silc_ske_st_initiator_end)
+/* Receives Key Exchange Payload from responder consisting responders
+ public key, f, and signature. This function verifies the public key,
+ computes the secret shared key and verifies the signature.
+
+ The `proto_continue' will be called to indicate that the caller may
+ continue with the SKE protocol. The caller must not continue
+ before the SKE libary has called that callback. If this function
+ returns an error the callback will not be called. It is called
+ if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
+ However, note that when the library calls the callback the ske->status
+ may be error.
+
+ This calls the `verify_key' callback to verify the received public
+ key or certificate. If the `verify_key' is provided then the remote
+ must send public key and it is considered to be an error if remote
+ does not send its public key. If caller is performing a re-key with
+ SKE then the `verify_key' is usually not provided when it is not also
+ required for the remote to send its public key. */
+
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+ SilcBuffer ke_payload)
{
- SilcSKE ske = fsm_context;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEKEPayload *payload;
+ SilcMPInt *KEY;
SILC_LOG_DEBUG(("Start"));
- if (ske->packet->type != SILC_PACKET_SUCCESS) {
- SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
- silc_ske_install_retransmission(ske);
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- return SILC_FSM_WAIT;
+ /* Decode the payload */
+ status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ return status;
}
+ ske->ke2_payload = payload;
- SILC_LOG_DEBUG(("Key exchange completed successfully"));
-
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
-
- /* Call completion */
- silc_ske_completion(ske);
-
- return SILC_FSM_FINISH;
-}
-
-/* Aborted by application */
-
-SILC_FSM_STATE(silc_ske_st_initiator_aborted)
-{
- SilcSKE ske = fsm_context;
- unsigned char data[4];
-
- SILC_LOG_DEBUG(("Aborted by caller"));
-
- /* Send FAILURE packet */
- SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, data);
- silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, data, 4);
-
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
-
- /* Call completion */
- silc_ske_completion(ske);
-
- return SILC_FSM_FINISH;
-}
-
-/* Error occurred. Send error to remote host */
-
-SILC_FSM_STATE(silc_ske_st_initiator_error)
-{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- unsigned char data[4];
-
- SILC_LOG_DEBUG(("Error %s (%d) occurred during key exchange",
- silc_ske_map_status(ske->status), ske->status));
-
- status = ske->status;
- if (status > SILC_SKE_STATUS_INVALID_COOKIE)
- status = SILC_SKE_STATUS_ERROR;
-
- /* Send FAILURE packet */
- SILC_PUT32_MSB((SilcUInt32)status, data);
- silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, data, 4);
-
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
-
- /* Call completion */
- silc_ske_completion(ske);
-
- return SILC_FSM_FINISH;
-}
-
-/* Failure received from remote */
-
-SILC_FSM_STATE(silc_ske_st_initiator_failure)
-{
- SilcSKE ske = fsm_context;
- SilcUInt32 error = SILC_SKE_STATUS_ERROR;
-
- SILC_LOG_DEBUG(("Error %s (%d) received during key exchange",
- silc_ske_map_status(ske->status), ske->status));
-
- if (ske->packet && silc_buffer_len(&ske->packet->buffer) == 4) {
- SILC_GET32_MSB(error, ske->packet->buffer.data);
- ske->status = error;
- silc_packet_free(ske->packet);
- ske->packet = NULL;
+ 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_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
-
- /* Call completion */
- silc_ske_completion(ske);
-
- return SILC_FSM_FINISH;
-}
-
-/* Starts the protocol as initiator */
-
-SilcAsyncOperation silc_ske_initiator(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKEParams params,
- SilcSKEStartPayload start_payload)
-{
- SILC_LOG_DEBUG(("Start SKE as initiator"));
-
- if (!ske || !stream || !params || !params->version)
- return NULL;
+ SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
- if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
- return NULL;
+ /* 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 (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
- return NULL;
+ if (payload->pk_data && ske->callbacks->verify_key) {
+ SILC_LOG_DEBUG(("Verifying public key"));
- if (params->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
- ske->session_port = params->session_port;
+ ske->users++;
+ (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
+ payload->pk_type, ske->callbacks->context,
+ silc_ske_initiator_finish_final, NULL);
- /* Generate security properties if not provided */
- if (!start_payload) {
- start_payload = silc_ske_assemble_security_properties(ske,
- params->flags,
- params->version);
- if (!start_payload)
- return NULL;
+ /* We will continue to the final state after the public key has
+ been verified by the caller. */
+ return SILC_SKE_STATUS_PENDING;
}
- ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
- ske->start_payload = start_payload;
- ske->version = params->version;
- ske->running = TRUE;
-
- /* 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 *********************************/
+ /* Continue to final state */
+ ske->users++;
+ silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
-/* Start protocol as responder. Wait initiator's start payload */
-
-SILC_FSM_STATE(silc_ske_st_responder_start)
-{
- SilcSKE ske = fsm_context;
+ return SILC_SKE_STATUS_OK;
- SILC_LOG_DEBUG(("Start"));
+ err:
+ silc_ske_payload_ke_free(payload);
+ ske->ke2_payload = NULL;
- if (ske->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_ske_st_responder_aborted);
- return SILC_FSM_CONTINUE;
- }
+ silc_mp_uninit(ske->KEY);
+ silc_free(ske->KEY);
+ ske->KEY = NULL;
- /* Add key exchange timeout */
- silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
- ske, ske->timeout, 0);
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
- /** Wait for initiator */
- silc_fsm_next(fsm, silc_ske_st_responder_phase1);
- return SILC_FSM_WAIT;
+ ske->status = status;
+ return status;
}
-/* Decode initiator's start payload. Select the security properties from
- the initiator's start payload and send our reply start payload back. */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase1)
+/* Starts Key Exchange protocol for responder. Responder receives
+ Key Exchange Start Payload from initiator consisting of all the
+ security properties the initiator supports. This function decodes
+ the payload and parses the payload further and selects the right
+ security properties. */
+
+SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ const char *version,
+ SilcBuffer start_payload,
+ SilcSKESecurityPropertyFlag flags)
{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- SilcSKEStartPayload remote_payload = NULL;
- SilcBuffer packet_buf = &ske->packet->buffer;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
SILC_LOG_DEBUG(("Start"));
+ ske->sock = sock;
+ ske->rng = rng;
+
/* Decode the payload */
- status = silc_ske_payload_start_decode(ske, packet_buf, &remote_payload);
+ status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
if (status != SILC_SKE_STATUS_OK) {
- /** Error decoding Start Payload */
- silc_packet_free(ske->packet);
- ske->packet = NULL;
ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ return status;
}
/* 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);
-
- silc_packet_free(ske->packet);
- ske->packet = NULL;
+ ske->start_payload_copy = silc_buffer_copy(start_payload);
/* Force the mutual authentication flag if we want to do it. */
- if (ske->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+ if (flags & SILC_SKE_SP_FLAG_MUTUAL) {
SILC_LOG_DEBUG(("Force mutual authentication"));
remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
}
/* Force PFS flag if we require it */
- if (ske->flags & SILC_SKE_SP_FLAG_PFS) {
+ if (flags & SILC_SKE_SP_FLAG_PFS) {
SILC_LOG_DEBUG(("Force PFS"));
remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
}
/* Disable IV Included flag if requested */
if (remote_payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED &&
- !(ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) {
+ !(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;
}
- /* Check and select security properties */
- status = silc_ske_select_security_properties(ske, remote_payload,
- &ske->prop);
- if (status != SILC_SKE_STATUS_OK) {
- /** Error selecting proposal */
- silc_ske_payload_start_free(remote_payload);
- ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
- }
-
- silc_ske_payload_start_free(remote_payload);
-
- /* Encode our reply payload to send the selected security properties */
- status = silc_ske_payload_start_encode(ske, ske->start_payload,
- &packet_buf);
+ /* Parse and select the security properties from the payload */
+ payload = silc_calloc(1, sizeof(*payload));
+ status = silc_ske_select_security_properties(ske, version,
+ payload, remote_payload);
if (status != SILC_SKE_STATUS_OK)
goto err;
- /* Send the packet. */
- if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE, 0,
- silc_buffer_data(packet_buf),
- silc_buffer_len(packet_buf)))
- goto err;
+ ske->start_payload = payload;
- silc_buffer_free(packet_buf);
+ /* Call the callback function. */
+ if (ske->callbacks->payload_receive)
+ (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
- /** Waiting initiator's KE payload */
- silc_fsm_next(fsm, silc_ske_st_responder_phase2);
- return SILC_FSM_WAIT;
+ silc_ske_payload_start_free(remote_payload);
+
+ return status;
err:
- if (ske->prop->group)
- silc_ske_group_free(ske->prop->group);
- 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);
- ske->prop = NULL;
+ if (remote_payload)
+ silc_ske_payload_start_free(remote_payload);
+ silc_free(payload);
if (status == SILC_SKE_STATUS_OK)
- status = SILC_SKE_STATUS_ERROR;
+ return SILC_SKE_STATUS_ERROR;
- /** Error */
ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ return status;
}
-/* Phase-2. Decode initiator's KE payload */
+/* The selected security properties from the initiator payload is now
+ encoded into Key Exchange Start Payload and sent to the initiator. */
-SILC_FSM_STATE(silc_ske_st_responder_phase2)
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske)
{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- SilcSKEKEPayload recv_payload;
- SilcBuffer packet_buf = &ske->packet->buffer;
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+ SilcSKESecurityProperties prop;
+ SilcSKEDiffieHellmanGroup group = NULL;
SILC_LOG_DEBUG(("Start"));
- if (ske->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
- SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
- silc_ske_install_retransmission(ske);
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- return SILC_FSM_WAIT;
+ /* 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));
+ 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;
+
+ prop->group = group;
+
+ if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list,
+ &prop->pkcs) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+ goto err;
}
- /* 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->packet = NULL;
- ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ if (silc_cipher_alloc(ske->start_payload->enc_alg_list,
+ &prop->cipher) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+ goto err;
}
- ske->ke1_payload = recv_payload;
+ if (silc_hash_alloc(ske->start_payload->hash_alg_list,
+ &prop->hash) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+ goto err;
+ }
- silc_packet_free(ske->packet);
- ske->packet = NULL;
+ if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
+ &prop->hmac) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HMAC;
+ goto err;
+ }
- /* 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) {
+ /* Encode the payload */
+ status = silc_ske_payload_start_encode(ske, ske->start_payload,
+ &payload_buf);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
- SILC_LOG_DEBUG(("We are doing mutual authentication"));
+ /* Send the packet. */
+ if (ske->callbacks->send_packet)
+ (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
+ ske->callbacks->context);
- if (!recv_payload->pk_data && (ske->callbacks->verify_key ||
- ske->repository)) {
- /** 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;
- }
+ silc_buffer_free(payload_buf);
- /* Decode the remote's public key */
- if (recv_payload->pk_data &&
- !silc_pkcs_public_key_alloc(recv_payload->pk_type,
- recv_payload->pk_data,
- recv_payload->pk_len,
- &ske->prop->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;
- }
+ return status;
- if (ske->prop->public_key && (ske->callbacks->verify_key ||
- ske->repository)) {
- SILC_LOG_DEBUG(("Verifying public key"));
+ err:
+ if (group)
+ silc_ske_group_free(group);
- /** Waiting public key verification */
- silc_fsm_next(fsm, silc_ske_st_responder_phase4);
-
- /* If repository is provided, verify the key from there. */
- if (ske->repository) {
- SilcSKRFind find;
-
- find = silc_skr_find_alloc();
- if (!find) {
- ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
- }
- silc_skr_find_set_pkcs_type(find,
- silc_pkcs_get_type(ske->prop->public_key));
- silc_skr_find_set_public_key(find, ske->prop->public_key);
- silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT);
-
- /* Find key from repository */
- SILC_FSM_CALL(silc_skr_find(ske->repository, find,
- silc_ske_skr_callback, ske));
- } else {
- /* Verify from application */
- SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key,
- ske->callbacks->context,
- silc_ske_pk_verified, NULL));
- }
- /* NOT REACHED */
- }
- }
+ 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 (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
- /** Generate KE2 payload */
- silc_fsm_next(fsm, silc_ske_st_responder_phase4);
- return SILC_FSM_CONTINUE;
+ ske->status = status;
+ return status;
}
-/* Phase-4. Generate KE2 payload */
+/* An responder phase 2 final callback that is called to indicate that
+ the SKE protocol may continue. */
-SILC_FSM_STATE(silc_ske_st_responder_phase4)
+static void silc_ske_responder_phase2_final(SilcSKE ske,
+ SilcSKEStatus status,
+ void *context)
{
- SilcSKE ske = fsm_context;
- SilcSKEStatus status;
- SilcSKEKEPayload recv_payload, send_payload;
- SilcMPInt *x, *KEY;
+ SilcSKEKEPayload *recv_payload, *send_payload;
+ SilcMPInt *x;
- if (ske->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_ske_st_responder_aborted);
- return SILC_FSM_CONTINUE;
+ /* If the SKE was freed during the async call then free it really now,
+ otherwise just decrement the reference counter. */
+ if (ske->status == SILC_SKE_STATUS_FREED) {
+ silc_ske_free(ske);
+ return;
}
- /* 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;
- }
+ /* If the caller returns PENDING status SKE library will assume that
+ the caller will re-call this callback when it is not anymore in
+ PENDING status. */
+ if (status == SILC_SKE_STATUS_PENDING)
+ return;
+ ske->users--;
recv_payload = ske->ke1_payload;
+ /* If the status is an error then the public key that was verified
+ by the caller is not authentic. */
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
+ }
+
/* 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)) {
+ ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+ SILC_LOG_ERROR(("Unsupported/malformed public key received"));
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
+ }
+
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;
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
}
SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
/* Verify signature */
- if (!silc_pkcs_verify(ske->prop->public_key, recv_payload->sign_data,
- recv_payload->sign_len, hash, hash_len, NULL)) {
- /** Incorrect 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) {
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;
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
}
SILC_LOG_DEBUG(("Signature is Ok"));
+ silc_pkcs_public_key_free(public_key);
memset(hash, 'F', hash_len);
}
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;
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+ return;
}
/* Save the results for later processing */
silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
&ske->prop->group->group);
+ /* Call the callback. The caller may now continue with the SKE protocol. */
+ ske->status = SILC_SKE_STATUS_OK;
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+}
+
+/* This function receives the Key Exchange Payload from the initiator.
+ This also performs the mutual authentication if required. Then, this
+ function first generated a random number x, such that 1 < x < q
+ and computes f = g ^ x mod p. This then puts the result f to a Key
+ Exchange Payload.
+
+ The `proto_continue' will be called to indicate that the caller may
+ continue with the SKE protocol. The caller must not continue
+ before the SKE libary has called that callback. If this function
+ returns an error the callback will not be called. It is called
+ if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
+ However, note that when the library calls the callback the ske->status
+ may be error.
+
+ This calls the `verify_key' callback to verify the received public
+ key or certificate if the Mutual Authentication flag is set. If the
+ `verify_key' is provided then the remote must send public key and it
+ is considered to be an error if remote does not send its public key. */
+
+SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+ SilcBuffer ke_payload)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEKEPayload *recv_payload;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode Key Exchange Payload */
+ status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ return status;
+ }
+
+ ske->ke1_payload = recv_payload;
+
+ /* 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) {
+ 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;
+ return status;
+ }
+
+ if (recv_payload->pk_data && ske->callbacks->verify_key) {
+ SILC_LOG_DEBUG(("Verifying public key"));
+
+ ske->users++;
+ (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
+ recv_payload->pk_len,
+ recv_payload->pk_type,
+ ske->callbacks->context,
+ silc_ske_responder_phase2_final, NULL);
+
+ /* We will continue to the final state after the public key has
+ been verified by the caller. */
+ return SILC_SKE_STATUS_PENDING;
+ }
+ }
+
+ /* Continue to final state */
+ ske->users++;
+ silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* This functions generates the secret key KEY = e ^ x mod p, and, a hash
+ value to be signed and sent to the other end. This then encodes Key
+ Exchange Payload and sends it to the other end. */
+
+SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcSKEPKType pk_type)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer payload_buf;
+ SilcMPInt *KEY;
+ unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1], *pk;
+ SilcUInt32 hash_len, sign_len, pk_len;
+
+ SILC_LOG_DEBUG(("Start"));
+
SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
/* Compute the shared secret key */
&ske->prop->group->group);
ske->KEY = KEY;
- /** Send KE2 payload */
- silc_fsm_next(fsm, silc_ske_st_responder_phase5);
- return SILC_FSM_CONTINUE;
+ if (public_key && private_key) {
+ SILC_LOG_DEBUG(("Getting public key"));
+
+ /* Get the public key */
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+ if (!pk) {
+ status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
+ ske->ke2_payload->pk_data = pk;
+ ske->ke2_payload->pk_len = pk_len;
+
+ SILC_LOG_DEBUG(("Computing HASH value"));
+
+ /* 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)
+ goto err;
+
+ ske->hash = silc_memdup(hash, hash_len);
+ ske->hash_len = hash_len;
+
+ SILC_LOG_DEBUG(("Signing HASH value"));
+
+ /* Sign the hash value */
+ silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
+ 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)) {
+ status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+ goto err;
+ }
+ 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 = pk_type;
+
+ /* Encode the Key Exchange Payload */
+ status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
+ &payload_buf);
+ if (status != SILC_SKE_STATUS_OK)
+ goto err;
+
+ /* Send the packet. */
+ if (ske->callbacks->send_packet)
+ (*ske->callbacks->send_packet)(ske, payload_buf,
+ SILC_PACKET_KEY_EXCHANGE_2,
+ ske->callbacks->context);
+
+ silc_buffer_free(payload_buf);
+
+ return status;
+
+ err:
+ silc_mp_uninit(ske->KEY);
+ silc_free(ske->KEY);
+ ske->KEY = NULL;
+ silc_ske_payload_ke_free(ske->ke2_payload);
+
+ if (status == SILC_SKE_STATUS_OK)
+ return SILC_SKE_STATUS_ERROR;
+
+ ske->status = status;
+ return status;
+}
+
+/* The Key Exchange protocol is ended by calling this function. This
+ must not be called until the keys are processed like the protocol
+ defines. This function is for both initiator and responder. */
+
+SilcSKEStatus silc_ske_end(SilcSKE ske)
+{
+ SilcBufferStruct packet;
+ unsigned char data[4];
+
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, data);
+ silc_buffer_set(&packet, data, 4);
+
+ if (ske->callbacks->send_packet)
+ (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_SUCCESS,
+ ske->callbacks->context);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* Aborts the Key Exchange protocol. This is called if error occurs
+ while performing the protocol. The status argument is the error
+ status and it is sent to the remote end. */
+
+SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
+{
+ SilcBufferStruct packet;
+ unsigned char data[4];
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (status > SILC_SKE_STATUS_INVALID_COOKIE)
+ status = SILC_SKE_STATUS_BAD_PAYLOAD;
+
+ SILC_PUT32_MSB((SilcUInt32)status, data);
+ silc_buffer_set(&packet, data, 4);
+
+ if (ske->callbacks->send_packet)
+ (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_FAILURE,
+ ske->callbacks->context);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* 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 protocol and not
+ by the protocol itself. */
+
+SilcSKEStatus
+silc_ske_assemble_security_properties(SilcSKE ske,
+ SilcSKESecurityPropertyFlag flags,
+ const char *version,
+ SilcSKEStartPayload **return_payload)
+{
+ SilcSKEStartPayload *rp;
+ int i;
+
+ SILC_LOG_DEBUG(("Assembling KE Start Payload"));
+
+ rp = silc_calloc(1, sizeof(*rp));
+
+ /* Set flags */
+ rp->flags = (unsigned char)flags;
+
+ /* 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;
+
+ /* Put version */
+ rp->version = strdup(version);
+ rp->version_len = strlen(version);
+
+ /* Get supported Key Exhange groups */
+ rp->ke_grp_list = silc_ske_get_supported_groups();
+ rp->ke_grp_len = strlen(rp->ke_grp_list);
+
+ /* Get supported PKCS algorithms */
+ rp->pkcs_alg_list = silc_pkcs_get_supported();
+ rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
+
+ /* Get supported encryption algorithms */
+ rp->enc_alg_list = silc_cipher_get_supported();
+ rp->enc_alg_len = strlen(rp->enc_alg_list);
+
+ /* Get supported hash algorithms */
+ rp->hash_alg_list = silc_hash_get_supported();
+ rp->hash_alg_len = strlen(rp->hash_alg_list);
+
+ /* Get supported HMACs */
+ rp->hmac_alg_list = silc_hmac_get_supported();
+ rp->hmac_alg_len = strlen(rp->hmac_alg_list);
+
+ /* XXX */
+ /* Get supported compression algorithms */
+ rp->comp_alg_list = strdup("none");
+ rp->comp_alg_len = strlen("none");
+
+ 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_payload = rp;
+
+ return SILC_SKE_STATUS_OK;
}
-/* Phase-5. Send KE2 payload */
+/* Selects the supported security properties from the remote end's Key
+ Exchange Start Payload. */
-SILC_FSM_STATE(silc_ske_st_responder_phase5)
+SilcSKEStatus
+silc_ske_select_security_properties(SilcSKE ske,
+ const char *version,
+ SilcSKEStartPayload *payload,
+ SilcSKEStartPayload *remote_payload)
{
- 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;
+ SilcSKEStartPayload *rp;
+ char *cp;
+ int len;
+
+ SILC_LOG_DEBUG(("Parsing KE Start Payload"));
+
+ rp = remote_payload;
+
+ /* Check version string */
+ if (ske->callbacks->check_version) {
+ status = ske->callbacks->check_version(ske, rp->version,
+ rp->version_len,
+ ske->callbacks->context);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ return status;
+ }
+ }
+
+ ske->remote_version = silc_memdup(rp->version, rp->version_len);
+
+ /* 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));
+ payload->cookie_len = SILC_SKE_COOKIE_LEN;
+ memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
- SILC_LOG_DEBUG(("Start"));
+ /* Put our version to our reply */
+ payload->version = strdup(version);
+ payload->version_len = strlen(version);
- if (ske->public_key && ske->private_key) {
- SILC_LOG_DEBUG(("Getting public key"));
+ /* Get supported Key Exchange groups */
+ cp = rp->ke_grp_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
- /* 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;
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
- SILC_LOG_DEBUG(("Computing HASH value"));
+ SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
- /* 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;
- }
+ if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
+ SILC_LOG_DEBUG(("Found KE group `%s'", item));
- ske->hash = silc_memdup(hash, hash_len);
- ske->hash_len = hash_len;
+ payload->ke_grp_len = len;
+ payload->ke_grp_list = item;
+ break;
+ }
- SILC_LOG_DEBUG(("Signing HASH value"));
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
- /* Sign the hash value */
- if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
- sizeof(sign) - 1, &sign_len, FALSE, ske->prop->hash)) {
- /** Error computing signature */
- status = SILC_SKE_STATUS_SIGNATURE_ERROR;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ if (item)
+ silc_free(item);
}
- 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 = silc_pkcs_get_type(ske->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;
- }
-
- /* Send the packet. */
- if (!silc_ske_packet_send(ske, SILC_PACKET_KEY_EXCHANGE_2, 0,
- payload_buf->data, silc_buffer_len(payload_buf))) {
- SILC_LOG_DEBUG(("Error sending packet"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
- }
- silc_buffer_free(payload_buf);
+ 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 {
- /** Waiting completion */
- silc_fsm_next(fsm, silc_ske_st_responder_end);
- return SILC_FSM_WAIT;
-}
+ if (!rp->ke_grp_len) {
+ SILC_LOG_DEBUG(("KE group not defined in payload"));
+ silc_free(payload);
+ return SILC_SKE_STATUS_BAD_PAYLOAD;
+ }
-/* Protocol completed */
+ SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
+ SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
-SILC_FSM_STATE(silc_ske_st_responder_end)
-{
- SilcSKE ske = fsm_context;
- unsigned char tmp[4];
- SilcUInt32 hash_len, key_len, block_len;
-
- if (ske->packet->type != SILC_PACKET_SUCCESS) {
- SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
- silc_ske_install_retransmission(ske);
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- return SILC_FSM_WAIT;
- }
- silc_packet_free(ske->packet);
- ske->packet = NULL;
-
- /* Process key material */
- key_len = silc_cipher_get_key_len(ske->prop->cipher);
- block_len = silc_cipher_get_block_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,
- &ske->rekey);
- 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;
+ payload->ke_grp_len = rp->ke_grp_len;
+ payload->ke_grp_list = strdup(rp->ke_grp_list);
}
- /* Send SUCCESS packet */
- SILC_PUT32_MSB(SILC_SKE_STATUS_OK, tmp);
- silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, tmp, 4);
+ /* Get supported PKCS algorithms */
+ cp = rp->pkcs_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
- /* Call completion */
- silc_ske_completion(ske);
+ SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
- return SILC_FSM_FINISH;
-}
+ if (silc_pkcs_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
-/* Aborted by application */
+ payload->pkcs_alg_len = len;
+ payload->pkcs_alg_list = item;
+ break;
+ }
-SILC_FSM_STATE(silc_ske_st_responder_aborted)
-{
- SilcSKE ske = fsm_context;
- unsigned char tmp[4];
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
- SILC_LOG_DEBUG(("Key exchange protocol aborted"));
+ if (item)
+ silc_free(item);
+ }
- /* Send FAILURE packet */
- SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, tmp);
- silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, tmp, 4);
+ 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 {
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
+ 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;
+ }
- /* Call completion */
- silc_ske_completion(ske);
+ SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
+ SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
- return SILC_FSM_FINISH;
-}
+ payload->pkcs_alg_len = rp->pkcs_alg_len;
+ payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
+ }
-/* Failure received from remote */
+ /* Get supported encryption algorithms */
+ cp = rp->enc_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
-SILC_FSM_STATE(silc_ske_st_responder_failure)
-{
- SilcSKE ske = fsm_context;
- SilcUInt32 error = SILC_SKE_STATUS_ERROR;
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
- SILC_LOG_DEBUG(("Key exchange protocol failed"));
+ SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
- if (ske->packet && silc_buffer_len(&ske->packet->buffer) == 4) {
- SILC_GET32_MSB(error, ske->packet->buffer.data);
- ske->status = error;
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- }
+ if (silc_cipher_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
+ payload->enc_alg_len = len;
+ payload->enc_alg_list = item;
+ break;
+ }
- /* Call completion */
- silc_ske_completion(ske);
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
- return SILC_FSM_FINISH;
-}
+ if (item)
+ silc_free(item);
+ }
-/* Error occurred */
+ 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_FSM_STATE(silc_ske_st_responder_error)
-{
- SilcSKE ske = fsm_context;
- unsigned char tmp[4];
+ 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;
+ }
- SILC_LOG_DEBUG(("Error %d (%s) during key exchange protocol",
- ske->status, silc_ske_map_status(ske->status)));
+ SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
+ rp->enc_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_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, tmp, 4);
+ payload->enc_alg_len = rp->enc_alg_len;
+ payload->enc_alg_list = strdup(rp->enc_alg_list);
+ }
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
+ /* Get supported hash algorithms */
+ cp = rp->hash_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
- /* Call completion */
- silc_ske_completion(ske);
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
- return SILC_FSM_FINISH;
-}
+ SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
-/* Starts the protocol as responder. */
+ if (silc_hash_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found hash alg `%s'", item));
-SilcAsyncOperation silc_ske_responder(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKEParams params)
-{
- SILC_LOG_DEBUG(("Start SKE as responder"));
+ payload->hash_alg_len = len;
+ payload->hash_alg_list = item;
+ break;
+ }
- if (!ske || !stream || !params || !params->version)
- return NULL;
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
- if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
- return NULL;
+ if (item)
+ silc_free(item);
+ }
- if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
- return NULL;
+ 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 {
- ske->responder = TRUE;
- ske->flags = params->flags;
- ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
- if (ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
- ske->session_port = params->session_port;
- ske->version = strdup(params->version);
- if (!ske->version)
- return NULL;
- ske->running = TRUE;
+ 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;
+ }
- /* 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);
+ SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
+ rp->hash_alg_list));
- /* Start SKE as responder */
- silc_fsm_start(&ske->fsm, silc_ske_st_responder_start);
+ payload->hash_alg_len = rp->hash_alg_len;
+ payload->hash_alg_list = strdup(rp->hash_alg_list);
+ }
- return &ske->op;
-}
+ /* Get supported HMACs */
+ cp = rp->hmac_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
-/***************************** Initiator Rekey ******************************/
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
-/* Start rekey */
+ SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_start)
-{
- SilcSKE ske = fsm_context;
- SilcStatus status;
+ if (silc_hmac_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found HMAC `%s'", item));
- SILC_LOG_DEBUG(("Start rekey (%s)", ske->rekey->pfs ? "PFS" : "No PFS"));
+ payload->hmac_alg_len = len;
+ payload->hmac_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++;
- /* Add rekey exchange timeout */
- silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout,
- ske, 30, 0);
+ if (item)
+ silc_free(item);
+ }
- ske->prop = silc_calloc(1, sizeof(*ske->prop));
- if (!ske->prop) {
- /** No memory */
- ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ 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 {
- /* Send REKEY packet to start rekey protocol */
- if (!silc_ske_packet_send(ske, SILC_PACKET_REKEY, 0, NULL, 0)) {
- /** Error sending packet */
- SILC_LOG_DEBUG(("Error sending packet"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ 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 doing rekey without PFS, move directly to the end of the protocol. */
- if (!ske->rekey->pfs) {
- /** Rekey without PFS */
- silc_fsm_next(fsm, silc_ske_st_rekey_initiator_done);
- return SILC_FSM_CONTINUE;
- }
+ SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
+ rp->hmac_alg_list));
- status = silc_ske_group_get_by_number(ske->rekey->ske_group,
- &ske->prop->group);
- if (status != SILC_SKE_STATUS_OK) {
- /** Unknown group */
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
+ payload->hmac_alg_len = rp->hmac_alg_len;
+ payload->hmac_alg_list = strdup(rp->hmac_alg_list);
}
- /** Rekey with PFS */
- silc_fsm_next(fsm, silc_ske_st_initiator_phase2);
- return SILC_FSM_CONTINUE;
-}
+ /* Get supported compression algorithms */
+ cp = rp->comp_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
-/* Sends REKEY_DONE packet to finish the protocol. */
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_done)
-{
- SilcSKE ske = fsm_context;
- SilcCipher send_key;
- SilcHmac hmac_send;
- SilcHash hash;
- SilcUInt32 key_len, block_len, hash_len, x_len;
- unsigned char *pfsbuf;
+ SILC_LOG_DEBUG(("Proposed Compression `%s'", item));
- SILC_LOG_DEBUG(("Start"));
+#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_packet_get_keys(ske->stream, &send_key, NULL, &hmac_send, NULL);
- key_len = silc_cipher_get_key_len(send_key);
- block_len = silc_cipher_get_block_len(send_key);
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
- if (!silc_hash_alloc(ske->rekey->hash, &hash)) {
- /** Cannot allocate hash */
- ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
- hash_len = silc_hash_len(hash);
-
- /* Process key material */
- if (ske->rekey->pfs) {
- /* PFS */
- pfsbuf = silc_mp_mp2bin(ske->KEY, 0, &x_len);
- if (pfsbuf) {
- ske->keymat = silc_ske_process_key_material_data(pfsbuf, x_len,
- block_len, key_len,
- hash_len, hash);
- memset(pfsbuf, 0, x_len);
- silc_free(pfsbuf);
+ if (item)
+ silc_free(item);
}
- } else {
- /* No PFS */
- ske->keymat =
- silc_ske_process_key_material_data(ske->rekey->send_enc_key,
- ske->rekey->enc_key_len / 8,
- block_len, key_len,
- hash_len, hash);
}
- if (!ske->keymat) {
- SILC_LOG_ERROR(("Error processing key material"));
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
-
- ske->prop->cipher = send_key;
- ske->prop->hmac = hmac_send;
- ske->prop->hash = hash;
-
- /* Get sending keys */
- if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, &send_key, NULL,
- &hmac_send, NULL, NULL)) {
- /** Cannot get keys */
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
-
- /* Set the new keys into use. This will also send REKEY_DONE packet. Any
- packet sent after this call will be protected with the new keys. */
- if (!silc_packet_set_keys(ske->stream, send_key, NULL, hmac_send, NULL,
- TRUE)) {
- /** Cannot set keys */
- SILC_LOG_DEBUG(("Cannot set new keys, error sending REKEY_DONE"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ 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;
- /** Wait for REKEY_DONE */
- silc_fsm_next(fsm, silc_ske_st_rekey_initiator_end);
- return SILC_FSM_WAIT;
+ return SILC_SKE_STATUS_OK;
}
-/* Rekey protocol end */
+/* 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_initiator_end)
+static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
+ SilcUInt32 len,
+ SilcMPInt *rnd)
{
- SilcSKE ske = fsm_context;
- SilcCipher receive_key;
- SilcHmac hmac_receive;
- SilcSKERekeyMaterial rekey;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (ske->packet->type != SILC_PACKET_REKEY_DONE) {
- SILC_LOG_DEBUG(("Remote retransmitted an old packet"));
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- return SILC_FSM_WAIT;
- }
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ unsigned char *string;
+ SilcUInt32 l;
- silc_packet_get_keys(ske->stream, NULL, &receive_key, NULL, &hmac_receive);
- ske->prop->cipher = receive_key;
- ske->prop->hmac = hmac_receive;
+ if (!len)
+ return SILC_SKE_STATUS_ERROR;
- /* Get receiving keys */
- if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, NULL, &receive_key,
- NULL, &hmac_receive, NULL)) {
- /** Cannot get keys */
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ SILC_LOG_DEBUG(("Creating random number"));
- /* Set new receiving keys into use. All packets received after this will
- be decrypted with the new keys. */
- if (!silc_packet_set_keys(ske->stream, NULL, receive_key, NULL,
- hmac_receive, FALSE)) {
- /** Cannot set keys */
- SILC_LOG_DEBUG(("Cannot set new keys"));
- ske->status = SILC_SKE_STATUS_ERROR;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
+ l = ((len - 1) / 8);
- SILC_LOG_DEBUG(("Rekey completed successfully"));
+ /* Get the random number as string */
+ string = silc_rng_get_rn_data(ske->rng, l);
+ if (!string)
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
- /* Generate new rekey material */
- rekey = silc_ske_make_rekey_material(ske, ske->keymat);
- if (!rekey) {
- /** No memory */
- ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
- }
- rekey->pfs = ske->rekey->pfs;
- ske->rekey = rekey;
+ /* Decode the string into a MP integer */
+ silc_mp_bin2mp(string, l, rnd);
+ silc_mp_mod_2exp(rnd, rnd, len);
- ske->prop->cipher = NULL;
- ske->prop->hmac = NULL;
- silc_packet_free(ske->packet);
- ske->packet = NULL;
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
- silc_schedule_task_del_by_context(ske->schedule, ske);
+ /* 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;
- /* Call completion */
- silc_ske_completion(ske);
+ memset(string, 'F', l);
+ silc_free(string);
- return SILC_FSM_FINISH;
+ return status;
}
-/* Starts rekey protocol as initiator */
+/* 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. */
-SilcAsyncOperation
-silc_ske_rekey_initiator(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKERekeyMaterial rekey)
+static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
+ unsigned char *return_hash,
+ SilcUInt32 *return_hash_len,
+ int initiator)
{
- SILC_LOG_DEBUG(("Start SKE rekey as initator"));
-
- if (!ske || !stream || !rekey)
- return NULL;
-
- if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
- return NULL;
-
- if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
- return NULL;
-
- ske->rekey = rekey;
- ske->responder = FALSE;
- ske->running = TRUE;
- ske->rekeying = TRUE;
-
- /* 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_REKEY,
- SILC_PACKET_REKEY_DONE,
- SILC_PACKET_KEY_EXCHANGE_2,
- SILC_PACKET_SUCCESS,
- SILC_PACKET_FAILURE, -1);
-
- /* Start SKE rekey as initiator */
- silc_fsm_start(&ske->fsm, silc_ske_st_rekey_initiator_start);
-
- return &ske->op;
-}
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcBuffer buf;
+ unsigned char *e, *f, *KEY;
+ SilcUInt32 e_len, f_len, KEY_len;
+ int ret;
-/***************************** Responder Rekey ******************************/
+ SILC_LOG_DEBUG(("Start"));
-SILC_FSM_STATE(silc_ske_st_rekey_responder_start);
+ 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);
-SILC_FSM_STATE(silc_ske_st_rekey_responder_start)
-{
- return SILC_FSM_FINISH;
-}
+ /* Format the buffer used to compute the hash value */
+ buf = silc_buffer_alloc_size(ske->start_payload_copy->len +
+ 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;
-/* Starts rekey protocol as responder */
+ /* 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,
+ ske->start_payload_copy->
+ len),
+ 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,
+ ske->start_payload_copy->
+ len),
+ 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;
+ }
-SilcAsyncOperation
-silc_ske_rekey_responder(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKERekeyMaterial rekey)
-{
- SILC_LOG_DEBUG(("Start SKE rekey as responder"));
+ 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);
- if (!ske || !stream || !rekey)
- return NULL;
+ buf = silc_buffer_alloc_size(ske->start_payload_copy->len +
+ ske->ke1_payload->pk_len + e_len);
+ if (!buf)
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
- if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
- return NULL;
+ /* Format the buffer used to compute the hash value */
+ ret =
+ silc_buffer_format(buf,
+ SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+ ske->start_payload_copy->len),
+ 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;
+ }
- if (!silc_fsm_init(&ske->fsm, ske, silc_ske_finished, ske, ske->schedule))
- return NULL;
+ memset(e, 0, e_len);
+ silc_free(e);
+ }
- ske->rekey = rekey;
- ske->responder = TRUE;
- ske->running = TRUE;
- ske->rekeying = TRUE;
+ /* Make the hash */
+ silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
+ *return_hash_len = silc_hash_len(ske->prop->hash);
- /* 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_REKEY,
- SILC_PACKET_REKEY_DONE,
- SILC_PACKET_KEY_EXCHANGE_1,
- SILC_PACKET_SUCCESS,
- SILC_PACKET_FAILURE, -1);
+ if (initiator == FALSE) {
+ SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
+ } else {
+ SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
+ }
- /* Start SKE rekey as responder */
- silc_fsm_start(&ske->fsm, silc_ske_st_rekey_responder_start);
+ silc_buffer_free(buf);
- return &ske->op;
+ return status;
}
/* Processes the provided key material `data' as the SILC protocol
specification defines. */
-SilcSKEKeyMaterial
+SilcSKEStatus
silc_ske_process_key_material_data(unsigned char *data,
SilcUInt32 data_len,
SilcUInt32 req_iv_len,
SilcUInt32 req_enc_key_len,
SilcUInt32 req_hmac_key_len,
- SilcHash hash)
+ SilcHash hash,
+ SilcSKEKeyMaterial *key)
{
SilcBuffer buf;
unsigned char hashd[SILC_HASH_MAXLEN];
SilcUInt32 hash_len = req_hmac_key_len;
SilcUInt32 enc_key_len = req_enc_key_len / 8;
- SilcSKEKeyMaterial key;
SILC_LOG_DEBUG(("Start"));
if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
- return NULL;
-
- key = silc_calloc(1, sizeof(*key));
- if (!key)
- return NULL;
+ return SILC_SKE_STATUS_ERROR;
buf = silc_buffer_alloc_size(1 + data_len);
if (!buf)
- return NULL;
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
silc_buffer_format(buf,
SILC_STR_UI_CHAR(0),
SILC_STR_UI_XNSTRING(data, data_len),
/* Take IVs */
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 0;
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
memcpy(key->send_iv, hashd, req_iv_len);
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 1;
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
memcpy(key->receive_iv, hashd, req_iv_len);
key->iv_len = req_iv_len;
/* XXX */
if (enc_key_len > (3 * hash_len))
- return NULL;
+ return SILC_SKE_STATUS_ERROR;
/* Take first round */
memset(k1, 0, sizeof(k1));
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), k1);
+ silc_hash_make(hash, buf->data, buf->len, k1);
/* Take second round */
dist = silc_buffer_alloc_size(data_len + hash_len);
if (!dist)
- return NULL;
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
silc_buffer_format(dist,
SILC_STR_UI_XNSTRING(data, data_len),
SILC_STR_UI_XNSTRING(k1, hash_len),
SILC_STR_END);
memset(k2, 0, sizeof(k2));
- silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2);
+ silc_hash_make(hash, dist->data, dist->len, k2);
/* Take third round */
dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
SILC_STR_END);
silc_buffer_push(dist, data_len + hash_len);
memset(k3, 0, sizeof(k3));
- silc_hash_make(hash, dist->data, silc_buffer_len(dist), k3);
+ silc_hash_make(hash, dist->data, dist->len, k3);
/* Then, save the keys */
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
} else {
/* Take normal hash as key */
memset(hashd, 0, sizeof(hashd));
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
memcpy(key->send_enc_key, hashd, enc_key_len);
key->enc_key_len = req_enc_key_len;
/* XXX */
if (enc_key_len > (3 * hash_len))
- return NULL;
+ return SILC_SKE_STATUS_ERROR;
/* Take first round */
memset(k1, 0, sizeof(k1));
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), k1);
+ silc_hash_make(hash, buf->data, buf->len, k1);
/* Take second round */
dist = silc_buffer_alloc_size(data_len + hash_len);
if (!dist)
- return NULL;
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
silc_buffer_format(dist,
SILC_STR_UI_XNSTRING(data, data_len),
SILC_STR_UI_XNSTRING(k1, hash_len),
SILC_STR_END);
memset(k2, 0, sizeof(k2));
- silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2);
+ silc_hash_make(hash, dist->data, dist->len, k2);
/* Take third round */
dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
SILC_STR_END);
silc_buffer_push(dist, data_len + hash_len);
memset(k3, 0, sizeof(k3));
- silc_hash_make(hash, dist->data, silc_buffer_len(dist), k3);
+ silc_hash_make(hash, dist->data, dist->len, k3);
/* Then, save the keys */
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
} else {
/* Take normal hash as key */
memset(hashd, 0, sizeof(hashd));
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
memcpy(key->receive_enc_key, hashd, enc_key_len);
key->enc_key_len = req_enc_key_len;
/* Take HMAC keys */
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 4;
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 5;
- silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
key->hmac_key_len = req_hmac_key_len;
silc_buffer_clear(buf);
silc_buffer_free(buf);
- SILC_LOG_HEXDUMP(("enc"), key->send_enc_key, key->enc_key_len / 8);
-
- return key;
+ return SILC_SKE_STATUS_OK;
}
/* Processes negotiated key material as protocol specifies. This returns
the actual keys to be used in the SILC. */
-SilcSKEKeyMaterial
-silc_ske_process_key_material(SilcSKE ske,
- SilcUInt32 req_iv_len,
- SilcUInt32 req_enc_key_len,
- SilcUInt32 req_hmac_key_len,
- SilcSKERekeyMaterial *rekey)
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
+ SilcUInt32 req_iv_len,
+ SilcUInt32 req_enc_key_len,
+ SilcUInt32 req_hmac_key_len,
+ SilcSKEKeyMaterial *key)
{
+ SilcSKEStatus status;
SilcBuffer buf;
unsigned char *tmpbuf;
SilcUInt32 klen;
- SilcSKEKeyMaterial key;
/* Encode KEY to binary data */
tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
buf = silc_buffer_alloc_size(klen + ske->hash_len);
if (!buf)
- return NULL;
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
silc_buffer_format(buf,
SILC_STR_UI_XNSTRING(tmpbuf, klen),
SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
SILC_STR_END);
/* Process the key material */
- key = silc_ske_process_key_material_data(buf->data, silc_buffer_len(buf),
- req_iv_len, req_enc_key_len,
- req_hmac_key_len,
- ske->prop->hash);
+ status = silc_ske_process_key_material_data(buf->data, buf->len,
+ req_iv_len, req_enc_key_len,
+ req_hmac_key_len,
+ ske->prop->hash, key);
memset(tmpbuf, 0, klen);
silc_free(tmpbuf);
silc_buffer_clear(buf);
silc_buffer_free(buf);
- if (rekey) {
- *rekey = silc_ske_make_rekey_material(ske, key);
- if (!(*rekey))
- return NULL;
- }
-
- return key;
+ return status;
}
/* Free key material structure */
-void silc_ske_free_key_material(SilcSKEKeyMaterial key)
+void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
{
if (!key)
return;
silc_free(key);
}
-/* Free rekey material */
-
-void silc_ske_free_rekey_material(SilcSKERekeyMaterial rekey)
-{
- if (!rekey)
- return;
- if (rekey->send_enc_key) {
- memset(rekey->send_enc_key, 0, rekey->enc_key_len / 8);
- silc_free(rekey->send_enc_key);
- }
- silc_free(rekey->hash);
- silc_free(rekey);
-}
-
-/* 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)
-{
- unsigned char iv[32];
- SilcBool iv_included = (prop->flags & SILC_SKE_SP_FLAG_IV_INCLUDED);
-
- /* 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 */
- memset(iv, 0, sizeof(iv));
- if (ske->responder) {
- if (ret_send_key) {
- silc_cipher_set_key(*ret_send_key, keymat->receive_enc_key,
- keymat->enc_key_len, TRUE);
-
- if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
- memcpy(iv, ske->hash, 4);
- memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8);
- silc_cipher_set_iv(*ret_send_key, iv);
- } else {
- silc_cipher_set_iv(*ret_send_key, keymat->receive_iv);
- }
- }
- if (ret_receive_key) {
- silc_cipher_set_key(*ret_receive_key, keymat->send_enc_key,
- keymat->enc_key_len, FALSE);
-
- if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
- memcpy(iv, ske->hash, 4);
- memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8);
- silc_cipher_set_iv(*ret_receive_key, iv);
- } else {
- silc_cipher_set_iv(*ret_receive_key, keymat->send_iv);
- }
- }
- if (ret_hmac_send)
- silc_hmac_set_key(*ret_hmac_send, keymat->receive_hmac_key,
- keymat->hmac_key_len);
- if (ret_hmac_receive)
- silc_hmac_set_key(*ret_hmac_receive, keymat->send_hmac_key,
- keymat->hmac_key_len);
- } else {
- if (ret_send_key) {
- silc_cipher_set_key(*ret_send_key, keymat->send_enc_key,
- keymat->enc_key_len, TRUE);
-
- if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) {
- memcpy(iv, ske->hash, 4);
- memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8);
- silc_cipher_set_iv(*ret_send_key, iv);
- } else {
- silc_cipher_set_iv(*ret_send_key, keymat->send_iv);
- }
- }
- if (ret_receive_key) {
- silc_cipher_set_key(*ret_receive_key, keymat->receive_enc_key,
- keymat->enc_key_len, FALSE);
-
- if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) {
- memcpy(iv, ske->hash, 4);
- memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8);
- silc_cipher_set_iv(*ret_receive_key, iv);
- } else {
- silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv);
- }
- }
- if (ret_hmac_send)
- silc_hmac_set_key(*ret_hmac_send, keymat->send_hmac_key,
- keymat->hmac_key_len);
- if (ret_hmac_receive)
- 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;
- }
-
- return TRUE;
-}
-
const char *silc_ske_status_string[] =
{
/* Official */
"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",
"System out of memory",
- "Key exchange timeout",
NULL
};
/* 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)
+bool silc_ske_parse_version(SilcSKE ske,
+ 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,
software_version_string,
vendor_version);
}
-
-/* Get security properties */
-
-SilcSKESecurityProperties silc_ske_get_security_properties(SilcSKE ske)
-{
- return ske->prop;
-}
-
-/* Get key material */
-
-SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske)
-{
- return ske->keymat;
-}
/*
- silcske.h
+ silcske.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2007 Pekka Riikonen
+ 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
*/
+#ifndef SILCSKE_H
+#define SILCSKE_H
+
/****h* silcske/SILC SKE Interface
*
* DESCRIPTION
*
- * The SILC Key Exchange (SKE) protocol interface. The SKE protocol
+ * Implementation of the SILC Key Exchange Protocol (SKE). The SKE protocol
* is used to negotiate secret key material between two parties, to be used
* as session key or some other key. For example, when client connects to
* 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.
+ * stream.
+ *
+ * SKE is based on Diffie-Hellman, and it derives its functionality from
+ * SSH2 Key Exchange protocol, OAKLEY Key Determination protocol and
+ * Station-To-Station (STS) protocols.
+ *
+ * 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. For the interface application must provide
+ * a packet sending function which SKE library can call when it wants
+ * to send packet to the remote host. The actual network connection
+ * therefore is handled in the application and not by the SKE library.
+ *
+ * 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.
*
***/
-#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 */
- SILC_SKE_STATUS_TIMEOUT, /* Timeout */
-} SilcSKEStatus;
-/***/
-
-#include "silcske_groups.h"
-#include "silcske_payload.h"
+#include "silcske_status.h"
-/****d* silcske/SilcSKEAPI/SilcSKESecurityPropertyFlag
+/****s* silcske/SilcSKEAPI/SilcSKE
*
* NAME
*
- * typedef enum { ... } SilcSKESecurityPropertyFlag
+ * typedef struct SilcSKEStruct *SilcSKE;
*
* DESCRIPTION
*
- * SKE security property flags as defined by the SK protocol.
+ * This context is forward declaration for the SilcSKEStruct.
+ * This is allocated by the silc_ske_alloc and freed by the
+ * silc_ske_free function. This context represents the SKE session.
*
- * SOURCE
- */
-typedef enum {
- SILC_SKE_SP_FLAG_NONE = 0x00, /* No flags */
- SILC_SKE_SP_FLAG_IV_INCLUDED = 0x01, /* IV included in packet */
- SILC_SKE_SP_FLAG_PFS = 0x02, /* Perfect Forward Secrecy */
- SILC_SKE_SP_FLAG_MUTUAL = 0x04, /* Mutual authentication */
-} SilcSKESecurityPropertyFlag;
-/***/
+ ***/
+typedef struct SilcSKEStruct *SilcSKE;
/****s* silcske/SilcSKEAPI/SilcSKESecurityProperties
*
* NAME
*
- * typedef struct { ... } *SilcSKESecurityProperties;
+ * typedef struct SilcSKESecurityPropertiesStruct
+ * *SilcSKESecurityProperties;
*
* DESCRIPTION
*
- * 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 must be used in the
- * communication.
+ * This context is forward declaration for the
+ * SilcSKESecurityPropertiesStruct structure. It is allocated by the
+ * library, and it represents the security properties selected during
+ * the SKE negotiation.
*
- * SOURCE
- */
-typedef struct {
- SilcSKESecurityPropertyFlag flags; /* Flags */
- SilcSKEDiffieHellmanGroup group; /* Selected Diffie Hellman group */
- SilcCipher cipher; /* Selected cipher */
- SilcHmac hmac; /* Selected HMAC */
- SilcHash hash; /* Selected hash algorithm */
- SilcPublicKey public_key; /* Remote public key */
- SilcUInt16 remote_port; /* Remote port, set when IV Included
- set and using UDP/IP */
-} *SilcSKESecurityProperties;
-/***/
+ ***/
+typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties;
-/****s* silcske/SilcSKEAPI/SilcSKEKeyMaterial
+/* Forward declaration for SKE callbacks structure, which is internal. */
+typedef struct SilcSKECallbacksStruct *SilcSKECallbacks;
+
+/****d* silcske/SilcSKEAPI/SilcSKEPKType
*
* NAME
*
- * typedef struct { ... } *SilcSKEKeyMaterial;
+ * typedef enum { ... } SilcSKEPKType;
*
* DESCRIPTION
*
- * This is the key material structure, and is passed as argument by the
- * application to silc_ske_process_key_material_data function. It includes
- * the processed key material which can be used as SILC session keys.
+ * Public key and certificate types defined by the SKE protocol.
*
* SOURCE
*/
-typedef struct {
- unsigned char *send_iv;
- unsigned char *receive_iv;
- SilcUInt32 iv_len;
- unsigned char *send_enc_key;
- unsigned char *receive_enc_key;
- SilcUInt32 enc_key_len;
- unsigned char *send_hmac_key;
- unsigned char *receive_hmac_key;
- SilcUInt32 hmac_key_len;
-} *SilcSKEKeyMaterial;
+typedef enum {
+ SILC_SKE_PK_TYPE_SILC = 1, /* Mandatory type */
+ /* Optional types. These are not implemented currently */
+ SILC_SKE_PK_TYPE_SSH2 = 2,
+ SILC_SKE_PK_TYPE_X509V3 = 3,
+ SILC_SKE_PK_TYPE_OPENPGP = 4,
+ SILC_SKE_PK_TYPE_SPKI = 5
+} SilcSKEPKType;
/***/
-/****s* silcske/SilcSKEAPI/SilcSKERekeyMaterial
+/****f* silcske/SilcSKEAPI/SilcSKESendPacketCb
*
- * NAME
+ * SYNOPSIS
*
- * typedef struct { ... } *SilcSKERekeyMaterial;
+ * typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet,
+ * SilcPacketType type, void *context);
*
* DESCRIPTION
*
- * This context is returned after key exchange protocol to application
- * in the completion callback. Application may save it and use it later
- * to perform the rekey with silc_ske_rekey_initiator and/or
- * silc_ske_rekey_responder functions. If application does not
- * need the context, it may free it with silc_ske_free_rekey_material
- * function.
+ * Packet sending callback. Caller of the SKE routines must provide
+ * a routine to send packets to negotiation parties. See the
+ * silc_ske_set_callbacks for more information.
*
***/
-typedef struct {
- unsigned char *send_enc_key;
- char *hash;
- unsigned int enc_key_len : 23;
- unsigned int ske_group : 8;
- unsigned int pfs : 1;
-} *SilcSKERekeyMaterial;
-
-/****s* silcske/SilcSKEAPI/SilcSKEParams
- *
- * NAME
- *
- * typedef struct { ... } *SilcSKEParams, SilcSKEParamsStruct;
- *
- * DESCRIPTION
- *
- * SKE parameters structure. This structure is given as argument to
- * silc_ske_initiator and silc_ske_responder functions.
- *
- * SOURCE
- */
-typedef struct {
- /* The SKE version string that is sent to the remote end. This field
- must be set. Caller must free the pointer. */
- char *version;
-
- /* Security property flags. When initiator sets these it requests them
- from the responder. Responder may set here the flags it supports
- and wants to enforce for the initiator. */
- SilcSKESecurityPropertyFlag flags;
-
- /* SILC Session port when using UDP/IP and SILC_SKE_SP_FLAG_IV_INCLUDED
- flag. It is the port the remote will use as SILC session port after
- the key exchange protocol. Ignored without SILC_SKE_SP_FLAG_IV_INCLUDED
- flag. */
- SilcUInt16 session_port;
-
- /* Key exchange timeout in seconds. If key exchange is not completed in
- this time it will timeout. If not specified (zero), default value
- (30 seconds) will be used. */
- SilcUInt16 timeout_secs;
-} *SilcSKEParams, SilcSKEParamsStruct;
-/***/
+typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet,
+ SilcPacketType type, void *context);
-/****d* silcske/SilcSKEAPI/SilcSKEPKType
+/****f* silcske/SilcSKEAPI/SilcSKECb
*
- * NAME
+ * SYNOPSIS
*
- * typedef enum { ... } SilcSKEPKType;
+ * typedef void (*SilcSKECb)(SilcSKE ske, void *context);
*
* DESCRIPTION
*
- * Public key and certificate types defined by the SKE protocol.
+ * Generic SKE callback function. This is called in various SKE
+ * routines. The SilcSKE object sent as argument provides all the data
+ * callers routine might need (payloads etc). This is usually called
+ * to indicate that the application may continue the execution of the
+ * SKE protocol. The application should check the ske->status in this
+ * callback function. This callback is also called when Start Payload
+ * is processed. See silc_ske_set_callbacks function for more information.
*
- * SOURCE
- */
-typedef enum {
- SILC_SKE_PK_TYPE_SILC = 1, /* SILC Public Key, mandatory */
- SILC_SKE_PK_TYPE_SSH2 = 2, /* SSH2 Public key, not supported */
- SILC_SKE_PK_TYPE_X509V3 = 3, /* X.509v3 certificate, not supported */
- SILC_SKE_PK_TYPE_OPENPGP = 4, /* OpenPGP certificate, not supported */
- SILC_SKE_PK_TYPE_SPKI = 5 /* SPKI certificate, not supported */
-} SilcSKEPKType;
-/***/
+ ***/
+typedef void (*SilcSKECb)(SilcSKE ske, void *context);
/****f* silcske/SilcSKEAPI/SilcSKEVerifyCbCompletion
*
*
* Completion callback that will be called when the public key
* has been verified. The `status' will indicate whether the public
- * key were trusted or not.
+ * key were trusted or not. If the `status' is PENDING then the status
+ * is not considered to be available at this moment. In this case the
+ * SKE libary will assume that the caller will call this callback again
+ * when the status is available. See silc_ske_set_callbacks for more
+ * information.
*
***/
typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske,
* SYNOPSIS
*
* typedef void (*SilcSKEVerifyCb)(SilcSKE ske,
- * SilcPublicKey public_key,
+ * unsigned char *pk_data,
+ * SilcUInt32 pk_len,
+ * SilcSKEPKType pk_type,
* void *context,
* SilcSKEVerifyCbCompletion completion,
* void *completion_context);
* DESCRIPTION
*
* Callback function used to verify the received public key or certificate.
- * The verification process is most likely asynchronous. That's why the
+ * The verification process is most likely asynchronous. That's why the
* application must call the `completion' callback when the verification
- * process has been completed. The `context' is the context given as
- * arugment to silc_ske_set_callbacks. See silc_ske_set_callbacks for
- * more information.
- *
- * If the key repository was provided in silc_ske_alloc this callback
- * is called only if the public key was not found from the repository.
+ * process has been completed. The library then calls the user callback
+ * (SilcSKECb), if it was provided for the function that takes this callback
+ * function as argument, to indicate that the SKE protocol may continue.
+ * See silc_ske_set_callbacks for more information.
*
***/
typedef void (*SilcSKEVerifyCb)(SilcSKE ske,
- SilcPublicKey public_key,
+ unsigned char *pk_data,
+ SilcUInt32 pk_len,
+ SilcSKEPKType pk_type,
void *context,
SilcSKEVerifyCbCompletion completion,
void *completion_context);
-/****f* silcske/SilcSKEAPI/SilcSKECompletionCb
+/****f* silcske/SilcSKEAPI/SilcSKECheckVersion
*
* SYNOPSIS
*
- * typedef void (*SilcSKECompletionCb)(SilcSKE ske,
- * SilcSKEStatus status,
- * const SilcSKESecurityProperties prop,
- * const SilcSKEKeyMaterial keymat,
- * SilcSKERekeyMaterial rekey,
- * void *context);
+ * typedef SilcSKEStatus (*SilcSKECheckVersion)(SilcSKE ske,
+ * unsigned char *version,
+ * SilcUInt32 len, 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' and `keymat'
- * will remain valid as long as `ske' is valid. The `rekey' will remain
- * valid until silc_ske_free_rekey_material is called. The application
- * must call it to free the `rekey'.
+ * 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 (*SilcSKECheckVersion)(SilcSKE ske,
+ unsigned char *version,
+ SilcUInt32 len, void *context);
+
+/****s* silcske/SilcSKEAPI/SilcSKEKeyMaterial
+ *
+ * NAME
+ *
+ * typedef struct { ... } SilcSKEKeyMaterial;
+ *
+ * DESCRIPTION
*
- * When doing rekey, this completion callback delivers the `keymat' and
- * new `rekey'. The `prop' is ignored. The `keymat' has already been set
- * to the packet stream associated with the `ske'. Thus, after this
- * is called the new keys are in use.
+ * This is the key material structure, and is passed as argument by the
+ * application to silc_ske_process_key_material* functions. It includes
+ * the processed key material which can be used as SILC session keys.
*
***/
-typedef void (*SilcSKECompletionCb)(SilcSKE ske,
- SilcSKEStatus status,
- const SilcSKESecurityProperties prop,
- const SilcSKEKeyMaterial keymat,
- SilcSKERekeyMaterial rekey,
- void *context);
+typedef struct {
+ unsigned char *send_iv;
+ unsigned char *receive_iv;
+ SilcUInt32 iv_len;
+ unsigned char *send_enc_key;
+ unsigned char *receive_enc_key;
+ SilcUInt32 enc_key_len;
+ unsigned char *send_hmac_key;
+ unsigned char *receive_hmac_key;
+ SilcUInt32 hmac_key_len;
+} SilcSKEKeyMaterial;
+
+/* Length of cookie in Start Payload */
+#define SILC_SKE_COOKIE_LEN 16
+
+#include "silcske_groups.h"
+#include "silcske_payload.h"
+
+/****d* silcske/SilcSKEAPI/SilcSKESecurityPropertyFlag
+ *
+ * NAME
+ *
+ * typedef enum { ... } SilcSKESecurityPropertyFlag
+ *
+ * DESCRIPTION
+ *
+ * SKE security property flags as defined by the SK protocol.
+ *
+ * SOURCE
+ */
+typedef enum {
+ SILC_SKE_SP_FLAG_NONE = 0x00, /* No flags */
+ SILC_SKE_SP_FLAG_IV_INCLUDED = 0x01, /* IV included in ciphertexts */
+ SILC_SKE_SP_FLAG_PFS = 0x02, /* Perfect Forward Secrecy */
+ SILC_SKE_SP_FLAG_MUTUAL = 0x04, /* Mutual authentication */
+} SilcSKESecurityPropertyFlag;
+/***/
+
+/****s* silcske/SilcSKEAPI/SilcSKESecurityPropertiesStruct
+ *
+ * NAME
+ *
+ * struct SilcSKESecurityPropertiesStruct { ... };
+ *
+ * DESCRIPTION
+ *
+ * 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
+ * communication.
+ *
+ * SOURCE
+ */
+struct SilcSKESecurityPropertiesStruct {
+ 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 */
+};
+/***/
+
+/****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,
+ * securit 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 connection object. This is initialized by the caller. */
+ SilcSocketConnection sock;
+
+ /* Security properties negotiated */
+ 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;
+};
+/***/
/* Prototypes */
*
* SYNOPSIS
*
- * SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
- * SilcSKR repository, SilcPublicKey public_key,
- * SilcPrivateKey private_key, void *context);
+ * SilcSKE silc_ske_alloc(SilcRng rng, void *context);
*
* DESCRIPTION
*
* Allocates the SKE session context and returns it. The `rng' is
* the random number generator the SKE is going to use when it needs
* random number generation during the SKE session. The `context' is
- * user context that the libary will not touch. Application can get the
- * context by calling the fuction silc_ske_get_context function. The
+ * user context that the libary will not touch. The application can
+ * access that context with the ske->user_context if needed. The
* application is responsible of freeing the `context'. After the
* SKE session context is allocated application must call the
* silc_ske_set_callbacks.
*
- * If the `repository' is non-NULL then the remote's public key will be
- * verified from the repository. If it is not provided then the
- * SilcSKEVerifyCb callback must be set, and it will be called to
- * verify the key. If both `repository' and the callback is provided the
- * callback is called only if the key is not found from the repository.
- *
- * The `public_key' and `private_key' is the caller's identity used
- * during the key exchange. Giving `private_key' is optional if the
- * SILC_SKE_SP_FLAG_MUTUAL is not set and you are initiator. For
- * responder both `public_key' and `private_key' must be set.
- *
- * EXMPALE
- *
- * // Initiator example
- * params.version = version;
- * params.flags = SILC_SKE_SP_FLAG_PFS | SILC_SKE_SP_FLAG_MUTUAL;
- * ske = silc_ske_alloc(rng, scheduler, NULL, pk, prv, app);
- * silc_ske_set_callbacks(ske, verify_public_key, completion, app);
- * silc_ske_initiator_start(ske, stream, ¶ms, NULL);
- *
***/
-SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
- SilcSKR repository, SilcPublicKey public_key,
- SilcPrivateKey private_key, void *context);
+SilcSKE silc_ske_alloc(SilcRng rng, void *context);
/****f* silcske/SilcSKEAPI/silc_ske_free
*
***/
void silc_ske_free(SilcSKE ske);
-/****f* silcske/SilcSKEAPI/silc_ske_get_context
- *
- * SYNOPSIS
- *
- * void *silc_ske_get_context(SilcSKE ske);
- *
- * DESCRIPTION
- *
- * Returns the context that was given as argument to silc_ske_alloc.
- *
- ***/
-void *silc_ske_get_context(SilcSKE ske);
-
/****f* silcske/SilcSKEAPI/silc_ske_set_callbacks
*
* SYNOPSIS
*
* void silc_ske_set_callbacks(SilcSKE ske,
+ * SilcSKESendPacketCb send_packet,
+ * SilcSKECb payload_receive,
* SilcSKEVerifyCb verify_key,
- * SilcSKECompletion completed,
+ * SilcSKECb proto_continue,
+ * SilcSKECheckVersion check_version,
* void *context);
*
* DESCRIPTION
*
* Sets the callback functions for the SKE session.
*
+ * The `send_packet' callback is a function that sends the packet to
+ * network. The SKE library will call it at any time packet needs to
+ * be sent to the remote host.
+ *
+ * The `payload_receive' callback is called when the remote host's Key
+ * Exchange Start Payload has been processed. The payload is saved
+ * to ske->start_payload if the application would need it. The application
+ * must also provide the payload to the next state of the SKE.
+ *
* The `verify_key' callback is called to verify the received public key
* or certificate. The verification process is most likely asynchronous.
* That is why the application must call the completion callback when the
- * verification process has been completed. If this SKE session context
- * is used to perform rekey, this callback usually is not provided as
- * argument since sending public key in rekey is not mandatory. Setting
- * this callback implies that remote end MUST send its public key.
- *
- * 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.
+ * verification process has been completed. The library then calls the user
+ * callback (`proto_continue'), if it is provided to indicate that the SKE
+ * protocol may continue. If this SKE session context is used to perform
+ * rekey, this callback usually is not provided as argument since sending
+ * public key in rekey is not mandatory. Setting this callback implies
+ * that remote end MUST send its public key, and this could cause
+ * problems when performing rekey. When doing normal SKE session this
+ * callback should be set.
+ *
+ * The `proto_continue' callback is called to indicate that it is
+ * safe to continue the execution of the SKE protocol after executing
+ * an asynchronous operation, such as calling the `verify_key' callback
+ * function, which is asynchronous. The application should check the
+ * ske->status in this function to check whether it is Ok to continue
+ * the execution of the protocol.
+ *
+ * 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 `context' is passed as argument to all of the above callback
* functions.
*
***/
void silc_ske_set_callbacks(SilcSKE ske,
+ SilcSKESendPacketCb send_packet,
+ SilcSKECb payload_receive,
SilcSKEVerifyCb verify_key,
- SilcSKECompletionCb completed,
+ SilcSKECb proto_continue,
+ SilcSKECheckVersion check_version,
void *context);
-/****f* silcske/SilcSKEAPI/silc_ske_initiator
+/****f* silcske/SilcSKEAPI/silc_ske_initiator_start
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_ske_initiator(SilcSKE ske,
- * SilcPacketStream stream,
- * SilcSKEParams params,
- * SilcSKEStartPayload start_payload);
+ * SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+ * SilcSocketConnection sock,
+ * SilcSKEStartPayload
+ * *start_payload);
*
* DESCRIPTION
*
- * Starts the SILC Key Exchange protocol as initiator. The completion
- * callback that was set in silc_ske_set_callbacks will be called once
- * the protocol has completed. The `stream' is the network connection
- * to the remote host. The SKE library will handle all key exchange
- * packets sent and received in the `stream' connection. The library will
- * also set the remote host's ID automatically to the `stream'. The
- * `params' include SKE parameters, and it must be provided.
+ * Starts the SILC Key Exchange protocol for initiator. The connection
+ * to the responder end must be established before calling this function
+ * and the connecting socket must be sent as argument. This function
+ * creates the Key Exchange Start Payload which includes all our
+ * configured security properties. This payload is then sent to the
+ * responder end for further processing. This payload must be sent as
+ * argument to the function, however, it must not be encoded
+ * already, it is done by this function. The caller must not free
+ * the `start_payload' since the SKE library will save it.
*
- * If the `start_payload' is NULL the library will generate it
- * automatically. Caller may provide it if it wants to send its own
- * security properties instead of using the default ones library
- * generates. If caller provides it, it must not free it once it has
- * been given as argument to this function.
+ * Before calling this function application calls the
+ * silc_ske_assemble_security_properties which returns the `start_payload'
+ * which application must provide for this function.
*
- * This function returns SilcAsyncOperation operation context which can
- * be used to control the protocol from the application. Application may
- * for example safely abort the protocol at any point, if needed. Returns
- * NULL on error.
+ * After calling this function the application must wait for reply
+ * from the responder.
*
***/
-SilcAsyncOperation silc_ske_initiator(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKEParams params,
- SilcSKEStartPayload start_payload);
+SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ SilcSKEStartPayload *start_payload);
-/****f* silcske/SilcSKEAPI/silc_ske_responder
+/****f* silcske/SilcSKEAPI/silc_ske_initiator_phase_1
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_ske_responder(SilcSKE ske,
- * SilcPacketStream stream,
- * SilcSKEParams params);
+ * SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
+ * SilcBuffer start_payload);
*
* DESCRIPTION
*
- * Starts SILC Key Exchange protocol as responder. The completion
- * callback that was set in silc_ske_set_callbacks will be called once
- * the protocol has completed. The `stream' is the network connection
- * to the remote host. The SKE library will handle all key exchange
- * packets sent and received in the `stream' connection. The `params'
- * include SKE parameters, and must be provided.
+ * Function called after ske_initiator_start fuction. This receives
+ * the responder's Key Exchange Start payload which includes the
+ * security properties selected by the responder from our payload
+ * sent in the silc_ske_initiator_start function. The `start_payload'
+ * is the received payload and the application must send it as argument.
*
- * This function returns SilcAsyncOperation operation context which can
- * be used to control the protocol from the application. Application may
- * for example safely abort the protocol at any point, if needed. Returns
- * NULL on error.
+ * After calling this function the application must call immediately,
+ * or with short timeout, the silc_ske_initiator_phase_2 function.
*
***/
-SilcAsyncOperation silc_ske_responder(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKEParams params);
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
+ SilcBuffer start_payload);
-/****f* silcske/SilcSKEAPI/silc_ske_rekey_initiator
+/****f* silcske/SilcSKEAPI/silc_ske_initiator_phase_2
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_ske_rekey_initiator(SilcSKE ske,
- * SilcPacketStream stream,
- * SilcSKERekeyMaterial rekey);
+ * SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+ * SilcPublicKey public_key,
+ * SilcPrivateKey private_key,
+ * SilcSKEPKType pk_type)
*
* DESCRIPTION
*
- * Starts SILC Key Exchange key regeneration (rekey) protocol. The `rekey'
- * is the rekey material received earlier in SilcSKECompletionCb. That
- * same callback is called after the rekey protocol is over to deliver new
- * key material and new rekey material.
+ * This function continues the SKE session after the initiator has
+ * called the silc_ske_initiator_phase_1. After that function returns
+ * the application should call immediately, or with short timeout, this
+ * function which will continue with the session, and sends next phase
+ * packet to the responder. The caller must provide the caller's
+ * public key and private key as argument, since the public key is
+ * sent to the responder, and the private key is be used to generate
+ * digital signature.
*
- * This function returns SilcAsyncOperation operation context which can
- * be used to control the protocol from the application. Application may
- * for example safely abort the protocol at any point, if needed. Returns
- * NULL on error.
+ * After this function the application must wait for reply from the
+ * responder.
*
***/
-SilcAsyncOperation silc_ske_rekey_initiator(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKERekeyMaterial rekey);
+SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcSKEPKType pk_type);
-/****f* silcske/SilcSKEAPI/silc_ske_rekey_responder
+/****f* silcske/SilcSKEAPI/silc_ske_initiator_finish
*
* SYNOPSIS
*
- * SilcAsyncOperation
- * silc_ske_rekey_responder(SilcSKE ske,
- * SilcPacketStream stream,
- * SilcSKERekeyMaterial rekey);
+ * SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+ * SilcBuffer ke_payload);
*
* DESCRIPTION
*
- * Starts SILC Key Exchange key regeneration (rekey) protocol as responder.
- * The `rekey' is the rekey material received earlier in
- * SilcSKECompletionCb. That same callback is called after the rekey
- * protocol is over to deliver new key material and new rekey material.
+ * Receives the reply from the responder and processes it. The
+ * `ke_payload' is the reply and application must provide it as argument.
+ * This function will verify the responder's public key, by calling
+ * the `verify_key' callback that was set with silc_ske_set_callbacks
+ * function.
*
- * This function returns SilcAsyncOperation operation context which can
- * be used to control the protocol from the application. Application may
- * for example safely abort the protocol at any point, if needed. Returns
- * NULL on error.
+ * If this function returns error, no callbacks will be called. If
+ * this function needs to verify remote end's public key, this will
+ * return SILC_SKE_STATUS_PENDING, which indicates application that
+ * SKE is performing asynchronous operation and is in pending status.
+ * When in this status application must not continue with calling
+ * any other SKE routine. The asynchronous operation is the `verify_key'
+ * callback, which application completes by calling its completion
+ * callback. After completion the SKE libary will call the
+ * `proto_continue' callback, to indicate application that pending
+ * status is over and it is safe to continue the execution of SKE,
+ * which application does by calling the silc_ske_end function.
+ *
+ * If this function returns SILC_SKE_STATUS_OK, it will not call the
+ * `verify_key' callback, however, it will or has already called the
+ * `proto_continue' callback.
+ *
+ * Application must not continue execution of the SKE before library
+ * has called the `proto_continue' callback. After it is called
+ * the application finishes SKE session by calling silc_ske_end
+ * function.
*
***/
-SilcAsyncOperation silc_ske_rekey_responder(SilcSKE ske,
- SilcPacketStream stream,
- SilcSKERekeyMaterial rekey);
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+ SilcBuffer ke_payload);
-/****f* silcske/SilcSKEAPI/silc_ske_set_keys
+/****f* silcske/SilcSKEAPI/silc_ske_responder_start
*
* 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);
+ * SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+ * SilcSocketConnection sock,
+ * const char *version,
+ * SilcBuffer start_payload,
+ * SilcSKESecurityPropertyFlag
+ * flags);
*
* 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.
+ * Starts Key Exchange protocol for responder. 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
+ * SilcSKESecurityPropertyFlag flags that responder enforces for the
+ * initiator. Responder may, for example, enforce that the PFS
+ * will be performed in rekey. This example can be done by providing
+ * SILC_SKE_SP_FLAG_PFS as `flags'. The `flags' is a bit mask of
+ * enforced flags.
+ *
+ * After this function the responder calls immediately, or with short
+ * timeout the silc_ske_responder_phase_1 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);
+SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+ SilcSocketConnection sock,
+ const char *version,
+ SilcBuffer start_payload,
+ SilcSKESecurityPropertyFlag flags);
-/****f* silcske/SilcSKEAPI/silc_ske_parse_version
+/****f* silcske/SilcSKEAPI/silc_ske_responder_phase_1
*
* 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);
+ * SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske);
*
* DESCRIPTION
*
- * Utility function to parse the remote host's version string. This can
- * be called after the key exchange has been completed.
+ * This function is called after the silc_ske_responder_start, and
+ * is used to send our reply to the initiator. This function is
+ * called either immediately, or with short timeout, after the
+ * silc_ske_responder_start function returned.
+ *
+ * After this function the responder must wait for reply from the
+ * initiator.
*
***/
-SilcBool silc_ske_parse_version(SilcSKE ske,
- SilcUInt32 *protocol_version,
- char **protocol_version_string,
- SilcUInt32 *software_version,
- char **software_version_string,
- char **vendor_version);
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske);
-/****f* silcske/SilcSKEAPI/silc_ske_get_security_properties
+/****f* silcske/SilcSKEAPI/silc_ske_responder_phase_2
*
* SYNOPSIS
*
- * SilcSKESecurityProperties silc_ske_get_security_properties(SilcSKE ske);
+ * SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+ * SilcBuffer ke_payload);
*
* DESCRIPTION
*
- * Returns negotiated security properties from the `ske' or NULL if they
- * have not yet been negotiated. This may be called to retrieve the
- * security properties after the SilcSKECompletionCb has been called.
+ * Receives the reply from the initiator and procedses it. The
+ * `ke_payload' is the reply and application must provide it as argument.
+ * This function will verify the remote host's public key, by calling
+ * the `verify_key' callback that was set with silc_ske_set_callbacks
+ * function.
+ *
+ * If this function returns error, no callbacks will be called. If
+ * this function needs to verify remote end's public key, this will
+ * return SILC_SKE_STATUS_PENDING, which indicates application that
+ * SKE is performing asynchronous operation and is in pending status.
+ * When in this status application must not continue with calling
+ * any other SKE routine. The asynchronous operation is the `verify_key'
+ * callback, which application completes by calling its completion
+ * callback. After completion the SKE libary will call the
+ * `proto_continue' callback, to indicate application that pending
+ * status is over and it is safe to continue the execution of SKE,
+ * which application does by calling the silc_ske_responder_finish
+ * function.
+ *
+ * If this function returns SILC_SKE_STATUS_OK, it will not call the
+ * `verify_key' callback, however, it will or has already called the
+ * `proto_continue' callback.
+ *
+ * Application must not continue execution of the SKE before library
+ * has called the `proto_continue' callback. After it is called
+ * the application calls the silc_ske_responder_finish function.
*
***/
-SilcSKESecurityProperties silc_ske_get_security_properties(SilcSKE ske);
+SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+ SilcBuffer ke_payload);
-/****f* silcske/SilcSKEAPI/silc_ske_get_key_material
+/****f* silcske/SilcSKEAPI/silc_ske_responder_finish
*
* SYNOPSIS
*
- * SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske);
+ * SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+ * SilcPublicKey public_key,
+ * SilcPrivateKey private_key,
+ * SilcSKEPKType pk_type);
*
* DESCRIPTION
*
- * Returns the negotiated key material from the `ske' or NULL if the
- * key material does not exist. The caller must not free the returned
- * pointer.
+ * This function finishes the responder's SKE session, and this function
+ * is called either immediately, or with short timeout, after the
+ * silc_ske_responder_phase_2 returned. This will send our reply to
+ * the initiator. The caller must provide the caller's public key and
+ * private key as argument, since the public key is sent to the responder,
+ * and the private key is be used to generate digital signature.
+ *
+ * After this function the application must wait for the end indication
+ * from the intiator, and when it is received the silc_ske_end is called.
*
***/
-SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske);
+SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcSKEPKType pk_type);
-/****f* silcske/SilcSKEAPI/silc_ske_process_key_material_data
+/****f* silcske/SilcSKEAPI/silc_ske_end
*
* SYNOPSIS
*
- * const char *silc_ske_map_status(SilcSKEStatus status);
+ * SilcSKEStatus silc_ske_end(SilcSKE ske);
*
* DESCRIPTION
*
- * Utility function to process key data `data' in the way specified
- * by the SILC Key Exchange protocol. This returns the processed key
- * material or NULL on error. Caller must free the returned key
- * material context by calling silc_ske_free_key_material.
+ * The Key Exchange protocol is ended by calling this function. This
+ * must not be called until the keys are processed by calling the
+ * silc_ske_process_key_material function. The protocol prohibits
+ * calling this function before key material is processed properly.
+ *
+ * This function is for both initiator and responder. After calling
+ * this function initiator must wait for end indication from the
+ * responder. After that the silc_ske_free may be called. The responder
+ * calls this function after it has received the intiator's end
+ * indication.
+ *
+ * NOTES
+ *
+ * Initiator must not start using the negotiated key material before
+ * calling this function or before remote end has sent its end
+ * indication. Only after that the key material may be taken in use.
*
***/
-SilcSKEKeyMaterial
-silc_ske_process_key_material_data(unsigned char *data,
- SilcUInt32 data_len,
- SilcUInt32 req_iv_len,
- SilcUInt32 req_enc_key_len,
- SilcUInt32 req_hmac_key_len,
- SilcHash hash);
+SilcSKEStatus silc_ske_end(SilcSKE ske);
-/****f* silcske/SilcSKEAPI/silc_ske_free_key_material
+/****f* silcske/SilcSKEAPI/silc_ske_abort
+ *
+ * SYNOPSIS
+ *
+ * SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status);
+ *
+ * DESCRIPTION
+ *
+ * Aborts the Key Exchange protocol. This is called if error occurs
+ * while performing the protocol. The status argument is the error
+ * status and it is sent to the remote end.
+ *
+ ***/
+SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status);
+
+/****f* silcske/SilcSKEAPI/silc_ske_assemble_security_properties
+ *
+ * SYNOPSIS
+ *
+ * SilcSKEStatus
+ * silc_ske_assemble_security_properties(SilcSKE ske,
+ * SilcSKESecurityPropertyFlag flags,
+ * const char *version,
+ * SilcSKEStartPayload
+ * **return_payload);
+ *
+ * DESCRIPTION
+ *
+ * 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. The assembled payload is returned into
+ * the `return_payload' pointer.
+ *
+ ***/
+SilcSKEStatus
+silc_ske_assemble_security_properties(SilcSKE ske,
+ SilcSKESecurityPropertyFlag flags,
+ const char *version,
+ SilcSKEStartPayload **return_payload);
+
+/****f* silcske/SilcSKEAPI/silc_ske_select_security_properties
*
* SYNOPSIS
*
- * void silc_ske_free_key_material(SilcSKEKeyMaterial key)
+ * SilcSKEStatus
+ * silc_ske_select_security_properties(SilcSKE ske,
+ * const char *version,
+ * SilcSKEStartPayload *payload,
+ * SilcSKEStartPayload *remote_payload);
*
* DESCRIPTION
*
- * Utility function to free the key material created by calling
- * silc_ske_process_key_material_data.
+ * Parses the Key Exchange Start Payload indicated by `remote_payload',
+ * and selects the security properties properties from it, and puts the
+ * selection into the `payload'. This always attempts to select the
+ * best security properties from the payload, and it always selects
+ * one of each kind of security property, as this is dictated by the
+ * protocol. The `version' is our version, that we will put to the
+ * `payload', since the `payload' is usually sent to the remote end.
+ * the `check_version' callback will be called in this function so
+ * that application can do version check with the remote end.
*
***/
-void silc_ske_free_key_material(SilcSKEKeyMaterial key);
+SilcSKEStatus
+silc_ske_select_security_properties(SilcSKE ske,
+ const char *version,
+ SilcSKEStartPayload *payload,
+ SilcSKEStartPayload *remote_payload);
-/****f* silcske/SilcSKEAPI/silc_ske_free_rekey_material
+/****f* silcske/SilcSKEAPI/silc_ske_process_key_material
*
* SYNOPSIS
*
- * void silc_ske_free_rekey_material(SilcSKERekeyMaterial rekey);
+ * SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
+ * SilcUInt32 req_iv_len,
+ * SilcUInt32 req_enc_key_len,
+ * SilcUInt32 req_hmac_key_len,
+ * SilcSKEKeyMaterial *key);
*
* DESCRIPTION
*
- * Utility function to free the rekey material returned in the
- * SilcSKECompletionCb callback.
+ * This function is used by the application to process the key material
+ * negotiated with the SKE session, to actually produce the keys that
+ * is to be used in SILC protocol. The key processing is defined by the
+ * protocol. The `req_iv_len', `req_enc_key_len' and `req_hmac_key_len'
+ * are the request IV length, requested encryption/decrypt key length,
+ * and requested HMAC key length, respectively, and they cannot be
+ * zero (0). They tell the function how long the keys should be, and
+ * it will produce the requested length keys for the application.
+ * The key material is returned in to the `key', which the caller must
+ * free.
*
***/
-void silc_ske_free_rekey_material(SilcSKERekeyMaterial rekey);
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
+ SilcUInt32 req_iv_len,
+ SilcUInt32 req_enc_key_len,
+ SilcUInt32 req_hmac_key_len,
+ SilcSKEKeyMaterial *key);
-/****f* silcske/SilcSKEAPI/silc_ske_map_status
+/****f* silcske/SilcSKEAPI/silc_ske_process_key_material_data
*
* SYNOPSIS
*
- * const char *silc_ske_map_status(SilcSKEStatus status);
+ * SilcSKEStatus
+ * silc_ske_process_key_material_data(unsigned char *data,
+ * SilcUInt32 data_len,
+ * SilcUInt32 req_iv_len,
+ * SilcUInt32 req_enc_key_len,
+ * SilcUInt32 req_hmac_key_len,
+ * SilcHash hash,
+ * SilcSKEKeyMaterial *key);
*
* DESCRIPTION
*
- * Utility function to map the `status' into human readable message.
+ * This function is equivalent to silc_ske_process_key_material, except
+ * that the caller provides the raw key material as argument, the `data'
+ * and `data_len'. This is special utility function provided for the
+ * application, if it needs to generate key material as the protocol
+ * defines for some other purpose than strictly SILC session key usage.
+ * Hence, this function can be used outside SKE protocol to just produce
+ * key material from some raw data. The `hash' is a hash algorithm that
+ * is used as part of key processing, and caller must provide it.
*
***/
-const char *silc_ske_map_status(SilcSKEStatus status);
+SilcSKEStatus
+silc_ske_process_key_material_data(unsigned char *data,
+ SilcUInt32 data_len,
+ SilcUInt32 req_iv_len,
+ SilcUInt32 req_enc_key_len,
+ SilcUInt32 req_hmac_key_len,
+ SilcHash hash,
+ SilcSKEKeyMaterial *key);
-#include "silcske_i.h"
+/****f* silcske/SilcSKEAPI/silc_ske_free_key_material
+ *
+ * SYNOPSIS
+ *
+ * void silc_ske_free_key_material(SilcSKEKeyMaterial *key);
+ *
+ * DESCRIPTION
+ *
+ * Frees the key material indicated by `key', and all data in it.
+ *
+ ***/
+void silc_ske_free_key_material(SilcSKEKeyMaterial *key);
+
+/****f* silcske/SilcSKEAPI/silc_ske_parse_version
+ *
+ * SYNOPSIS
+ *
+ * bool silc_ske_parse_version(SilcSKE ske,
+ * 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.
+ *
+ ***/
+bool silc_ske_parse_version(SilcSKE ske,
+ SilcUInt32 *protocol_version,
+ char **protocol_version_string,
+ SilcUInt32 *software_version,
+ char **software_version_string,
+ char **vendor_version);
#endif /* !SILCSKE_H */
/*
- silcske_groups.h
+ silcske_groups.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2005 Pekka Riikonen
+ 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
#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
*
* SYNOPSIS
*
- * SilcSKEStatus
+ * SilcSKEStatus
* silc_ske_group_get_by_number(int number,
* SilcSKEDiffieHellmanGroup *ret);
*
*
* SYNOPSIS
*
- * SilcSKEStatus
+ * SilcSKEStatus
* silc_ske_get_group_by_name(const char *name,
* SilcSKEDiffieHellmanGroup *ret);
*
+++ /dev/null
-/*
-
- silcske_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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 SILCSKE_I_H
-#define SILCSKE_I_H
-
-/* Packet retry counter and timer defines for UDP transport. */
-#define SILC_SKE_RETRY_COUNT 4 /* Max packet retry count */
-#define SILC_SKE_RETRY_MUL 2 /* Retry timer interval growth */
-#define SILC_SKE_RETRY_RAND 2 /* Randomizer, timeout += rnd % 2 */
-#define SILC_SKE_RETRY_MIN 1 /* Min retry timeout, seconds */
-
-/* Length of cookie in Start Payload */
-#define SILC_SKE_COOKIE_LEN 16
-
-/* SKE context */
-struct SilcSKEStruct {
- SilcPacketStream stream;
- SilcRng rng;
- SilcSKR repository;
- SilcSKECallbacks callbacks;
- void *user_data;
- SilcSKEStatus status;
-
- /* 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;
-
- /* 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;
-
- char *version; /* Local version */
- char *remote_version; /* Remote version */
-
- SilcPublicKey public_key;
- SilcPrivateKey private_key;
- SilcSKEPKType pk_type;
- SilcPacket packet;
- SilcSKESecurityPropertyFlag flags;
- SilcSKEKeyMaterial keymat;
- SilcSKERekeyMaterial rekey;
- SilcSchedule schedule;
- SilcFSMStruct fsm;
- SilcAsyncOperationStruct op;
- SilcUInt16 session_port;
-
- /* Packet retransmission */
- SilcUInt16 retry_timer;
- SilcUInt16 retry_count;
- struct SilcSKEPacketRetransmission {
- SilcPacketType type;
- SilcPacketFlags flags;
- unsigned char *data;
- SilcUInt32 data_len;
- } retrans;
-
- SilcUInt16 timeout; /* SKE timeout */
- SilcUInt16 refcnt; /* Reference counter */
-
- unsigned int aborted : 1; /* Set when SKE aborted */
- unsigned int freed : 1; /* Set when freed during session */
- unsigned int responder : 1; /* Set when we are responder side */
- unsigned int running : 1; /* Set when SKE is running */
- unsigned int rekeying : 1; /* Set when rekeying */
-};
-
-#endif /* SILCSKE_I_H */
/*
- silcske_payload.h
+ silcske_payload.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2005 Pekka Riikonen
+ 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
/****s* silcske/SilcSKEPayloads/SilcSKEStartPayload
*
* NAME
- *
+ *
* typedef struct SilcSKEStartPayloadStruct SilcSKEStartPayload;
*
* DESCRIPTION
* silc_ske_payload_start_free function.
*
***/
-typedef struct SilcSKEStartPayloadStruct *SilcSKEStartPayload;
+typedef struct SilcSKEStartPayloadStruct SilcSKEStartPayload;
/****s* silcske/SilcSKEPayloads/SilcSKEKEPayload
*
* NAME
- *
+ *
* typedef struct SilcSKEKEPayloadStruct SilcSKEKEPayload;
*
* DESCRIPTION
*
* This context is the actual Key Exchange Payload and is allocated
* by silc_ske_payload_ke_decode. It is freed by calling the
- * silc_ske_payload_ke_free function.
+ * silc_ske_payload_ke_free function.
*
***/
-typedef struct SilcSKEKEPayloadStruct *SilcSKEKEPayload;
+typedef struct SilcSKEKEPayloadStruct SilcSKEKEPayload;
/* SILC Key Exchange Start Payload */
struct SilcSKEStartPayloadStruct {
SilcUInt16 enc_alg_len;
unsigned char *enc_alg_list;
-
+
SilcUInt16 hash_alg_len;
unsigned char *hash_alg_list;
* SYNOPSIS
*
* SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
- * SilcSKEStartPayload payload,
+ * SilcSKEStartPayload *payload,
* SilcBuffer *return_buffer);
*
* DESCRIPTION
*
***/
SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
- SilcSKEStartPayload payload,
+ SilcSKEStartPayload *payload,
SilcBuffer *return_buffer);
/****f* silcske/SilcSKEPayloads/silc_ske_payload_start_decode
*
* SYNOPSIS
*
- * SilcSKEStatus
+ * SilcSKEStatus
* silc_ske_payload_start_decode(SilcSKE ske,
* SilcBuffer buffer,
- * SilcSKEStartPayload *return_payload);
+ * SilcSKEStartPayload **return_payload);
*
* DESCRIPTION
*
* `return_payload' and the caller must free it.
*
***/
-SilcSKEStatus
+SilcSKEStatus
silc_ske_payload_start_decode(SilcSKE ske,
SilcBuffer buffer,
- SilcSKEStartPayload *return_payload);
+ SilcSKEStartPayload **return_payload);
/****f* silcske/SilcSKEPayloads/silc_ske_payload_start_free
*
* Frees the Key Exchange Start Payload indicated by `payload'.
*
***/
-void silc_ske_payload_start_free(SilcSKEStartPayload payload);
+void silc_ske_payload_start_free(SilcSKEStartPayload *payload);
/****f* silcske/SilcSKEPayloads/silc_ske_payload_ke_encode
*
* SYNOPSIS
*
* SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
- * SilcSKEKEPayload payload,
+ * SilcSKEKEPayload *payload,
* SilcBuffer *return_buffer);
*
* DESCRIPTION
*
***/
SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske,
- SilcSKEKEPayload payload,
+ SilcSKEKEPayload *payload,
SilcBuffer *return_buffer);
/****f* silcske/SilcSKEPayloads/silc_ske_payload_ke_decode
*
* SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
* SilcBuffer buffer,
- * SilcSKEKEPayload
+ * SilcSKEKEPayload
* **return_payload);
*
* DESCRIPTION
***/
SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske,
SilcBuffer buffer,
- SilcSKEKEPayload *return_payload);
+ SilcSKEKEPayload **return_payload);
/****f* silcske/SilcSKEPayloads/silc_ske_payload_ke_free
*
* Frees the Key Exchange Payload indicated by `payload'.
*
***/
-void silc_ske_payload_ke_free(SilcSKEKEPayload payload);
+void silc_ske_payload_ke_free(SilcSKEKEPayload *payload);
#endif /* SILCSKE_PAYLOAD_H */
--- /dev/null
+/*
+
+ 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 */
+++ /dev/null
-<!--
-@LIBRARY=SILC Key Repository Library
-@FILENAME=silcskrlib.html
-@LINK=silcskr.html:SILC SKR Interface
--->
-
-<big><b>SILC Key Repository Library</b></big>
-<br />
-<small>Directory: lib/silcskr/</small>
-<br />
-<small>Library: libsilc.a, libsilc.lib</small>
-<br /><br />
-<b>Introduction</b>
-
-<br /><br />
-SILC Key Repository (SKR) Library can be used to store and retrieve public
-keys and certificates.
-
-<br /><br />
-@LINKS@
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
-
- silcskr.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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"
-
-/* XXX Locking, when removing keys */
-
-/************************** 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:
- silc_snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type],
- (int)SILC_PTR_TO_32(data));
- break;
-
- case SILC_SKR_FIND_PUBLIC_KEY:
- silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
- break;
-
- default:
- silc_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)
- return;
-
- silc_pkcs_public_key_free(entry->key.key);
- 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)
-{
- SilcSKRKeyInternal key;
- SilcSKRStatus status = SILC_SKR_ERROR;
- SilcPublicKeyIdentifier ident;
- SilcSILCPublicKey silc_pubkey;
-
- /* Get the SILC public key */
- silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
- ident = &silc_pubkey->identifier;
-
- SILC_LOG_DEBUG(("Adding SILC public key [%s]", ident->username));
-
- 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 | SILC_SKR_ALREADY_EXIST;
- }
-
- /* 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.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 (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
- SILC_32_TO_PTR(SILC_PKCS_SILC), 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);
-
- return SILC_SKR_OK;
-
- err:
- silc_mutex_unlock(skr->lock);
- 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"));
-
- 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 | SILC_SKR_ALREADY_EXIST;
- }
-
- /* 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.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)
-{
- SilcPKCSType type;
-
- if (!public_key)
- return SILC_SKR_ERROR;
-
- type = silc_pkcs_get_type(public_key);
-
- SILC_LOG_DEBUG(("Adding public key to repository"));
-
- switch (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)
-{
- SilcPKCSType type;
-
- if (!public_key)
- return SILC_SKR_ERROR;
-
- type = silc_pkcs_get_type(public_key);
-
- SILC_LOG_DEBUG(("Adding public key to repository"));
-
- switch (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;
-}
+++ /dev/null
-/*
-
- silcskr.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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, optional public key specific
- * context and public key usage bits. This context is returned in
- * the SilcSKRFindCallback list. Each entry in the list is SIlcSKRKey.
- *
- * SOURCE
- *
- */
-typedef struct SilcSKRKeyStruct {
- SilcSKRKeyUsage usage; /* Key usage */
- SilcPublicKey key; /* Public key */
- 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_USAGE_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_context
- *
- * 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 the finding was not
- * asynchronous, and the `callback' has been called already.
- *
- * EXAMPLE
- *
- * SilcSKRFind find;
- *
- * // Find all SILC public keys originating from Finland
- * find = silc_skr_find_alloc();
- * silc_skr_find_set_pkcs_type(find, SILC_PKCS_SILC);
- * silc_skr_find_set_country(find, "FI");
- *
- * // Find
- * silc_skr_find(skr, find, find_callback, cb_context);
- *
- ***/
-SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
- SilcSKRFindCallback callback,
- void *callback_context);
-
-#include "silcskr_i.h"
-
-#endif /* SILCSKR_H */
+++ /dev/null
-/*
-
- 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 */
+++ /dev/null
-#
-# 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
+++ /dev/null
-/* 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;
-}
<!--
@LIBRARY=SILC Utility Library
@FILENAME=silcutillib.html
-@LINK=silctypes.html:Basic Types and Definitions
-@LINK=silcbuffer.html:Data Buffer Interface
-@LINK=silcbuffmt.html:Data Buffer Format Interface
-@LINK=silchashtable.html:Hash Table Interface
-@LINK=silcmemory.html:Memory Allocation Interface
-@LINK=silcstack.html:Data Stack (memory pool) Interface
-@LINK=silcthread.html:Thread Interface
-@LINK=silcmutex.html:Mutual Exclusion Lock Interface
-@LINK=silccond.html:Conditional Variable Interface
-@LINK=silcatomic.html:Atomic Operations Interface
-@LINK=silcnet.html:Network (TCP and UDP) Interface
-@LINK=silcschedule.html:Scheduler Interface
-@LINK=silcasync.html:Asynchronous Operation Interface
-@LINK=silcstream.html:Abstract Stream Interface
-@LINK=silcsocketstream.html:Socket Stream Interface
-@LINK=silcfdstream.html:File Descriptor Stream Interface
-@LINK=silcfsm.html:Finite State Machine Interface
-@LINK=silcfileutil.html:File Utility Functions
-@LINK=silcstrutil.html:String Utility Interface
-@LINK=silcsnprintf.html:Snprintf Interface
-@LINK=silcutf8.html:UTF-8 String Interface
-@LINK=silcstringprep.html:Stringprep Interface
-@LINK=silcutil.html:Utility Functions
-@LINK=silclist.html:List Interface
-@LINK=silcdlist.html:Dynamic List Interface
-@LINK=silcmime.html:MIME Interface
-@LINK=silctime.html:Time Utility Functions
-@LINK=silclog.html:Logging Interface
-@LINK=silcconfig.html:Config File Interface
+@LINK=silctypes.html:Basic SILC Types
+@LINK=silcbuffer.html:SILC Buffer Interface
+@LINK=silcbuffmt.html:SILC Buffer Format Interface
+@LINK=silchashtable.html:SILC Hash Table Interface
+@LINK=silclog.html:SILC Logging Interface
+@LINK=silcmemory.html:SILC Memory Interface
+@LINK=silcmutex.html:SILC Mutex Interface
+@LINK=silcthread.html:SILC Thread Interface
+@LINK=silcnet.html:SILC Network Interface
+@LINK=silcschedule.html:SILC Schedule Interface
+@LINK=silcsockconn.html:SILC Socket Interface
+@LINK=silcprotocol.html:SILC Protocol Interface
+@LINK=silcconfig.html:SILC Config Interface
+@LINK=silcfileutil.html:SILC File Util Interface
+@LINK=silcstrutil.html:SILC String Util Interface
+@LINK=silcutf8.html:SILC UTF-8 Interface
+@LINK=silcstringprep.html:SILC Stringprep Interface
+@LINK=silcutil.html:SILC Util Interface
+@LINK=silclist.html:SILC List Interface
+@LINK=silcdlist.html:SILC Dynamic List Interface
+@LINK=silcvcard.html:SILC VCard Interface
+@LINK=silcapputil.html:SILC Application Utilities
+@LINK=silcmime.html:SILC MIME Interface
-->
<big><b>SILC Utility Library</b></big>
<b>Introduction</b>
<br /><br />
-SILC Utility Library provides a full featured runtime library for
-applications. It provides the application's main loop, called SILC
-Scheduler, threads, locks, file utilities, file streams, socket streams,
-TCP and UDP network routines, a finite state machine, lists, a hash table,
-UTF-8 routines and other string utilities, and many other utility routines.
-The library works on multiple platforms.
+SILC Utility Library provides various utility routines for the applications.
+For example, it provides the application's main loop, called the SILC
+Scheduler. It can handle all kinds of tasks, like socket connections and
+timeout tasks. The SILC Utility Library also provides various buffer
+management routines. All of these routines work on multiple platforms
+such as Unix and WIN32.
<br /><br />
@LINKS@
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2000 - 2007 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
if SILC_WIN32
SUBDIRS=win32
else
-if SILC_SYMBIAN
-SUBDIRS=symbian
+if SILC_EPOC
+SUBDIRS=epoc
+else
+if SILC_BEOS
+SUBDIRS=beos
+else
+if SILC_OS2
+SUBDIRS=os2
else
SUBDIRS=unix
endif
endif
+endif
+endif
-#ifdef SILC_DIST_TOOLKIT
-DIST_SUBDIRS=win32 symbian unix
-#else !SILC_DIST_TOOLKIT
-#ifdef SILC_DIST_CLIENT
-DIST_SUBDIRS=win32 unix
-#else !SILC_DIST_CLIENT
-#ifdef SILC_DIST_SERVER
-DIST_SUBDIRS=unix
-#endif SILC_DIST_SERVER
-#endif SILC_DIST_CLIENT
-#endif SILC_DIST_TOOLKIT
+DIST_SUBDIRS=win32 epoc beos os2 unix
#ifdef SILC_DIST_TOOLKIT
SILC_DIST_SOURCE = stacktrace.c
libsilcutil_la_SOURCES = \
$(SILC_DIST_SOURCE) \
- silcbuffmt.c \
- silcconfig.c \
- silclog.c \
- silcmemory.c \
- silcnet.c \
- silcschedule.c \
- silcfileutil.c \
- silcstrutil.c \
- silcutil.c \
+ silcbuffmt.c \
+ silcconfig.c \
+ silclog.c \
+ silcmemory.c \
+ silcnet.c \
+ silcschedule.c \
+ silcfileutil.c \
+ silcstrutil.c \
+ silcutil.c \
silchashtable.c \
- silcutf8.c \
- silcstringprep.c \
- silcstream.c \
- silcfdstream.c \
- silcsocketstream.c \
- silcfsm.c \
- silcasync.c \
- silctime.c \
+ silcsockconn.c \
+ silcprotocol.c \
+ silcvcard.c \
+ silcapputil.c \
silcmime.c \
- silcstack.c \
- silcsnprintf.c
+ silcutf8.c \
+ silcstringprep.c
#ifdef SILC_DIST_TOOLKIT
include_HEADERS = \
silclog_i.h \
silcmemory.h \
silcmutex.h \
- silcatomic.h \
- silccond.h \
silcnet.h \
- silcnet_i.h \
silcschedule.h \
- silcschedule_i.h \
+ silcsockconn.h \
+ silcprotocol.h \
silcthread.h \
silclist.h \
silcdlist.h \
silcfileutil.h \
silcutil.h \
silcstrutil.h \
- silcutf8.h \
- silcstringprep.h \
- silctypes.h \
- silcstream.h \
- silcfdstream.h \
- silcsocketstream.h \
- silcsocketstream_i.h \
- silcfsm.h \
- silcfsm_i.h \
- silctime.h \
+ silcvcard.h \
+ silcapputil.h \
silcmime.h \
- silcmime_i.h \
- silcasync.h \
- silcasync_i.h \
- silcstack.h \
- silcstack_i.h \
- silcsnprintf.h
+ silcutf8.h \
+ silcstringprep.h \
+ silctypes.h
SILC_EXTRA_DIST = tests
#endif SILC_DIST_TOOLKIT
/* I used Apache's APR code as a reference here. */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#ifdef SILC_THREADS
sem_id sema;
};
-SilcBool silc_mutex_alloc(SilcMutex *mutex)
+bool silc_mutex_alloc(SilcMutex *mutex)
{
int ret;
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* Maybe works, or maybe not */
#include "../unix/silcunixnet.c"
#ifdef SILC_BEOS_BONE
#include "../unix/silcunixsockconn.c"
#else
-#include "silc.h"
+#include "silcincludes.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.
/* Returns human readable socket error message */
-SilcBool silc_socket_get_error(SilcSocketConnection sock, char *error,
+bool silc_socket_get_error(SilcSocketConnection sock, char *error,
SilcUInt32 error_len)
{
char *err;
since the silc_thread_self() causes that BeOS and OS/2 is hard to
do to support this SilcThread API */
-#include "silc.h"
+#include "silcincludes.h"
#ifdef SILC_THREADS
thread_id thread;
SilcThreadStart start_func;
void *context;
- SilcBool waitable;
+ bool waitable;
} *SilcBeosThread;
/* Actual routine that is called by BeOS when the thread is created.
#endif
SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- SilcBool waitable)
+ bool waitable)
{
#ifdef SILC_THREADS
int ret;
#endif
}
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
+bool silc_thread_wait(SilcThread thread, void **exit_value)
{
#ifdef SILC_THREADS
status_t ret, retval;
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.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
/* I used Apache's APR code as a reference here. */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#ifdef SILC_THREADS
HMTX mutex;
};
-SilcBool silc_mutex_alloc(SilcMutex *mutex)
+bool silc_mutex_alloc(SilcMutex *mutex)
{
char name[64];
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcnet.h"
/* XXX TODO */
#endif
} SilcSockaddr;
-static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
+static bool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
int port)
{
int len;
/* Converts the IP number string from numbers-and-dots notation to
binary form. */
-SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
+bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
{
int ret = 0;
/* XXX TODO */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcschedule_i.h"
/* Calls normal select() system call. */
/* XXX TODO */
-#include "silc.h"
+#include "silcincludes.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.
/* Returns human readable socket error message */
-SilcBool silc_socket_get_error(SilcSocketConnection sock, char *error,
+bool silc_socket_get_error(SilcSocketConnection sock, char *error,
SilcUInt32 error_len)
{
/* XXX TODO */
/* I used Apache's APR code as a reference here. */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.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
unsigned long thread;
SilcThreadStart start_func;
void *context;
- SilcBool waitable;
+ bool waitable;
} *SilcOs2Thread;
/* Actual routine that is called by OS/2 when the thread is created.
#endif
SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- SilcBool waitable)
+ bool waitable)
{
#ifdef SILC_THREADS
int ret;
#endif
}
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
+bool silc_thread_wait(SilcThread thread, void **exit_value)
{
#ifdef SILC_THREADS
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
char *silc_string_regexify(const char *string)
{
--- /dev/null
+/*
+
+ silcapputil.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ 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
+ 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 "silcincludes.h"
+
+static char *silc_create_pk_identifier(void)
+{
+ char *username = NULL, *realname = NULL;
+ char *hostname, email[256];
+ char *ident;
+
+ /* Get realname */
+ realname = silc_get_real_name();
+
+ /* Get hostname */
+ hostname = silc_net_localhost();
+ if (!hostname)
+ return NULL;
+
+ /* Get username (mandatory) */
+ username = silc_get_username();
+ if (!username)
+ return NULL;
+
+ /* Create default email address, whether it is right or not */
+ snprintf(email, sizeof(email), "%s@%s", username, hostname);
+
+ ident = silc_pkcs_encode_identifier(username, hostname, realname, email,
+ NULL, NULL);
+ if (realname)
+ silc_free(realname);
+ silc_free(hostname);
+ silc_free(username);
+
+ return ident;
+}
+
+/* Generate key pair */
+
+bool silc_create_key_pair(const char *pkcs_name,
+ SilcUInt32 key_len_bits,
+ const char *pub_filename,
+ const char *prv_filename,
+ const char *pub_identifier,
+ const char *passphrase,
+ SilcPKCS *return_pkcs,
+ SilcPublicKey *return_public_key,
+ SilcPrivateKey *return_private_key,
+ bool interactive)
+{
+ SilcPKCS pkcs;
+ SilcPublicKey pub_key;
+ SilcPrivateKey prv_key;
+ SilcRng rng;
+ unsigned char *key;
+ SilcUInt32 key_len;
+ char line[256];
+ char *pkfile = pub_filename ? strdup(pub_filename) : NULL;
+ char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
+ char *alg = pkcs_name ? strdup(pkcs_name) : NULL;
+ char *identifier = pub_identifier ? strdup(pub_identifier) : NULL;
+ char *pass = passphrase ? strdup(passphrase) : NULL;
+
+ if (interactive && (!alg || !pub_filename || !prv_filename))
+ printf("\
+New pair of keys will be created. Please, answer to following questions.\n\
+");
+
+ if (!alg) {
+ if (interactive) {
+ while (!alg) {
+ alg = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
+ if (!alg)
+ alg = strdup("rsa");
+
+ if (*alg == 'l' || *alg == 'L') {
+ char *list = silc_pkcs_get_supported();
+ printf("%s\n", list);
+ silc_free(list);
+ silc_free(alg);
+ alg = NULL;
+ }
+ }
+ } else {
+ alg = strdup("rsa");
+ }
+ }
+
+ if (!silc_pkcs_is_supported(alg)) {
+ fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library"
+ "is not initialized", alg);
+ return FALSE;
+ }
+
+ if (!key_len_bits) {
+ if (interactive) {
+ char *length = NULL;
+ length = silc_get_input("Key length in key_len_bits [2048]: ", FALSE);
+ if (length)
+ key_len_bits = atoi(length);
+ silc_free(length);
+ }
+ if (!key_len_bits)
+ key_len_bits = 2048;
+ }
+
+ if (!identifier) {
+ char *def = silc_create_pk_identifier();
+
+ if (interactive) {
+ memset(line, 0, sizeof(line));
+ if (def)
+ snprintf(line, sizeof(line), "Identifier [%s]: ", def);
+ else
+ snprintf(line, sizeof(line),
+ "Identifier (eg. UN=jon, HN=jon.dummy.com, "
+ "RN=Jon Johnson, E=jon@dummy.com): ");
+
+ while (!identifier) {
+ identifier = silc_get_input(line, FALSE);
+ if (!identifier && def)
+ identifier = strdup(def);
+ }
+ } else {
+ if (!def) {
+ fprintf(stderr, "Could not create public key identifier: %s\n",
+ strerror(errno));
+ return FALSE;
+ }
+ identifier = strdup(def);
+ }
+
+ silc_free(def);
+ }
+
+ rng = silc_rng_alloc();
+ silc_rng_init(rng);
+ silc_rng_global_init(rng);
+
+ if (!pkfile) {
+ if (interactive) {
+ memset(line, 0, sizeof(line));
+ snprintf(line, sizeof(line), "Public key filename [public_key.pub]: ");
+ pkfile = silc_get_input(line, FALSE);
+ }
+ if (!pkfile)
+ pkfile = strdup("public_key.pub");
+ }
+
+ if (!prvfile) {
+ if (interactive) {
+ memset(line, 0, sizeof(line));
+ snprintf(line, sizeof(line), "Private key filename [private_key.prv]: ");
+ prvfile = silc_get_input(line, FALSE);
+ }
+ if (!prvfile)
+ prvfile = strdup("private_key.prv");
+ }
+
+ if (!pass) {
+ while (TRUE) {
+ char *pass2 = NULL;
+ pass = silc_get_input("Private key passphrase: ", TRUE);
+ if (!pass) {
+ pass = strdup("");
+ break;
+ } else {
+ bool match;
+ printf("\n");
+ pass2 = silc_get_input("Retype private key passphrase: ", TRUE);
+ if (!pass2)
+ pass2 = strdup("");
+ match = !strcmp(pass, pass2);
+ silc_free(pass2);
+ if (match)
+ break;
+ fprintf(stderr, "\nPassphrases do not match\n\n");
+ }
+ }
+ }
+
+ /* Generate keys */
+ silc_pkcs_alloc(alg, &pkcs);
+ silc_pkcs_generate_key(pkcs, key_len_bits, rng);
+
+ /* Save public key into file */
+ key = silc_pkcs_get_public_key(pkcs, &key_len);
+ pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs),
+ identifier, key, key_len);
+ silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
+ if (return_public_key)
+ *return_public_key = pub_key;
+ else
+ silc_pkcs_public_key_free(pub_key);
+ memset(key, 0, key_len);
+ silc_free(key);
+
+ /* Save private key into file */
+ key = silc_pkcs_get_private_key(pkcs, &key_len);
+ prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
+ key, key_len);
+ silc_pkcs_save_private_key(prvfile, prv_key,
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_BIN);
+ if (return_private_key)
+ *return_private_key = prv_key;
+ else
+ silc_pkcs_private_key_free(prv_key);
+ memset(key, 0, key_len);
+ silc_free(key);
+
+ printf("Public key has been saved into `%s'.\n", pkfile);
+ printf("Private key has been saved into `%s'.\n", prvfile);
+ if (interactive) {
+ printf("Press <Enter> to continue...\n");
+ getchar();
+ }
+
+ if (return_pkcs)
+ *return_pkcs = pkcs;
+ else
+ silc_pkcs_free(pkcs);
+
+ silc_rng_free(rng);
+ silc_free(alg);
+ silc_free(pkfile);
+ silc_free(prvfile);
+ silc_free(identifier);
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+
+ return TRUE;
+}
+
+/* Load key pair */
+
+bool silc_load_key_pair(const char *pub_filename,
+ const char *prv_filename,
+ const char *passphrase,
+ SilcPKCS *return_pkcs,
+ SilcPublicKey *return_public_key,
+ SilcPrivateKey *return_private_key)
+{
+ char *pass = passphrase ? strdup(passphrase) : NULL;
+
+ SILC_LOG_DEBUG(("Loading public and private keys"));
+
+ if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
+ SILC_PKCS_FILE_PEM) == FALSE)
+ if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
+ SILC_PKCS_FILE_BIN) == FALSE) {
+ if (pass)
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+ return FALSE;
+ }
+
+ if (!pass) {
+ pass = silc_get_input("Private key passphrase: ", TRUE);
+ if (!pass)
+ pass = strdup("");
+ }
+
+ if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_BIN) == FALSE)
+ if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_PEM) == FALSE) {
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+ return FALSE;
+ }
+
+ if (return_pkcs) {
+ silc_pkcs_alloc((*return_public_key)->name, return_pkcs);
+ silc_pkcs_public_key_set(*return_pkcs, *return_public_key);
+ silc_pkcs_private_key_set(*return_pkcs, *return_private_key);
+ }
+
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+ return TRUE;
+}
+
+/* Dump public key into stdout */
+
+bool silc_show_public_key(const char *pub_filename)
+{
+ SilcPublicKey public_key;
+ SilcPublicKeyIdentifier ident;
+ char *fingerprint, *babbleprint;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+ SilcPKCS pkcs;
+ SilcUInt32 key_len = 0;
+
+ if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
+ SILC_PKCS_FILE_PEM) == FALSE)
+ if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
+ SILC_PKCS_FILE_BIN) == FALSE) {
+ fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
+ return FALSE;
+ }
+
+ ident = silc_pkcs_decode_identifier(public_key->identifier);
+
+ pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+ babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+
+ if (silc_pkcs_alloc(public_key->name, &pkcs)) {
+ key_len = silc_pkcs_public_key_set(pkcs, public_key);
+ silc_pkcs_free(pkcs);
+ }
+
+ printf("Public key file : %s\n", pub_filename);
+ printf("Algorithm : %s\n", public_key->name);
+ if (key_len)
+ printf("Key length (bits) : %d\n", (unsigned int)key_len);
+ if (ident->realname)
+ printf("Real name : %s\n", ident->realname);
+ if (ident->username)
+ printf("Username : %s\n", ident->username);
+ if (ident->host)
+ printf("Hostname : %s\n", ident->host);
+ if (ident->email)
+ printf("Email : %s\n", ident->email);
+ if (ident->org)
+ printf("Organization : %s\n", ident->org);
+ if (ident->country)
+ printf("Country : %s\n", ident->country);
+ printf("Fingerprint (SHA1) : %s\n", fingerprint);
+ printf("Babbleprint (SHA1) : %s\n", babbleprint);
+
+ fflush(stdout);
+
+ silc_free(fingerprint);
+ silc_free(babbleprint);
+ silc_free(pk);
+ silc_pkcs_public_key_free(public_key);
+ silc_pkcs_free_identifier(ident);
+
+ return TRUE;
+}
+
+/* Change private key passphrase */
+
+bool silc_change_private_key_passphrase(const char *prv_filename,
+ const char *old_passphrase,
+ const char *new_passphrase)
+{
+ SilcPrivateKey private_key;
+ bool base64 = FALSE;
+ char *pass;
+
+ pass = old_passphrase ? strdup(old_passphrase) : NULL;
+ if (!pass) {
+ pass = silc_get_input("Old passphrase: ", TRUE);
+ if (!pass)
+ pass = strdup("");
+ }
+
+ if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_BIN) == FALSE) {
+ base64 = TRUE;
+ if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_PEM) == FALSE) {
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+ fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
+ return FALSE;
+ }
+ }
+
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+
+ pass = new_passphrase ? strdup(new_passphrase) : NULL;
+ if (!pass) {
+ char *pass2 = NULL;
+ fprintf(stdout, "\n");
+ pass = silc_get_input("New passphrase: ", TRUE);
+ if (!pass) {
+ pass = strdup("");
+ } else {
+ while (TRUE) {
+ printf("\n");
+ pass2 = silc_get_input("Retype new passphrase: ", TRUE);
+ if (!pass2)
+ pass2 = strdup("");
+ if (!strcmp(pass, pass2))
+ break;
+ fprintf(stderr, "\nPassphrases do not match");
+ }
+ silc_free(pass2);
+ }
+ }
+
+ silc_pkcs_save_private_key((char *)prv_filename, private_key,
+ (unsigned char *)pass, strlen(pass),
+ base64 ? SILC_PKCS_FILE_PEM : SILC_PKCS_FILE_BIN);
+
+ fprintf(stdout, "\nPassphrase changed\n");
+
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
+
+ silc_pkcs_private_key_free(private_key);
+ return TRUE;
+}
--- /dev/null
+/*
+
+ silcapputil.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 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* silcutil/SILC Application Utilities
+ *
+ * DESCRIPTION
+ *
+ * This interface provides utility functions for applications'
+ * convenience. It provides functions that may be used for example by
+ * command line applications but also other applications may find some
+ * routines helpful. None of these routines are mandatory in any other
+ * SILC routines or libraries, and are purely provided for convenience.
+ * These routines for example provide simple public key and private key
+ * pair generation, public key and private key file saving and loading
+ * for application, and other similar routines.
+ *
+ ***/
+
+#ifndef SILCAPPUTIL_H
+#define SILCAPPUTIL_H
+
+/****f* silcutil/SilcAppUtil/silc_create_key_pair
+ *
+ * SYNOPSIS
+ *
+ * bool silc_create_key_pair(const char *pkcs_name,
+ * SilcUInt32 key_len_bits,
+ * const char *pub_filename,
+ * const char *prv_filename,
+ * const char *pub_identifier,
+ * const char *passphrase,
+ * SilcPKCS *return_pkcs,
+ * SilcPublicKey *return_public_key,
+ * SilcPrivateKey *return_private_key,
+ * bool interactive);
+ *
+ * DESCRIPTION
+ *
+ * This routine can be used to generate new public key and private key
+ * pair. The `pkcs_name' is the name of public key algorithm, or if
+ * NULL it defaults to "rsa". The `key_len_bits' is the key length
+ * in bits and if zero (0) it defaults to 2048 bits. The `pub_filename'
+ * and `prv_filename' is the public key and private key filenames.
+ * The `pub_identifier' is the public key identifier (for example:
+ * "UN=foobar, HN=hostname"), or if NULL the routine generates it
+ * automatically.
+ *
+ * The `passphrase' is the passphrase that is used to encrypt the
+ * private key file. It is recommended that you would protect your
+ * private key file with a passphrase.
+ *
+ * The routine returns FALSE if error occurs during key generation.
+ * Function returns TRUE when success and returns the created SilcPKCS
+ * object, which can be used to perform public key cryptography into
+ * `return_pkcs' pointer, created public key into `return_public_key',
+ * and created private key into `return_private_key' pointer.
+ *
+ * If the `interactive' is TRUE then this asks the user (by blocking
+ * the process for input) some questions about key generation (like
+ * public key algorithm, key length, filenames, etc). If all
+ * arguments are provided to this function already then `interactive'
+ * has no effect.
+ *
+ * NOTES
+ *
+ * Before calling this function the application must have initialized
+ * the crypto library by registering the public key algorithms with
+ * silc_pkcs_register_default function.
+ *
+ ***/
+bool silc_create_key_pair(const char *pkcs_name,
+ SilcUInt32 key_len_bits,
+ const char *pub_filename,
+ const char *prv_filename,
+ const char *pub_identifier,
+ const char *passphrase,
+ SilcPKCS *return_pkcs,
+ SilcPublicKey *return_public_key,
+ SilcPrivateKey *return_private_key,
+ bool interactive);
+
+/****f* silcutil/SilcAppUtil/silc_load_key_pair
+ *
+ * SYNOPSIS
+ *
+ * bool silc_load_key_pair(const char *pub_filename,
+ * const char *prv_filename,
+ * const char *passphrase,
+ * SilcPKCS *return_pkcs,
+ * SilcPublicKey *return_public_key,
+ * SilcPrivateKey *return_private_key);
+ *
+ * DESCRIPTION
+ *
+ * This routine can be used to load the public key and private key
+ * from files. This retuns FALSE it either of the key could not be
+ * loaded. This function returns TRUE on success and returns the
+ * public key into `return_public_key' pointer, private key into
+ * `return_private_key' pointer and the SilcPKCS object to the
+ * `return_pkcs'. The SilcPKCS can be used to perform public key
+ * cryptographic operations. The `passphrase' is the passphrase
+ * which will be used to decrypt the private key file.
+ *
+ ***/
+bool silc_load_key_pair(const char *pub_filename,
+ const char *prv_filename,
+ const char *passphrase,
+ SilcPKCS *return_pkcs,
+ SilcPublicKey *return_public_key,
+ SilcPrivateKey *return_private_key);
+
+/****f* silcutil/SilcAppUtil/silc_show_public_key
+ *
+ * SYNOPSIS
+ *
+ * bool silc_show_public_key(const char *pub_filename);
+ *
+ * DESCRIPTION
+ *
+ * This routine can be used to dump the contents of the public key
+ * in the public key file `pub_filename'. This dumps the public key
+ * into human readable form into stdout. Returns FALSE on error.
+ *
+ ***/
+bool silc_show_public_key(const char *pub_filename);
+
+/****f* silcutil/SilcAppUtil/silc_change_private_key_passphrase
+ *
+ * SYNOPSIS
+ *
+ * bool silc_change_private_key_passphrase(const char *prv_filename,
+ * const char *old_passphrase,
+ * const char *new_passphrase);
+ *
+ * DESCRIPTION
+ *
+ * This routine can be used to change the passphrase of the private
+ * key file, which is used to encrypt the private key. If the old
+ * and new passphrase is not provided for this function this will
+ * prompt for them.
+ *
+ ***/
+bool silc_change_private_key_passphrase(const char *prv_filename,
+ const char *old_passphrase,
+ const char *new_passphrase);
+
+#endif /* SILCAPPUTIL_H */
+++ /dev/null
-/*
-
- silcasync.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005, 2006 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"
-
-/* Halts async operation */
-
-SilcBool silc_async_halt(SilcAsyncOperation op)
-{
- SILC_LOG_DEBUG(("Halting async operation"));
-
- if (op->pause_cb)
- return op->pause_cb(op, TRUE, op->context);
-
- return FALSE;
-}
-
-/* Resumes async operation */
-
-SilcBool silc_async_resume(SilcAsyncOperation op)
-{
- SILC_LOG_DEBUG(("Resuming async operation"));
-
- if (op->pause_cb)
- return op->pause_cb(op, FALSE, op->context);
-
- return FALSE;
-}
-
-/* Aborts async operation */
-
-void silc_async_abort(SilcAsyncOperation op,
- SilcAsyncOperationAbort abort_cb, void *context)
-{
- SILC_LOG_DEBUG(("Aborting async operation"));
-
- if (op->abort_cb)
- op->abort_cb(op, op->context);
-
- if (abort_cb)
- abort_cb(op, context);
-
- silc_async_free(op);
-}
-
-/* Creates new async operation */
-
-SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
- SilcAsyncOperationPause pause_cb,
- void *context)
-{
- SilcAsyncOperation op;
-
- SILC_LOG_DEBUG(("Creating new async operation"));
-
- op = silc_calloc(1, sizeof(*op));
- if (!op)
- return NULL;
-
- silc_async_init(op, abort_cb, pause_cb, context);
-
- op->allocated = TRUE;
-
- return op;
-}
-
-/* Creates new async operation */
-
-SilcBool silc_async_init(SilcAsyncOperation op,
- SilcAsyncOperationAbort abort_cb,
- SilcAsyncOperationPause pause_cb,
- void *context)
-{
- SILC_ASSERT(abort_cb);
- op->abort_cb = abort_cb;
- op->pause_cb = pause_cb;
- op->context = context;
- op->allocated = FALSE;
- return TRUE;
-}
-
-/* Stops async operation */
-
-void silc_async_free(SilcAsyncOperation op)
-{
- if (op->allocated) {
- SILC_LOG_DEBUG(("Stopping async operation"));
- silc_free(op);
- }
-}
-
-/* Return context */
-
-void *silc_async_get_context(SilcAsyncOperation op)
-{
- return op->context;
-}
+++ /dev/null
-/*
-
- silcasync.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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* silcutil/SILC Async Operation Interface
- *
- * DESCRIPTION
- *
- * SILC Async Operation API is an interface that can be used to control
- * asynchronous operations. All functions that take callback as argument
- * should return SilcAsyncOperation context. That context then can be
- * used to control, such as, abort the asynchronous operation. Using
- * SILC Async Operation API, asynchronous functions can be controlled
- * and aborted safely.
- *
- * The SILC Async Operation API is divided in two levels; the underlaying
- * operation level that implements the asynchronous operation, and the
- * upper layer that can control the asynchronous operation. The operation
- * layer must guarantee that if the upper layer aborts the asynchronous
- * operation, no callback function will be called back to the upper layer.
- * This must be remembered when implementing the operation layer.
- *
- ***/
-
-#ifndef SILCASYNC_H
-#define SILCASYNC_H
-
-/****s* silcutil/SilcAsyncOperationAPI/SilcAsyncOperation
- *
- * NAME
- *
- * typedef struct SilcAsyncOperationObject *SilcAsyncOperation;
- *
- * DESCRIPTION
- *
- * The asynchronous operation context allocated by silc_async_alloc.
- * The layer that implements the asynchronous operation allocates this
- * context. The layer that receives this context can use it to control
- * the underlaying asynchronous operation. It is also possible to use
- * a pre-allocated context by using SilcAsyncOperationStruct instead
- * SilcAsyncOperation.
- *
- ***/
-typedef struct SilcAsyncOperationObject *SilcAsyncOperation;
-
-/****s* silcutil/SilcAsyncOperationAPI/SilcAsyncOperationStruct
- *
- * NAME
- *
- * typedef struct SilcAsyncOperationObject SilcAsyncOperationStruct;
- *
- * DESCRIPTION
- *
- * The asynchronous operation context that can be used as a pre-allocated
- * context. This is initialized with silc_async_init. It need not
- * be uninitialized. The layer that implements the asynchronous
- * operation initializes this context. The layer that has access to this
- * context can use it to control the underlaying asynchronous operation.
- *
- ***/
-typedef struct SilcAsyncOperationObject SilcAsyncOperationStruct;
-
-/****f* silcutil/SilcAsyncOperationAPI/SilcAsyncOperationAbort
- *
- * SYNOPSIS
- *
- * typedef void (*SilcAsyncOperationAbort)(SilcAsyncOperation op,
- * void *context);
- *
- * DESCRIPTION
- *
- * This callback is called when upper layer calls the silc_async_abort,
- * and is used to actually perform the abortion of the asynchronous
- * operation. The silc_async_free must not be called in this function.
- *
- * This callback type can also be provided to silc_async_abort function
- * by the upper layer, if it wants that callback is called to the upper
- * layer when aborting the operation.
- *
- ***/
-typedef void (*SilcAsyncOperationAbort)(SilcAsyncOperation op,
- void *context);
-
-/****f* silcutil/SilcAsyncOperationAPI/SilcAsyncOperationPause
- *
- * SYNOPSIS
- *
- * typedef SilcBool (*SilcAsyncOperationPause)(SilcAsyncOperation op,
- * SilcBool pause_operation,
- * void *context);
- *
- * DESCRIPTION
- *
- * This callback is used to halt an operation, if upper layer calls the
- * silc_async_halt function, or to resume an operation if upper layer
- * calls the silc_async_resume, after it has earlier halted the operation.
- * If this callback is implemented it is guaranteed that the asynchronous
- * operation is not progressed when it is halted. If the `pause_operation'
- * is TRUE the operation is halted. If it is FALSE, then the operation
- * resumes its execution. This function returns TRUE if the operation
- * was (or is going to be) halted or resumed, and FALSE on error.
- *
- ***/
-typedef SilcBool (*SilcAsyncOperationPause)(SilcAsyncOperation op,
- SilcBool pause_operation,
- void *context);
-
-/* Upper layer functions for managing asynchronous operations. Layer
- that has received SilcAsyncOperation context can control the async
- operation with these functions. */
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_halt
- *
- * SYNOPSIS
- *
- * SilcBool silc_async_halt(SilcAsyncOperation op);
- *
- * DESCRIPTION
- *
- * Halt the execution of the asynchronous operation. If the operation
- * supports this feature, it is guaranteed that the operation is halted
- * and its execution is not progressed until the silc_async_resume function
- * is called. The operation still can be aborted even if it is halted.
- * If this function is not supported, calling this has no effect and the
- * function returns FALSE. This function is for the upper layer that
- * controls the asynchronous operation.
- *
- ***/
-SilcBool silc_async_halt(SilcAsyncOperation op);
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_resume
- *
- * SYNOPSIS
- *
- * SilcBool silc_async_resume(SilcAsyncOperation op);
- *
- * DESCRIPTION
- *
- * Resume the execution of the asynchronous operation. If the halting of
- * the operation was supported, then this function is used to resume the
- * execution of the operation after it was halted. If this function is
- * not supported, calling this has no effect and the function returns
- * FALSE. This function is for the upper layer that controls the
- * asynchronous operation.
- *
- ***/
-SilcBool silc_async_resume(SilcAsyncOperation op);
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_abort
- *
- * SYNOPSIS
- *
- * void silc_async_abort(SilcAsyncOperation op,
- * SilcAsyncOperationAbort abort_cb, void *context);
- *
- * DESCRIPTION
- *
- * This function is used by upper layer that received SilcAsyncOperation
- * context from an asynchronous function, to abort the asynchronous
- * operation. The `op' becomes invalid after this function returns.
- * It is also guaranteed (assuming the use of this API is implemented
- * correctly) that some other completion callback is not called after
- * the operation was aborted. However, if the caller wants to receive
- * a callback when aborting the caller may specify the `abort_cb' and
- * `context' which will be called after the operation is aborted, but
- * before the `op' becomes invalid. The `abort_cb' is called immediately
- * inside this function.
- *
- ***/
-void silc_async_abort(SilcAsyncOperation op,
- SilcAsyncOperationAbort abort_cb, void *context);
-
-/* The operation layer functions. The layer that performs the async
- operation use these functions. */
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_alloc
- *
- * SYNOPSIS
- *
- * SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
- * SilcAsyncOperationPause pause_cb,
- * void *context);
- *
- * DESCRIPTION
- *
- * Start asynchronous operation, and assign `abort_cb' callback for it,
- * which can be used by some upper layer to abort the asynchronous
- * operation, by calling the silc_async_abort. The layer which calls
- * this function must also call silc_async_free when the asynchronous
- * operation is successfully completed. If it is aborted by upper layer
- * then silc_async_free must not be called, since it is called by the
- * silc_async_abort function.
- *
- * If the `pause_cb' is provided then the upper layer may also halt and
- * then later resume the execution of the operation, by calling the
- * silc_async_halt and silc_async_resume respectively. If `pause_cb' is
- * not provided then these functions has no effect for this operation.
- *
- * EXAMPLE
- *
- * SilcAsyncOperation silc_async_call(Callback callback, void *cb_context)
- * {
- * SilcAsyncOperation op;
- * ...
- *
- * // Allocate async operation so that caller can control us, like abort
- * op = silc_async_alloc(silc_async_call_abort, NULL, ctx);
- *
- * // Start async operation in FSM
- * silc_fsm_init(&ctx->fsm, ctx, fsm_destructor, ctx, schedule);
- * silc_fsm_start(&ctx->fsm, first_state);
- * ...
- *
- * // Return async operation for upper layer
- * return op;
- * }
- *
- ***/
-SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
- SilcAsyncOperationPause pause_cb,
- void *context);
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_init
- *
- * SYNOPSIS
- *
- * SilcBool silc_async_init(SilcAsyncOperation op,
- * SilcAsyncOperationAbort abort_cb,
- * SilcAsyncOperationPause pause_cb,
- * void *context);
- *
- * DESCRIPTION
- *
- * Initializes and starts a pre-allocated asynchronous operation context,
- * and assigns `abort_cb' callback for it, which can be used by some upper
- * layer to abort the asynchronous operation, by calling the
- * silc_async_abort. Since this use pre-allocated context, the function
- * silc_async_free need not be called. This function is equivalent
- * to silc_async_alloc except this does not allocate any memory. The `op'
- * needs not be uninitialized.
- *
- * If the `pause_cb' is provided then the upper layer may also halt and
- * then later resume the execution of the operation, by calling the
- * silc_async_halt and silc_async_resume respectively. If `pause_cb' is
- * not provided then these functions has no effect for this operation.
- *
- ***/
-SilcBool silc_async_init(SilcAsyncOperation op,
- SilcAsyncOperationAbort abort_cb,
- SilcAsyncOperationPause pause_cb,
- void *context);
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_free
- *
- * SYNOPSIS
- *
- * void silc_async_free(SilcAsyncOperation op);
- *
- * DESCRIPTION
- *
- * Stop the asynchronous operation. If the asynchronous operation ended
- * normally (ie. it was not aborted) this function must be called by the
- * caller who called silc_async_alloc. The `op' will become invalid after
- * this and the upper layer must not call silc_async_abort after this
- * function is called. The layer that calls this, must call some other
- * completion callback to the upper layer, so that it knows that the
- * asynchronous operation is completed.
- *
- ***/
-void silc_async_free(SilcAsyncOperation op);
-
-/****f* silcutil/SilcAsyncOperationAPI/silc_async_get_context
- *
- * SYNOPSIS
- *
- * void *silc_async_get_context(SilcAsyncOperation op);
- *
- * DESCRIPTION
- *
- * Returns the context that was given to the silc_async_alloc or
- * silc_async_init.
- *
- ***/
-void *silc_async_get_context(SilcAsyncOperation op);
-
-#include "silcasync_i.h"
-
-#endif /* SILCASYNC_H */
+++ /dev/null
-/*
-
- silcasync_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 SILCASYNC_I_H
-#define SILCASYNC_I_H
-
-#ifndef SILCASYNC_H
-#error "Do not include this header directly"
-#endif
-
-/* Async operation context */
-struct SilcAsyncOperationObject {
- SilcAsyncOperationAbort abort_cb;
- SilcAsyncOperationPause pause_cb;
- void *context;
- unsigned int allocated : 1;
-};
-
-#endif /* SILCASYNC_I_H */
+++ /dev/null
-/*
-
- silcatomic.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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* silcutil/SILC Atomic Operations Interface
- *
- * DESCRIPTION
- *
- * SILC Atomic operations interface provides utility functions to perform
- * simple operations with integers atomically. This enables fast integer
- * additions and subtractions safely in multithreaded environment. It is
- * especially suited for reference counters and similar and is much faster
- * than using locking. This interface supports 8, 16 and 32 bit integers
- * and 32 or 64 bit pointers.
- *
- * On some platforms this interface actually use mutual exclusion lock
- * instead of true atomic operations, leading into some performace penalty.
- * Also on some platforms the 8 and 16 bit integers are actually 32 bit
- * integers.
- *
- * Fast operations are supported on: x86, x86_64, ia64, PPC
- *
- ***/
-
-#ifndef SILCATOMIC_H
-#define SILCATOMIC_H
-
-/* For now we always assume SMP */
-#define SILC_SMP 1
-
-/* Use lock prefix only on true SMP systems */
-#ifdef SILC_SMP
-#define SILC_SMP_LOCK "lock; "
-#else
-#define SILC_SMP_LOCK
-#endif /* SILC_SMP */
-
-/****s* silcutil/SilcAtomicAPI/SilcAtomic32
- *
- * NAME
- *
- * typedef struct { ... } SilcAtomic32;
- *
- * DESCRIPTION
- *
- * The atomic operation structure given as argument to all atomic
- * operation functions. It hols the actual 32-bit atomic variable.
- *
- * EXAMPLE
- *
- * SilcAtomic32 refcnt;
- *
- * // Initialize atomic variable
- * silc_atomic_init32(&refcnt, 0);
- *
- * ...
- * // Increment referene counter
- * silc_atomic_add_int32(&refcnt, 1);
- * ...
- *
- * // Uninitialize atomic variable
- * silc_atomic_uninit32(&refcnt);
- *
- ***/
-
-/****s* silcutil/SilcAtomicAPI/SilcAtomic16
- *
- * NAME
- *
- * typedef struct { ... } SilcAtomic16;
- *
- * DESCRIPTION
- *
- * The atomic operation structure given as argument to all atomic
- * operation functions. It hols the actual 16-bit atomic variable.
- *
- * EXAMPLE
- *
- * SilcAtomic16 refcnt;
- *
- * // Initialize atomic variable
- * silc_atomic_init16(&refcnt, 0);
- *
- * ...
- * // Increment referene counter
- * silc_atomic_add_int16(&refcnt, 1);
- * ...
- *
- * // Uninitialize atomic variable
- * silc_atomic_uninit16(&refcnt);
- *
- ***/
-
-/****s* silcutil/SilcAtomicAPI/SilcAtomic8
- *
- * NAME
- *
- * typedef struct { ... } SilcAtomic8;
- *
- * DESCRIPTION
- *
- * The atomic operation structure given as argument to all atomic
- * operation functions. It hols the actual 8-bit atomic variable.
- *
- * EXAMPLE
- *
- * SilcAtomic8 refcnt;
- *
- * // Initialize atomic variable
- * silc_atomic_init8(&refcnt, 0);
- *
- * ...
- * // Increment referene counter
- * silc_atomic_add_int8(&refcnt, 1);
- * ...
- *
- * // Uninitialize atomic variable
- * silc_atomic_uninit8(&refcnt);
- *
- ***/
-
-/****s* silcutil/SilcAtomicAPI/SilcAtomicPointer
- *
- * NAME
- *
- * typedef struct { ... } SilcAtomicPointer;
- *
- * DESCRIPTION
- *
- * The atomic operation structure given as argument to all atomic
- * operation functions. It hols the actual pointer variable.
- *
- * EXAMPLE
- *
- * SilcAtomicPointer ptr;
- *
- * // Initialize atomic variable
- * silc_atomic_init_pointer(&ptr, NULL);
- *
- * ...
- * // Set pointer
- * silc_atomic_set_pointer(&ptr, context);
- * ...
- *
- * // Uninitialize atomic variable
- * silc_atomic_uninit_pointer(&ptr);
- *
- ***/
-
-#if !defined(SILC_THREADS) || defined(SILC_WIN32) || (defined(__GNUC__) && \
- (defined(SILC_I486) || defined(SILC_X86_64) || defined(SILC_IA64) || \
- defined(SILC_POWERPC)))
-typedef struct {
- volatile SilcUInt32 value;
-} SilcAtomic32;
-typedef struct {
- volatile void *value;
-} SilcAtomicPointer;
-#else
-#define SILC_ATOMIC_MUTEX
-typedef struct {
- SilcMutex lock;
- volatile SilcUInt32 value;
-} SilcAtomic32;
-typedef struct {
- SilcMutex lock;
- volatile void *value;
-} SilcAtomicPointer;
-#endif
-
-#if !defined(SILC_THREADS) || (defined(__GNUC__) && (defined(SILC_I486) || \
- defined(SILC_X86_64)))
-typedef struct {
- volatile SilcUInt16 value;
-} SilcAtomic16;
-#elif defined(SILC_WIN32) || (defined(__GNUC__) && (defined(SILC_IA64) || \
- defined(SILC_POWERPC)))
-typedef struct {
- volatile SilcUInt32 value;
-} SilcAtomic16;
-#else
-typedef struct {
- SilcMutex lock;
- volatile SilcUInt16 value;
-} SilcAtomic16;
-#endif
-
-#if !defined(SILC_THREADS) || (defined(__GNUC__) && (defined(SILC_I486) || \
- defined(SILC_X86_64)))
-typedef struct {
- volatile SilcUInt8 value;
-} SilcAtomic8;
-#elif defined(SILC_WIN32) || (defined(__GNUC__) && (defined(SILC_IA64) || \
- defined(SILC_POWERPC)))
-typedef struct {
- volatile SilcUInt32 value;
-} SilcAtomic8;
-#else
-typedef struct {
- SilcMutex lock;
- volatile SilcUInt8 value;
-} SilcAtomic8;
-#endif
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_init32
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_init32(SilcAtomic32 *atomic, SilcUInt32 value);
- *
- * DESCRIPTION
- *
- * Initializes the atomic variable `atomic', and sets the `value' as its
- * inital value. Returns FALSE on error. To uninitialize call the
- * silc_atomic_uninit32 function.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_init16
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_init16(SilcAtomic16 *atomic, SilcUInt16 value);
- *
- * DESCRIPTION
- *
- * Initializes the atomic variable `atomic', and sets the `value' as its
- * inital value. Returns FALSE on error. To uninitialize call the
- * silc_atomic_uninit32 function.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_init8
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_init8(SilcAtomic8 *atomic, SilcUInt8 value);
- *
- * DESCRIPTION
- *
- * Initializes the atomic variable `atomic', and sets the `value' as its
- * inital value. Returns FALSE on error. To uninitialize call the
- * silc_atomic_uninit8 function.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_init_pointer
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_init_pointer(SilcAtomicPointer *atomic,
- * void *pointer);
- *
- * DESCRIPTION
- *
- * Initializes the atomic pointer variable `atomic', and sets the `pointer'
- * as its inital pointer. Returns FALSE on error. To uninitialize call
- * the silc_atomic_uninit_pointer function.
- *
- ***/
-
-#define SILC_ATOMIC_INIT_F(name, bits, type) \
-static inline \
-SilcBool silc_atomic_init##name(SilcAtomic##bits *atomic, type value)
-
-#if defined(SILC_ATOMIC_MUTEX)
-#define SILC_ATOMIC_INIT(name, bits, type) \
-SILC_ATOMIC_INIT_F(name, bits, type) \
-{ \
- atomic->value = value; \
- return silc_mutex_alloc(&atomic->lock); \
-}
-#else
-#define SILC_ATOMIC_INIT(name, bits, type) \
-SILC_ATOMIC_INIT_F(name, bits, type) \
-{ \
- atomic->value = value; \
- return TRUE; \
-}
-#endif /* SILC_ATOMIC_MUTEX */
-
-SILC_ATOMIC_INIT(8, 8, SilcUInt8);
-SILC_ATOMIC_INIT(16, 16, SilcUInt16);
-SILC_ATOMIC_INIT(32, 32, SilcUInt32);
-SILC_ATOMIC_INIT(_pointer, Pointer, void *);
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit32
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_uninit32(SilcAtomic32 *atomic);
- *
- * DESCRIPTION
- *
- * Uninitializes the atomic variable `atomic'. This should alwyas be
- * called after the atomic variable is not used anymore.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit16
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_uninit16(SilcAtomic16 *atomic);
- *
- * DESCRIPTION
- *
- * Uninitializes the atomic variable `atomic'. This should alwyas be
- * called after the atomic variable is not used anymore.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit8
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_uninit8(SilcAtomic8 *atomic);
- *
- * DESCRIPTION
- *
- * Uninitializes the atomic variable `atomic'. This should alwyas be
- * called after the atomic variable is not used anymore.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_uninit_pointer
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_uninit_pointer(SilcAtomicPointer *atomic);
- *
- * DESCRIPTION
- *
- * Uninitializes the atomic variable `atomic'. This should alwyas be
- * called after the atomic variable is not used anymore.
- *
- ***/
-
-#define SILC_ATOMIC_UNINIT_F(bits, t) \
-static inline void silc_atomic_uninit##bits(SilcAtomic##t *atomic)
-
-#if defined(SILC_ATOMIC_MUTEX)
-#define SILC_ATOMIC_UNINIT(bits, t) \
-SILC_ATOMIC_UNINIT_F(bits, t) \
-{ \
- silc_mutex_free(atomic->lock); \
-}
-#else
-#define SILC_ATOMIC_UNINIT(bits, t) \
-SILC_ATOMIC_UNINIT_F(bits, t) \
-{ \
-}
-#endif /* SILC_ATOMIC_MUTEX */
-
-SILC_ATOMIC_UNINIT(8, 8);
-SILC_ATOMIC_UNINIT(16, 16);
-SILC_ATOMIC_UNINIT(32, 32);
-SILC_ATOMIC_UNINIT(_pointer, Pointer);
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_set_int32
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_set_int32(SilcAtomic32 *atomic, SilcUInt32 value);
- *
- * DESCRIPTION
- *
- * Atomically sets `value' to 32-bit integer.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_set_int16
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_set_int16(SilcAtomic16 *atomic, SilcUInt16 value);
- *
- * DESCRIPTION
- *
- * Atomically sets `value' to 16-bit integer.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_set_int8
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_set_int8(SilcAtomic8 *atomic, SilcUInt8 value);
- *
- * DESCRIPTION
- *
- * Atomically sets `value' to 8-bit integer.
- *
- ***/
-
-#define SILC_ATOMIC_SET_INT_F(bits) \
-static inline void silc_atomic_set_int##bits(SilcAtomic##bits *atomic, \
- SilcUInt##bits value)
-
-#if !defined(SILC_THREADS)
-#define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
-SILC_ATOMIC_SET_INT_F(bits) \
-{ \
- /* No atomic operations */ \
- atomic->value = value; \
-}
-
-#elif defined(SILC_WIN32)
-#define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
-SILC_ATOMIC_SET_INT_F(bits) \
-{ \
- /* Windows */ \
- InterlockedExchange((LONG)&atomic->value, (LONG)value); \
-}
-
-#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-#define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
-SILC_ATOMIC_SET_INT_F(bits) \
-{ \
- /* GCC + i486 or x86_64 */ \
- __asm __volatile("xchg" bp " %" bp2 "0, %1" \
- : "=r" (value) \
- : "m" (atomic->value), "0" (value)); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
-#define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
-SILC_ATOMIC_SET_INT_F(bits) \
-{ \
- /* IA64, memory barrier needed */ \
- atomic->value = value; \
- __sync_synchronize(); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-#define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
-SILC_ATOMIC_SET_INT_F(bits) \
-{ \
- /* PowerPC, memory barrier needed */ \
- atomic->value = value; \
- __asm("sync" : : : "memory"); \
-}
-
-#else /* SILC_ATOMIC_MUTEX */
-#define SILC_ATOMIC_SET_INT(bits, bp, bp2) \
-SILC_ATOMIC_SET_INT_F(bits) \
-{ \
- /* Mutex */ \
- silc_mutex_lock(atomic->lock); \
- atomic->value = value; \
- silc_mutex_unlock(atomic->lock); \
-}
-#endif /* !SILC_THREADS */
-
-SILC_ATOMIC_SET_INT(8, "b", "b");
-SILC_ATOMIC_SET_INT(16, "w", "w");
-SILC_ATOMIC_SET_INT(32, "l", "");
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_set_pointer
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer);
- *
- * DESCRIPTION
- *
- * Atomically sets `pointer' to the atomic variable.
- *
- ***/
-
-static inline
-void silc_atomic_set_pointer(SilcAtomicPointer *atomic, void *pointer)
-{
-#if !defined(SILC_THREADS) || \
- (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
- /* No threads, Windows, i486 or x86_64, no memory barrier needed */
- atomic->value = pointer;
-
-#elif defined(SILC_WIN32)
- InterlockedExchangePointer(&atomic->value, pointer);
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
- /* IA64, memory barrier needed */
- atomic->value = pointer;
- __sync_synchronize();
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
- /* PowerPC, memory barrier needed */
- atomic->value = pointer;
- __asm("sync" : : : "memory");
-
-#else
- /* Mutex */
- silc_mutex_lock(atomic->lock);
- atomic->value = pointer;
- silc_mutex_unlock(atomic->lock);
-#endif
-}
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int32
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt32 silc_atomic_get_int32(SilcAtomic32 *atomic);
- *
- * DESCRIPTION
- *
- * Returns the current value of the atomic variable.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int16
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt32 silc_atomic_get_int16(SilcAtomic16 *atomic);
- *
- * DESCRIPTION
- *
- * Returns the current value of the atomic variable.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_get_int8
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt32 silc_atomic_get_int8(SilcAtomic8 *atomic);
- *
- * DESCRIPTION
- *
- * Returns the current value of the atomic variable.
- *
- ***/
-
-#define SILC_ATOMIC_GET_INT_F(bits) \
-static inline \
-SilcUInt##bits silc_atomic_get_int##bits(SilcAtomic##bits *atomic)
-
-#if !defined(SILC_THREADS) || defined(SILC_WIN32) || \
- (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
-#define SILC_ATOMIC_GET_INT(bits) \
-SILC_ATOMIC_GET_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- \
- /* No threads, Windows, i486 or x86_64, no memory barrier needed */ \
- ret = atomic->value; \
- return ret; \
-}
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
-#define SILC_ATOMIC_GET_INT(bits) \
-SILC_ATOMIC_GET_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- \
- /* IA64, memory barrier needed */ \
- __sync_synchronize(); \
- ret = atomic->value; \
- return ret; \
-}
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-#define SILC_ATOMIC_GET_INT(bits) \
-SILC_ATOMIC_GET_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- \
- /* PowerPC, memory barrier needed */ \
- __asm("sync" : : : "memory"); \
- ret = atomic->value; \
- return ret; \
-}
-
-#else /* SILC_ATOMIC_MUTEX */
-#define SILC_ATOMIC_GET_INT(bits) \
-SILC_ATOMIC_GET_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- \
- /* Mutex */ \
- silc_mutex_lock(atomic->lock); \
- ret = atomic->value; \
- silc_mutex_unlock(atomic->lock); \
- return ret; \
-}
-#endif /* !SILC_THREADS */
-
-SILC_ATOMIC_GET_INT(8);
-SILC_ATOMIC_GET_INT(16);
-SILC_ATOMIC_GET_INT(32);
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_get_pointer
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt8 silc_atomic_get_pointer(SilcAtomicPointer *atomic)
- *
- * DESCRIPTION
- *
- * Returns the current pointer value of the atomic variable.
- *
- ***/
-
-static inline
-void *silc_atomic_get_pointer(SilcAtomicPointer *atomic)
-{
- void *ret;
-
-#if !defined(SILC_THREADS) || defined(SILC_WIN32) || \
- (defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64)))
- /* No threads, Windows, i486 or x86_64, no memory barrier needed */
- ret = (void *)atomic->value;
- return ret;
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
- /* IA64, memory barrier needed */
- __sync_synchronize();
- ret = (void *)atomic->value;
- return ret;
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
- /* PowerPC, memory barrier needed */
- __asm("sync" : : : "memory");
- ret = (void *)atomic->value;
- return ret;
-
-#else
- /* Mutex */
- silc_mutex_lock(atomic->lock);
- ret = (void *)atomic->value;
- silc_mutex_unlock(atomic->lock);
- return ret;
-#endif
-}
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int32
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt32 silc_atomic_add_int32(SilcAtomic32 *atomic, SilcInt32 value);
- *
- * DESCRIPTION
- *
- * Atomically adds `value' to 32-bit integer. Returns the value after
- * addition.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int16
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt16 silc_atomic_add_int16(SilcAtomic16 *atomic, SilcInt16 value);
- *
- * DESCRIPTION
- *
- * Atomically adds `value' to 16-bit integer. Returns the value after
- * addition.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_add_int8
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt8 silc_atomic_add_int8(SilcAtomic8 *atomic, SilcInt8 value);
- *
- * DESCRIPTION
- *
- * Atomically adds `value' to 8-bit integer. Returns the value after
- * addition.
- *
- ***/
-
-#define SILC_ATOMIC_ADD_INT_F(bits) \
-static inline \
-SilcUInt##bits silc_atomic_add_int##bits(SilcAtomic##bits *atomic, \
- SilcInt##bits value)
-
-#if !defined(SILC_THREADS)
-#define SILC_ATOMIC_ADD_INT(bits, bp) \
-SILC_ATOMIC_ADD_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- /* No atomic operations */ \
- ret = atomic->value; \
- atomic->value += value; \
- return ret + value; \
-}
-
-#elif defined(SILC_WIN32)
-#define SILC_ATOMIC_ADD_INT(bits, bp) \
-SILC_ATOMIC_ADD_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- LONG val = value; \
- /* Windows */ \
- ret = InterlockedExchangeAdd(&atomic->value, val); \
- return ret + value; \
-}
-
-#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-#define SILC_ATOMIC_ADD_INT(bits, bp) \
-SILC_ATOMIC_ADD_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- /* GCC + i486 or x86_64 */ \
- __asm __volatile(SILC_SMP_LOCK "xadd" bp " %0, %1" \
- : "=r" (ret), "+m" (atomic->value) \
- : "0" (value)); \
- return ret + value; \
-}
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
-#define SILC_ATOMIC_ADD_INT(bits, bp) \
-SILC_ATOMIC_ADD_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- SilcInt32 val = value;
- /* GCC + IA64 (GCC builtin atomic operations) */ \
- ret = __sync_fetch_and_add(&atomic->value, val); \
- return ret + value; \
-}
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-#define SILC_ATOMIC_ADD_INT(bits, bp) \
-SILC_ATOMIC_ADD_INT_F(bits) \
-{ \
- SilcUInt32 ret; \
- SilcInt32 val = value; \
- /* GCC + PowerPC (code adapted from IBM's documentation) */ \
- __asm __volatile("0: lwarx %0, 0, %2\n" \
- " add %0, %1, %0\n" \
- " stwcx. %0, 0, %2\n" \
- " bne- 0b" \
- : "=&r" (ret) \
- : "r" (val), "r" (&atomic->value) \
- : "cc"); \
- return ret; \
-}
-
-#else /* SILC_ATOMIC_MUTEX */
-#define SILC_ATOMIC_ADD_INT(bits, bp) \
-SILC_ATOMIC_ADD_INT_F(bits) \
-{ \
- SilcUInt##bits ret; \
- /* Mutex */ \
- silc_mutex_lock(atomic->lock); \
- ret = atomic->value; \
- atomic->value += value; \
- silc_mutex_unlock(atomic->lock); \
- return ret + value; \
-}
-#endif /* !SILC_THREADS */
-
-SILC_ATOMIC_ADD_INT(8, "b");
-SILC_ATOMIC_ADD_INT(16, "w");
-SILC_ATOMIC_ADD_INT(32, "l");
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int32
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt32 silc_atomic_sub_int32(SilcAtomic32 *atomic, SilcInt32 value);
- *
- * DESCRIPTION
- *
- * Atomically subtracts `value' from 32-bit integer. Returns the value
- * after subtraction.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int16
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt16 silc_atomic_sub_int16(SilcAtomic16 *atomic, SilcInt16 value);
- *
- * DESCRIPTION
- *
- * Atomically subtracts `value' from 16-bit integer. Returns the value
- * after subtraction.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_sub_int8
- *
- * SYNOPSIS
- *
- * static inline
- * SilcUInt8 silc_atomic_sub_int8(SilcAtomic8 *atomic, SilcInt8 value);
- *
- * DESCRIPTION
- *
- * Atomically subtracts `value' from 8-bit integer. Returns the value
- * after subtraction.
- *
- ***/
-
-#define silc_atomic_sub_int8(a, v) silc_atomic_add_int8(a, (-v))
-#define silc_atomic_sub_int16(a, v) silc_atomic_add_int16(a, (-v))
-#define silc_atomic_sub_int32(a, v) silc_atomic_add_int32(a, (-v))
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_inc32
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_inc32(SilcAtomic32 *atomic);
- *
- * DESCRIPTION
- *
- * Atomically increments 32-bit integer by one.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_inc16
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_inc16(SilcAtomic16 *atomic);
- *
- * DESCRIPTION
- *
- * Atomically increments 16-bit integer by one.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_inc8
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_inc8(SilcAtomic8 *atomic);
- *
- * DESCRIPTION
- *
- * Atomically increments 8-bit integer by one.
- *
- ***/
-
-#define SILC_ATOMIC_INC_F(bits) \
-static inline void silc_atomic_inc##bits(SilcAtomic##bits *atomic)
-
-#if !defined(SILC_THREADS)
-#define SILC_ATOMIC_INC(bits, bp) \
-SILC_ATOMIC_INC_F(bits) \
-{ \
- /* No atomic operations */ \
- ++atomic->value; \
-}
-
-#elif defined(SILC_WIN32)
-#define SILC_ATOMIC_INC(bits, bp) \
-SILC_ATOMIC_INC_F(bits) \
-{ \
- /* Windows */ \
- InterlockedIncrement((LONG)&atomic->value); \
-}
-
-#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-#define SILC_ATOMIC_INC(bits, bp) \
-SILC_ATOMIC_INC_F(bits) \
-{ \
- /* GCC + i486 or x86_64 */ \
- __asm __volatile(SILC_SMP_LOCK "inc" bp " %0" \
- : "+m" (atomic->value)); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
-#define SILC_ATOMIC_INC(bits, bp) \
-SILC_ATOMIC_INC_F(bits) \
-{ \
- /* GCC + IA64 (GCC builtin atomic operations) */ \
- __sync_fetch_and_add(&atomic->value, 1); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-#define SILC_ATOMIC_INC(bits, bp) \
-SILC_ATOMIC_INC_F(bits) \
-{ \
- SilcUInt32 ret; \
- SilcInt32 val = 1; \
- /* GCC + PowerPC (code adapted from IBM's documentation) */ \
- __asm __volatile("0: lwarx %0, 0, %2\n" \
- " add %0, %1, %0\n" \
- " stwcx. %0, 0, %2\n" \
- " bne- 0b" \
- : "=&r" (ret) \
- : "r" (val), "r" (&atomic->value) \
- : "cc"); \
-}
-
-#else /* SILC_ATOMIC_MUTEX */
-#define SILC_ATOMIC_INC(bits, bp) \
-SILC_ATOMIC_INC_F(bits) \
-{ \
- /* Mutex */ \
- silc_mutex_lock(atomic->lock); \
- ++atomic->value; \
- silc_mutex_unlock(atomic->lock); \
-}
-#endif /* !SILC_THREADS */
-
-SILC_ATOMIC_INC(8, "b");
-SILC_ATOMIC_INC(16, "w");
-SILC_ATOMIC_INC(32, "l");
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_dec32
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_dec32(SilcAtomic32 *atomic);
- *
- * DESCRIPTION
- *
- * Atomically decrements 32-bit integer by one.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_dec16
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_dec16(SilcAtomic16 *atomic);
- *
- * DESCRIPTION
- *
- * Atomically decrements 16-bit integer by one.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_dec8
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_atomic_dec8(SilcAtomic8 *atomic);
- *
- * DESCRIPTION
- *
- * Atomically decrements 8-bit integer by one.
- *
- ***/
-
-#define SILC_ATOMIC_DEC_F(bits) \
-static inline void silc_atomic_dec##bits(SilcAtomic##bits *atomic)
-
-#if !defined(SILC_THREADS)
-#define SILC_ATOMIC_DEC(bits, bp) \
-SILC_ATOMIC_DEC_F(bits) \
-{ \
- /* No atomic operations */ \
- --atomic->value; \
-}
-
-#elif defined(SILC_WIN32)
-#define SILC_ATOMIC_DEC(bits, bp) \
-SILC_ATOMIC_DEC_F(bits) \
-{ \
- /* Windows */ \
- InterlockedDecrement((LONG)&atomic->value); \
-}
-
-#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-#define SILC_ATOMIC_DEC(bits, bp) \
-SILC_ATOMIC_DEC_F(bits) \
-{ \
- /* GCC + i486 or x86_64 */ \
- __asm __volatile(SILC_SMP_LOCK "dec" bp " %0" \
- : "+m" (atomic->value)); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
-#define SILC_ATOMIC_DEC(bits, bp) \
-SILC_ATOMIC_DEC_F(bits) \
-{ \
- /* GCC + IA64 (GCC builtin atomic operations) */ \
- __sync_fetch_and_sub(&atomic->value, 1); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-#define SILC_ATOMIC_DEC(bits, bp) \
-SILC_ATOMIC_DEC_F(bits) \
-{ \
- SilcUInt32 ret; \
- SilcInt32 val = -1; \
- /* GCC + PowerPC (code adapted from IBM's documentation) */ \
- __asm __volatile("0: lwarx %0, 0, %2\n" \
- " add %0, %1, %0\n" \
- " stwcx. %0, 0, %2\n" \
- " bne- 0b" \
- : "=&r" (ret) \
- : "r" (val), "r" (&atomic->value) \
- : "cc"); \
-}
-
-#else /* SILC_ATOMIC_MUTEX */
-#define SILC_ATOMIC_DEC(bits, bp) \
-SILC_ATOMIC_DEC_F(bits) \
-{ \
- /* Mutex */ \
- silc_mutex_lock(atomic->lock); \
- --atomic->value; \
- silc_mutex_unlock(atomic->lock); \
-}
-#endif /* !SILC_THREADS */
-
-SILC_ATOMIC_DEC(8, "b");
-SILC_ATOMIC_DEC(16, "w");
-SILC_ATOMIC_DEC(32, "l");
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_cas32
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_cas32(SilcAtomic32 *atomic, SilcUInt32 old_val,
- * SilcUInt32 new_val)
- *
- * DESCRIPTION
- *
- * Performs compare and swap (CAS). Atomically compares if the variable
- * `atomic' has the value `old_val' and in that case swaps it with the
- * value `new_val'. Returns TRUE if the old value was same and it was
- * swapped and FALSE if it differed and was not swapped.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_cas16
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_cas16(SilcAtomic16 *atomic, SilcUInt16 old_val,
- * SilcUInt16 new_val)
- *
- * DESCRIPTION
- *
- * Performs compare and swap (CAS). Atomically compares if the variable
- * `atomic' has the value `old_val' and in that case swaps it with the
- * value `new_val'. Returns TRUE if the old value was same and it was
- * swapped and FALSE if it differed and was not swapped.
- *
- ***/
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_cas8
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_cas8(SilcAtomic8 *atomic, SilcUInt8 old_val,
- * SilcUInt8 new_val)
- *
- * DESCRIPTION
- *
- * Performs compare and swap (CAS). Atomically compares if the variable
- * `atomic' has the value `old_val' and in that case swaps it with the
- * value `new_val'. Returns TRUE if the old value was same and it was
- * swapped and FALSE if it differed and was not swapped.
- *
- ***/
-
-#define SILC_ATOMIC_CAS_F(bits) \
-static inline SilcBool silc_atomic_cas##bits(SilcAtomic##bits *atomic, \
- SilcInt##bits old_val, \
- SilcInt##bits new_val)
-
-#if !defined(SILC_THREADS)
-#define SILC_ATOMIC_CAS(bits, bp) \
-SILC_ATOMIC_CAS_F(bits) \
-{ \
- /* No atomic operations */ \
- if (atomic->value == (SilcUInt##bits)old_val) { \
- atomic->value = new_val; \
- return TRUE; \
- } \
- return FALSE; \
-}
-
-#elif defined(SILC_WIN32)
-#define SILC_ATOMIC_CAS(bits, bp) \
-SILC_ATOMIC_CAS_F(bits) \
-{ \
- /* Windows */ \
- LONG o = old_val, n = new_val; \
- return InterlockedCompareExchange(&atomic->value, n, o) == o; \
-}
-
-#elif defined(__GNUC__) && (defined(SILC_I486) || defined(SILC_X86_64))
-#define SILC_ATOMIC_CAS(bits, bp) \
-SILC_ATOMIC_CAS_F(bits) \
-{ \
- /* GCC + i486 or x86_64 */ \
- SilcUInt##bits ret; \
- __asm __volatile(SILC_SMP_LOCK "cmpxchg" bp " %2, %1" \
- : "=a" (ret), "=m" (atomic->value) \
- : "r" (new_val), "m" (atomic->value), "0" (old_val)); \
- return ret == (SilcUInt##bits)old_val; \
-}
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
-#define SILC_ATOMIC_CAS(bits, bp) \
-SILC_ATOMIC_CAS_F(bits) \
-{ \
- /* GCC + IA64 (GCC builtin atomic operations) */ \
- SilcUInt32 o = old_val, n = new_val; \
- return __sync_bool_compare_and_swap(&atomic->value, o, n); \
-}
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
-#define SILC_ATOMIC_CAS(bits, bp) \
-SILC_ATOMIC_CAS_F(bits) \
-{ \
- /* GCC + PowerPC */ \
- /* XXX TODO */ \
-}
-
-#else /* SILC_ATOMIC_MUTEX */
-#define SILC_ATOMIC_CAS(bits, bp) \
-SILC_ATOMIC_CAS_F(bits) \
-{ \
- /* Mutex */ \
- silc_mutex_lock(atomic->lock); \
- if (atomic->value == (SilcUInt##bits)old_val) { \
- atomic->value = new_val; \
- silc_mutex_unlock(atomic->lock); \
- return TRUE; \
- } \
- silc_mutex_unlock(atomic->lock); \
- return FALSE; \
-}
-#endif /* !SILC_THREADS */
-
-SILC_ATOMIC_CAS(8, "b");
-SILC_ATOMIC_CAS(16, "w");
-SILC_ATOMIC_CAS(32, "l");
-
-/****f* silcutil/SilcAtomicAPI/silc_atomic_cas_pointer
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic,
- * void *old_ptr, void *new_ptr);
- *
- * DESCRIPTION
- *
- * Performs compare and swap (CAS). Atomically compares if the variable
- * `atomic' has the pointer `old_ptr' and in that case swaps it with the
- * pointer `new_ptr'. Returns TRUE if the old pointer was same and it was
- * swapped and FALSE if it differed and was not swapped.
- *
- ***/
-
-static inline
-SilcBool silc_atomic_cas_pointer(SilcAtomicPointer *atomic, void *old_val,
- void *new_val)
-{
-#if !defined(SILC_THREADS)
- /* No atomic operations */
- if (atomic->value == old_val) {
- atomic->value = new_val;
- return TRUE;
- }
- return FALSE;
-
-#elif defined(SILC_WIN32)
- /* Windows */
- return InterlockedCompareExchangePointer(&atomic->value, n, o) == o;
-
-#elif defined(__GNUC__) && defined(SILC_I486)
- /* GCC + i486 */
- void *ret;
- __asm __volatile(SILC_SMP_LOCK "cmpxchgl %2, %1"
- : "=a" (ret), "=m" (atomic->value)
- : "c" (new_val), "m" (atomic->value), "0" (old_val));
- return ret == old_val;
-
-#elif defined(__GNUC__) && defined(SILC_X86_64)
- /* GCC + x86_64 */
- void *ret;
- __asm __volatile(SILC_SMP_LOCK "cmpxchgq %q2, %1"
- : "=a" (ret), "=m" (atomic->value)
- : "c" (new_val), "m" (atomic->value), "0" (old_val));
- return ret == old_val;
-
-#elif defined(__GNUC__) && defined(SILC_IA64)
- /* GCC + IA64 (GCC builtin atomic operations) */
- return __sync_bool_compare_and_swap((long)&atomic->value, (long)old_val,
- (long)new_val);
-
-#elif defined(__GNUC__) && defined(SILC_POWERPC)
- /* GCC + PowerPC */
- /* XXX TODO */
-
-#else
- /* Mutex */
- silc_mutex_lock(atomic->lock);
- if (atomic->value == old_val) {
- atomic->value = new_val;
- silc_mutex_unlock(atomic->lock);
- return TRUE;
- }
- silc_mutex_unlock(atomic->lock);
- return FALSE;
-#endif
-}
-
-#endif /* SILCATOMIC_H */
/*
- silcbuffer.h
+ silcbuffer.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1998 - 2006 Pekka Riikonen
+ Copyright (C) 1998 - 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
*/
/* $Id$ */
+/* Optimized buffer managing routines. These are short inline functions. */
+
+#ifndef SILCBUFFER_H
+#define SILCBUFFER_H
/****h* silcutil/SILC Buffer Interface
*
* DESCRIPTION
*
- * SilcBuffer is very simple and easy to use, yet you can do to the
- * buffer almost anything you want with its method functions. The buffer
- * is constructed of four different data sections that in whole creates
- * the allocated data area.
+ * SilcBuffer is very simple and easy to use, yet you can do to the
+ * buffer almost anything you want with its method functions. The buffer
+ * is constructed of four different data sections that in whole creates
+ * the allocated data area.
+ *
+ * This buffer scheme is based on Linux kernel's Socket Buffer, the
+ * idea were taken directly from there and credits should go there.
*
***/
-#ifndef SILCBUFFER_H
-#define SILCBUFFER_H
-
/****s* silcutil/SilcBufferAPI/SilcBuffer
*
* NAME
*
* EXAMPLE
*
+ * SilcUInt32 truelen;
+ *
+ * True length of the buffer. This is set at the allocation of the
+ * buffer and it should not be touched after that. This field should
+ * be considered read-only.
+ *
+ * SilcUInt32 len;
+ *
+ * Length of the currently valid data area. Tells the length of the
+ * data at the buffer. This is set to zero at the allocation of the
+ * buffer and should not be updated by hand. Method functions of the
+ * buffer automatically updates this field. However, it is not
+ * read-only field and can be updated manually if necessary.
+ *
* unsiged char *head;
*
* Head of the allocated buffer. This is the start of the allocated
* section. Tail section can be pulled towards end, and thus the data
* section becomes larger.
*
- * SILC Buffer is not thread-safe. If the same SilcBuffer context must be
- * used in multithreaded environment concurrency control must be employed.
- *
* SOURCE
*/
typedef struct {
+ SilcUInt32 truelen;
+ SilcUInt32 len;
unsigned char *head;
unsigned char *data;
unsigned char *tail;
/* Macros */
-/****d* silcutil/SilcBufferAPI/silc_buffer_truelen
- *
- * NAME
- *
- * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
- *
- * DESCRIPTION
- *
- * Returns the true length of the buffer.
- *
- * SOURCE
- */
-#define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
-/***/
-
-/****d* silcutil/SilcBufferAPI/silc_buffer_len
- *
- * NAME
- *
- * SilcUInt32 silc_buffer_len(SilcBuffer sb)
- *
- * DESCRIPTION
- *
- * Returns the current length of the data area of the buffer.
- *
- * SOURCE
- */
-#define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
-/***/
-
-/****d* silcutil/SilcBufferAPI/silc_buffer_headlen
- *
- * NAME
- *
- * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
- *
- * DESCRIPTION
- *
- * Returns the current length of the head data area of the buffer.
- *
- * SOURCE
- */
-#define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
-/***/
-
-/****d* silcutil/SilcBufferAPI/silc_buffer_taillen
- *
- * NAME
- *
- * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
- *
- * DESCRIPTION
- *
- * Returns the current length of the tail data area of the buffer.
- *
- * SOURCE
- */
-#define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
-/***/
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_data
- *
+/****d* silcutil/SilcBufferAPI/SILC_BUFFER_END
+ *
* NAME
*
- * unsigned char *silc_buffer_data(SilcBuffer sb)
+ * #define SILC_BUFFER_END(...)
*
* DESCRIPTION
*
- * Returns pointer to the data area of the buffer.
- *
- * SOURCE
- */
-#define silc_buffer_data(x) (x)->data
-/***/
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_datalen
- *
- * NAME
- *
- * #define silc_buffer_datalen ...
- *
- * DESCRIPTION
- *
- * Macro that can be used in function argument list to give the data
- * pointer and the data length, instead of calling both silc_buffer_data
- * and silc_buffer_len separately.
- *
- * EXAMPLE
- *
- * // Following are the same thing
- * silc_foo_function(foo, silc_buffer_datalen(buf));
- * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
+ * Returns the true length of the buffer. This is used to pull
+ * the buffer area to the end of the buffer.
*
* SOURCE
*/
-#define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
- (x) ? silc_buffer_len((x)) : 0
+#define SILC_BUFFER_END(x) ((x)->end - (x)->head)
/***/
/* Inline functions */
*
* DESCRIPTION
*
- * Allocates new SilcBuffer and returns it. Returns NULL on error.
+ * Allocates new SilcBuffer and returns it.
*
***/
-
+
static inline
SilcBuffer silc_buffer_alloc(SilcUInt32 len)
{
/* Allocate new SilcBuffer */
sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
- if (silc_unlikely(!sb))
+ if (!sb)
return NULL;
- if (silc_likely(len)) {
- /* Allocate the actual data area */
- sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
- if (silc_unlikely(!sb->head))
- return NULL;
+ /* Allocate the actual data area */
+ sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
+ if (!sb->head)
+ return NULL;
- /* Set pointers to the new buffer */
- sb->data = sb->head;
- sb->tail = sb->head;
- sb->end = sb->head + len;
- }
+ /* Set pointers to the new buffer */
+ sb->truelen = len;
+ sb->data = sb->head;
+ sb->tail = sb->head;
+ sb->end = sb->head + sb->truelen;
return sb;
}
*
* DESCRIPTION
*
- * Frees SilcBuffer. Can be called safely `sb' as NULL.
- *
- * NOTES
- *
- * Must not be called for buffers allocated with silc_buffer_salloc,
- * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
+ * Frees SilcBuffer.
*
***/
if (sb) {
#if defined(SILC_DEBUG)
if (sb->head)
- memset(sb->head, 'F', silc_buffer_truelen(sb));
+ memset(sb->head, 'F', sb->truelen);
#endif
silc_free(sb->head);
silc_free(sb);
{
unsigned char *buf = sb->head;
if (data_len)
- *data_len = silc_buffer_truelen(sb);
+ *data_len = sb->truelen;
sb->head = sb->data = sb->tail = sb->end = NULL;
+ sb->len = sb->truelen = 0;
return buf;
}
-/****f* silcutil/SilcBufferAPI/silc_buffer_purge
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_buffer_purge(SilcBuffer sb);
- *
- * DESCRIPTION
- *
- * Same as silc_buffer_free but free's only the contents of the buffer
- * not the buffer itself. The `sb' remains intact, data is freed. Buffer
- * is ready for re-use after calling this function.
- *
- * NOTES
- *
- * Must not be called for buffers allocated with silc_buffer_salloc,
- * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
- *
- ***/
-
-static inline
-void silc_buffer_purge(SilcBuffer sb)
-{
- silc_free(silc_buffer_steal(sb, NULL));
-}
-
/****f* silcutil/SilcBufferAPI/silc_buffer_set
*
* SYNOPSIS
* can be used to set the data to static buffer without needing any
* memory allocations. The `data' will not be copied to the buffer.
*
- * EXAMPLE
- *
- * SilcBufferStruct buf;
- * silc_buffer_set(&buf, data, data_len);
- *
***/
static inline
{
sb->data = sb->head = data;
sb->tail = sb->end = data + data_len;
+ sb->len = sb->truelen = data_len;
}
/****f* silcutil/SilcBufferAPI/silc_buffer_pull
*
* Pulls current data area towards end. The length of the currently
* valid data area is also decremented. Returns pointer to the data
- * area before pulling. Returns NULL on error.
+ * area before pulling.
*
* EXAMPLE
*
* | head | data | tail |
* ---------------------------------
* ^
- *
- * silc_buffer_pull(sb, 20);
- *
***/
static inline
unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
{
unsigned char *old_data = sb->data;
+
#if defined(SILC_DEBUG)
- SILC_ASSERT(len <= silc_buffer_len(sb));
-#else
- if (silc_unlikely(len > silc_buffer_len(sb)))
- return NULL;
+ assert(len <= (SilcUInt32)(sb->tail - sb->data));
#endif
+
sb->data += len;
+ sb->len -= len;
+
return old_data;
}
* DESCRIPTION
*
* Pushes current data area towards beginning. Length of the currently
- * valid data area is also incremented. Returns a pointer to the
- * data area before pushing. Returns NULL on error.
+ * valid data area is also incremented. Returns a pointer to the
+ * data area before pushing.
*
* EXAMPLE
*
* ---------------------------------
* ^
*
- * silc_buffer_push(sb, 20);
- *
***/
static inline
unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
{
unsigned char *old_data = sb->data;
+
#if defined(SILC_DEBUG)
- SILC_ASSERT((sb->data - len) >= sb->head);
-#else
- if (silc_unlikely((sb->data - len) < sb->head))
- return NULL;
+ assert((sb->data - len) >= sb->head);
#endif
+
sb->data -= len;
+ sb->len += len;
+
return old_data;
}
*
* SYNOPSIS
*
- * static inline
+ * static inline
* unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
*
* DESCRIPTION
*
* Pulls current tail section towards end. Length of the current valid
- * data area is also incremented. Returns a pointer to the data area
- * before pulling. Returns NULL on error.
+ * data area is also incremented. Returns a pointer to the data area
+ * before pulling.
*
* EXAMPLE
*
* ---------------------------------
* ^
*
- * silc_buffer_pull_tail(sb, 23);
- *
***/
static inline
unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
{
unsigned char *old_tail = sb->tail;
+
#if defined(SILC_DEBUG)
- SILC_ASSERT(len <= silc_buffer_taillen(sb));
-#else
- if (silc_unlikely(len > silc_buffer_taillen(sb)))
- return NULL;
+ assert((SilcUInt32)(sb->end - sb->tail) >= len);
#endif
+
sb->tail += len;
+ sb->len += len;
+
return old_tail;
}
*
* Pushes current tail section towards beginning. Length of the current
* valid data area is also decremented. Returns a pointer to the
- * tail section before pushing. Returns NULL on error.
+ * tail section before pushing.
*
* EXAMPLE
*
* ---------------------------------
* ^
*
- * silc_buffer_push_tail(sb, 23);
- *
***/
static inline
unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
{
unsigned char *old_tail = sb->tail;
+
#if defined(SILC_DEBUG)
- SILC_ASSERT((sb->tail - len) >= sb->data);
-#else
- if (silc_unlikely((sb->tail - len) < sb->data))
- return NULL;
+ assert((sb->tail - len) >= sb->data);
#endif
+
sb->tail -= len;
+ sb->len -= len;
+
return old_tail;
}
* SYNOPSIS
*
* static inline
- * unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ * unsigned char *silc_buffer_put_head(SilcBuffer sb,
* const unsigned char *data,
* SilcUInt32 len);
*
* DESCRIPTION
*
* Puts data at the head of the buffer. Returns pointer to the copied
- * data area. Returns NULL on error.
+ * data area.
*
* EXAMPLE
*
* | head | data | tail |
* ---------------------------------
* ^
- * Puts data to the head section.
- *
- * silc_buffer_put_head(sb, data, data_len);
+ * Puts data to the head section.
*
***/
SilcUInt32 len)
{
#if defined(SILC_DEBUG)
- SILC_ASSERT(len <= silc_buffer_headlen(sb));
-#else
- if (silc_unlikely(len > silc_buffer_headlen(sb)))
- return NULL;
+ assert((SilcUInt32)(sb->data - sb->head) >= len);
#endif
return (unsigned char *)memcpy(sb->head, data, len);
}
* DESCRIPTION
*
* Puts data at the start of the valid data area. Returns a pointer
- * to the copied data area. Returns NULL on error.
+ * to the copied data area.
*
* EXAMPLE
*
* ^
* Puts data to the data section.
*
- * silc_buffer_put(sb, data, data_len);
- *
***/
static inline
SilcUInt32 len)
{
#if defined(SILC_DEBUG)
- SILC_ASSERT(len <= silc_buffer_len(sb));
-#else
- if (silc_unlikely(len > silc_buffer_len(sb)))
- return NULL;
+ assert((SilcUInt32)(sb->tail - sb->data) >= len);
#endif
return (unsigned char *)memcpy(sb->data, data, len);
}
* DESCRIPTION
*
* Puts data at the tail of the buffer. Returns pointer to the copied
- * data area. Returns NULL on error.
+ * data area.
*
* EXAMPLE
*
* ^
* Puts data to the tail section.
*
- * silc_buffer_put_tail(sb, data, data_len);
- *
***/
static inline
SilcUInt32 len)
{
#if defined(SILC_DEBUG)
- SILC_ASSERT(len <= silc_buffer_taillen(sb));
-#else
- if (silc_unlikely(len > silc_buffer_taillen(sb)))
- return NULL;
+ assert((SilcUInt32)(sb->end - sb->tail) >= len);
#endif
return (unsigned char *)memcpy(sb->tail, data, len);
}
*
* Allocates `len' bytes size buffer and moves the tail area automatically
* `len' bytes so that the buffer is ready to use without calling the
- * silc_buffer_pull_tail. Returns NULL on error.
+ * silc_buffer_pull_tail.
*
***/
SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
{
SilcBuffer sb = silc_buffer_alloc(len);
- if (silc_unlikely(!sb))
+ if (!sb)
return NULL;
silc_buffer_pull_tail(sb, len);
return sb;
}
-/****f* silcutil/SilcBufferAPI/silc_buffer_reset
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_buffer_reset(SilcBuffer sb);
- *
- * DESCRIPTION
- *
- * Resets the buffer to the state as if it was just allocated by
- * silc_buffer_alloc. This does not clear the data area. Use
- * silc_buffer_clear if you also want to clear the data area.
- *
- ***/
-
-static inline
-void silc_buffer_reset(SilcBuffer sb)
-{
- sb->data = sb->tail = sb->head;
-}
-
/****f* silcutil/SilcBufferAPI/silc_buffer_clear
*
* SYNOPSIS
static inline
void silc_buffer_clear(SilcBuffer sb)
{
- memset(sb->head, 0, silc_buffer_truelen(sb));
- silc_buffer_reset(sb);
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_start
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_buffer_start(SilcBuffer sb);
- *
- * DESCRIPTION
- *
- * Moves the data area at the start of the buffer. The tail area remains
- * as is.
- *
- ***/
-
-static inline
-void silc_buffer_start(SilcBuffer sb)
-{
+ if (!sb)
+ return;
+ memset(sb->head, 0, sb->truelen);
sb->data = sb->head;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_end
- *
- * SYNOPSIS
- *
- * static inline
- * void silc_buffer_end(SilcBuffer sb);
- *
- * DESCRIPTION
- *
- * Moves the end of the data area to the end of the buffer. The start
- * of the data area remains same. If the start of data area is at the
- * start of the buffer, after this function returns the buffer's data
- * area length is the length of the entire buffer.
- *
- ***/
-
-static inline
-void silc_buffer_end(SilcBuffer sb)
-{
- sb->tail = sb->end;
+ sb->tail = sb->head;
+ sb->len = 0;
}
/****f* silcutil/SilcBufferAPI/silc_buffer_copy
*
* Generates copy of a SilcBuffer. This copies everything inside the
* currently valid data area, nothing more. Use silc_buffer_clone to
- * copy entire buffer. Returns NULL on error.
+ * copy entire buffer.
*
***/
{
SilcBuffer sb_new;
- sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
- if (silc_unlikely(!sb_new))
+ sb_new = silc_buffer_alloc_size(sb->len);
+ if (!sb_new)
return NULL;
- silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
+ silc_buffer_put(sb_new, sb->data, sb->len);
return sb_new;
}
*
* Clones SilcBuffer. This generates new SilcBuffer and copies
* everything from the source buffer. The result is exact clone of
- * the original buffer. Returns NULL on error.
+ * the original buffer.
*
***/
{
SilcBuffer sb_new;
- sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
- if (silc_unlikely(!sb_new))
+ sb_new = silc_buffer_alloc_size(sb->truelen);
+ if (!sb_new)
return NULL;
- silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
- sb_new->data = sb_new->head + silc_buffer_headlen(sb);
- sb_new->tail = sb_new->data + silc_buffer_len(sb);
+ silc_buffer_put(sb_new, sb->head, sb->truelen);
+ sb_new->data = sb_new->head + (sb->data - sb->head);
+ sb_new->tail = sb_new->data + sb->len;
+ sb_new->len = sb->len;
return sb_new;
}
*
* DESCRIPTION
*
- * Reallocates buffer. Old data is saved into the new buffer. The buffer
- * is exact clone of the old one except that there is now more space
- * at the end of buffer. This always returns the same `sb' unless `sb'
- * was NULL. Returns NULL on error.
+ * Reallocates buffer. Old data is saved into the new buffer. Returns
+ * new SilcBuffer pointer. The buffer is exact clone of the old one
+ * except that there is now more space at the end of buffer.
*
***/
static inline
SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
{
- SilcUInt32 hlen, dlen;
- unsigned char *h;
+ SilcBuffer sb_new;
if (!sb)
return silc_buffer_alloc(newsize);
- if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
+ if (newsize <= sb->truelen)
return sb;
- hlen = silc_buffer_headlen(sb);
- dlen = silc_buffer_len(sb);
- h = (unsigned char *)silc_realloc(sb->head, newsize);
- if (silc_unlikely(!h))
+ sb_new = silc_buffer_alloc_size(newsize);
+ if (!sb_new)
return NULL;
- sb->head = h;
- sb->data = sb->head + hlen;
- sb->tail = sb->data + dlen;
- sb->end = sb->head + newsize;
+ silc_buffer_put(sb_new, sb->head, sb->truelen);
+ sb_new->data = sb_new->head + (sb->data - sb->head);
+ sb_new->tail = sb_new->data + sb->len;
+ sb_new->len = sb->len;
- return sb;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
- *
- * DESCRIPTION
- *
- * Same as silc_buffer_realloc but moves moves the tail area
- * automatically so that the buffer is ready to use without calling the
- * silc_buffer_pull_tail. Returns NULL on error.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
-{
- sb = silc_buffer_realloc(sb, newsize);
- if (silc_unlikely(!sb))
- return NULL;
- silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
- return sb;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Enlarges the buffer by the amount of `size' if it doesn't have that
- * must space in the data area and in the tail area. Moves the tail
- * area automatically after enlarging so that the current data area
- * is at least the size of `size'. If there is more space than `size'
- * in the data area this does not do anything. If there is enough
- * space in the tail area this merely moves the tail area to reveal
- * the extra space. Returns FALSE on error.
- *
- ***/
-
-static inline
-SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
-{
- if (size > silc_buffer_len(sb)) {
- if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
- if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
- (size - silc_buffer_taillen(sb) -
- silc_buffer_len(sb)))))
- return FALSE;
- silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
- }
- return TRUE;
-}
-
-
-/* SilcStack aware SilcBuffer routines */
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_salloc
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
- *
- * DESCRIPTION
- *
- * Allocates new SilcBuffer and returns it.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
-{
- SilcBuffer sb;
-
- if (!stack)
- return silc_buffer_alloc(len);
-
- /* Allocate new SilcBuffer */
- sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
- if (silc_unlikely(!sb))
- return NULL;
-
- /* Allocate the actual data area */
- sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
- if (silc_unlikely(!sb->head))
- return NULL;
-
- /* Set pointers to the new buffer */
- sb->data = sb->head;
- sb->tail = sb->head;
- sb->end = sb->head + len;
-
- return sb;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
- *
- * DESCRIPTION
- *
- * Allocates `len' bytes size buffer and moves the tail area automatically
- * `len' bytes so that the buffer is ready to use without calling the
- * silc_buffer_pull_tail.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
-{
- SilcBuffer sb = silc_buffer_salloc(stack, len);
- if (silc_unlikely(!sb))
- return NULL;
- silc_buffer_pull_tail(sb, len);
- return sb;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_srealloc(SilcStack stack,
- * SilcBuffer sb, SilcUInt32 newsize);
- *
- * DESCRIPTION
- *
- * Reallocates buffer. Old data is saved into the new buffer. The buffer
- * is exact clone of the old one except that there is now more space
- * at the end of buffer.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_srealloc(SilcStack stack,
- SilcBuffer sb, SilcUInt32 newsize)
-{
- SilcUInt32 hlen, dlen;
- unsigned char *h;
-
- if (!stack)
- return silc_buffer_realloc(sb, newsize);
-
- if (!sb)
- return silc_buffer_salloc(stack, newsize);
-
- if (newsize <= silc_buffer_truelen(sb))
- return sb;
-
- hlen = silc_buffer_headlen(sb);
- dlen = silc_buffer_len(sb);
- h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
- sb->head, newsize);
- if (!h) {
- /* Do slow and stack wasting realloc. The old sb->head is lost and
- is freed eventually. */
- h = (unsigned char *)silc_smalloc_ua(stack, newsize);
- if (silc_unlikely(!h))
- return NULL;
- memcpy(h, sb->head, silc_buffer_truelen(sb));
- }
-
- sb->head = h;
- sb->data = sb->head + hlen;
- sb->tail = sb->data + dlen;
- sb->end = sb->head + newsize;
-
- return sb;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
- * SilcBuffer sb, SilcUInt32 newsize);
- *
- * DESCRIPTION
- *
- * Same as silc_buffer_srealloc but moves moves the tail area
- * automatically so that the buffer is ready to use without calling the
- * silc_buffer_pull_tail.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
- SilcBuffer sb, SilcUInt32 newsize)
-{
- sb = silc_buffer_srealloc(stack, sb, newsize);
- if (silc_unlikely(!sb))
- return NULL;
- silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
- return sb;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
- * SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Enlarges the buffer by the amount of `size' if it doesn't have that
- * must space in the data area and in the tail area. Moves the tail
- * area automatically after enlarging so that the current data area
- * is at least the size of `size'. If there is more space than `size'
- * in the data area this does not do anything. If there is enough
- * space in the tail area this merely moves the tail area to reveal
- * the extra space. Returns FALSE on error.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
-{
- if (size > silc_buffer_len(sb)) {
- if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
- if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
- silc_buffer_truelen(sb) +
- (size - silc_buffer_taillen(sb) -
- silc_buffer_len(sb)))))
- return FALSE;
- silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
- }
- return TRUE;
-}
-
-/****f* silcutil/SilcBufferAPI/silc_buffer_scopy
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
- *
- * DESCRIPTION
- *
- * Generates copy of a SilcBuffer. This copies everything inside the
- * currently valid data area, nothing more. Use silc_buffer_clone to
- * copy entire buffer.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
-{
- SilcBuffer sb_new;
-
- sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
- if (silc_unlikely(!sb_new))
- return NULL;
- silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
+ silc_buffer_free(sb);
return sb_new;
}
-/****f* silcutil/SilcBufferAPI/silc_buffer_sclone
- *
- * SYNOPSIS
- *
- * static inline
- * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
- *
- * DESCRIPTION
- *
- * Clones SilcBuffer. This generates new SilcBuffer and copies
- * everything from the source buffer. The result is exact clone of
- * the original buffer.
- *
- * This routine use SilcStack are memory source. If `stack' is NULL
- * reverts back to normal allocating routine.
- *
- ***/
-
-static inline
-SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
-{
- SilcBuffer sb_new;
-
- sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
- if (silc_unlikely(!sb_new))
- return NULL;
- silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
- sb_new->data = sb_new->head + silc_buffer_headlen(sb);
- sb_new->tail = sb_new->data + silc_buffer_len(sb);
-
- return sb_new;
-}
-
-#endif /* SILCBUFFER_H */
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
*/
/* $Id$ */
-#include "silc.h"
-
-/************************** Types and definitions ***************************/
-
-/* Check that buffer has enough room to format data in it, if not
- allocate more. */
-#define FORMAT_HAS_SPACE(s, b, req) \
-do { \
- if (silc_unlikely(!silc_buffer_senlarge(s, b, req))) \
- goto fail; \
- flen += req; \
-} while(0)
-
-/* Check that there is data to be unformatted */
-#define UNFORMAT_HAS_SPACE(b, req) \
-do { \
- if (silc_unlikely(req > silc_buffer_len(b))) \
- goto fail; \
- if (silc_unlikely((req + 1) <= 0)) \
- goto fail; \
-} while(0)
-
-
-/******************************* Formatting *********************************/
+#include "silcincludes.h"
+
+/* Macros to check whether there is enough free space to add the
+ required amount of data. For unformatting this means that there must
+ be the data that is to be extracted. */
+#define FORMAT_HAS_SPACE(__x__, __req__) \
+ do { \
+ if (__req__ > (__x__)->len) \
+ goto fail; \
+ } while(0)
+#define UNFORMAT_HAS_SPACE(__x__, __req__) \
+ do { \
+ if (__req__ > (__x__)->len) \
+ goto fail; \
+ if ((__req__ + 1) <= 0) \
+ goto fail; \
+ } while(0)
+
+/* Formats the arguments sent and puts them into the buffer sent as
+ argument. The buffer must be initialized beforehand and it must have
+ enough free space to include the formatted data. If this function
+ fails caller should not trust the buffer anymore and should free it.
+ This function is used, for example, to create packets to send over
+ network. */
int silc_buffer_format(SilcBuffer dst, ...)
{
int ret;
va_start(ap, dst);
- ret = silc_buffer_sformat_vp(NULL, dst, ap);
+ ret = silc_buffer_format_vp(dst, ap);
va_end(ap);
return ret;
}
int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
-{
- return silc_buffer_sformat_vp(NULL, dst, ap);
-}
-
-int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, dst);
- ret = silc_buffer_sformat_vp(stack, dst, ap);
- va_end(ap);
-
- return ret;
-}
-
-int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
{
SilcBufferParamType fmt;
- int flen = 0;
- SilcBool advance = FALSE;
+ unsigned char *start_ptr = dst->data;
+ int len;
/* Parse the arguments by formatting type. */
while (1) {
fmt = va_arg(ap, SilcBufferParamType);
switch(fmt) {
- case SILC_PARAM_FUNC:
- {
- SilcBufferFormatFunc func = NULL;
- SilcBufferSFormatFunc funcs = NULL;
- void *val;
- void *context;
- int tmp_len;
- if (!stack)
- func = va_arg(ap, SilcBufferFormatFunc);
- else
- funcs = va_arg(ap, SilcBufferSFormatFunc);
- val = va_arg(ap, void *);
- context = va_arg(ap, void *);
- if (!stack)
- tmp_len = func(dst, val, context);
- else
- tmp_len = funcs(stack, dst, val, context);
- if (tmp_len < 0)
- goto fail;
- if (tmp_len) {
- silc_buffer_pull(dst, tmp_len);
- flen += tmp_len;
- }
- }
- break;
- case SILC_PARAM_UI8_STRING:
- case SILC_PARAM_UI16_STRING:
- case SILC_PARAM_UI32_STRING:
- case SILC_PARAM_UI8_STRING_ALLOC:
- case SILC_PARAM_UI16_STRING_ALLOC:
- case SILC_PARAM_UI32_STRING_ALLOC:
- {
- unsigned char *x = va_arg(ap, unsigned char *);
- SilcUInt32 tmp_len = strlen(x);
- FORMAT_HAS_SPACE(stack, dst, tmp_len);
- silc_buffer_put(dst, x, tmp_len);
- silc_buffer_pull(dst, tmp_len);
- break;
- }
- case SILC_PARAM_UI8_NSTRING:
- case SILC_PARAM_UI16_NSTRING:
- case SILC_PARAM_UI32_NSTRING:
- case SILC_PARAM_UI_XNSTRING:
- case SILC_PARAM_DATA:
- case SILC_PARAM_UI8_NSTRING_ALLOC:
- case SILC_PARAM_UI16_NSTRING_ALLOC:
- case SILC_PARAM_UI32_NSTRING_ALLOC:
- case SILC_PARAM_UI_XNSTRING_ALLOC:
- case SILC_PARAM_DATA_ALLOC:
+ case SILC_BUFFER_PARAM_SI8_CHAR:
{
- unsigned char *x = va_arg(ap, unsigned char *);
- SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
- if (x && tmp_len) {
- FORMAT_HAS_SPACE(stack, dst, tmp_len);
- silc_buffer_put(dst, x, tmp_len);
- silc_buffer_pull(dst, tmp_len);
- }
+ char x = (char)va_arg(ap, int);
+ FORMAT_HAS_SPACE(dst, 1);
+ silc_buffer_put(dst, &x, 1);
+ silc_buffer_pull(dst, 1);
break;
}
- case SILC_PARAM_UI8_CHAR:
+ case SILC_BUFFER_PARAM_UI8_CHAR:
{
unsigned char x = (unsigned char)va_arg(ap, int);
- FORMAT_HAS_SPACE(stack, dst, 1);
+ FORMAT_HAS_SPACE(dst, 1);
silc_buffer_put(dst, &x, 1);
silc_buffer_pull(dst, 1);
break;
}
- case SILC_PARAM_UI16_SHORT:
+ case SILC_BUFFER_PARAM_SI16_SHORT:
{
unsigned char xf[2];
- SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
- FORMAT_HAS_SPACE(stack, dst, 2);
+ SilcInt16 x = (SilcInt16)va_arg(ap, int);
+ FORMAT_HAS_SPACE(dst, 2);
SILC_PUT16_MSB(x, xf);
silc_buffer_put(dst, xf, 2);
silc_buffer_pull(dst, 2);
break;
}
- case SILC_PARAM_UI32_INT:
- {
- unsigned char xf[4];
- SilcUInt32 x = va_arg(ap, SilcUInt32);
- FORMAT_HAS_SPACE(stack, dst, 4);
- SILC_PUT32_MSB(x, xf);
- silc_buffer_put(dst, xf, 4);
- silc_buffer_pull(dst, 4);
- break;
- }
- case SILC_PARAM_UI64_INT:
- {
- unsigned char xf[8];
- SilcUInt64 x = va_arg(ap, SilcUInt64);
- FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64));
- SILC_PUT64_MSB(x, xf);
- silc_buffer_put(dst, xf, sizeof(SilcUInt64));
- silc_buffer_pull(dst, sizeof(SilcUInt64));
- break;
- }
- case SILC_PARAM_SI8_CHAR:
- {
- char x = (char)va_arg(ap, int);
- FORMAT_HAS_SPACE(stack, dst, 1);
- silc_buffer_put(dst, &x, 1);
- silc_buffer_pull(dst, 1);
- break;
- }
- case SILC_PARAM_SI16_SHORT:
+ case SILC_BUFFER_PARAM_UI16_SHORT:
{
unsigned char xf[2];
- SilcInt16 x = (SilcInt16)va_arg(ap, int);
- FORMAT_HAS_SPACE(stack, dst, 2);
+ SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
+ FORMAT_HAS_SPACE(dst, 2);
SILC_PUT16_MSB(x, xf);
silc_buffer_put(dst, xf, 2);
silc_buffer_pull(dst, 2);
break;
}
- case SILC_PARAM_SI32_INT:
+ case SILC_BUFFER_PARAM_SI32_INT:
{
unsigned char xf[4];
SilcInt32 x = va_arg(ap, SilcInt32);
- FORMAT_HAS_SPACE(stack, dst, 4);
+ FORMAT_HAS_SPACE(dst, 4);
SILC_PUT32_MSB(x, xf);
silc_buffer_put(dst, xf, 4);
silc_buffer_pull(dst, 4);
break;
}
- case SILC_PARAM_SI64_INT:
+ case SILC_BUFFER_PARAM_UI32_INT:
+ {
+ unsigned char xf[4];
+ SilcUInt32 x = va_arg(ap, SilcUInt32);
+ FORMAT_HAS_SPACE(dst, 4);
+ SILC_PUT32_MSB(x, xf);
+ silc_buffer_put(dst, xf, 4);
+ silc_buffer_pull(dst, 4);
+ break;
+ }
+ case SILC_BUFFER_PARAM_SI64_INT:
{
unsigned char xf[8];
SilcInt64 x = va_arg(ap, SilcInt64);
- FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64));
+ FORMAT_HAS_SPACE(dst, sizeof(SilcInt64));
SILC_PUT64_MSB(x, xf);
silc_buffer_put(dst, xf, sizeof(SilcInt64));
silc_buffer_pull(dst, sizeof(SilcInt64));
break;
}
- case SILC_PARAM_BUFFER:
- case SILC_PARAM_BUFFER_ALLOC:
+ case SILC_BUFFER_PARAM_UI64_INT:
{
- SilcBuffer x = va_arg(ap, SilcBuffer);
- unsigned char xf[4];
- if (x && silc_buffer_len(x)) {
- FORMAT_HAS_SPACE(stack, dst, silc_buffer_len(x) + 4);
- SILC_PUT32_MSB(silc_buffer_len(x), xf);
- silc_buffer_put(dst, xf, 4);
- silc_buffer_pull(dst, 4);
- silc_buffer_put(dst, silc_buffer_data(x), silc_buffer_len(x));
- silc_buffer_pull(dst, silc_buffer_len(x));
- }
+ unsigned char xf[8];
+ SilcUInt64 x = va_arg(ap, SilcUInt64);
+ FORMAT_HAS_SPACE(dst, sizeof(SilcUInt64));
+ SILC_PUT64_MSB(x, xf);
+ silc_buffer_put(dst, xf, sizeof(SilcUInt64));
+ silc_buffer_pull(dst, sizeof(SilcUInt64));
+ break;
}
- break;
- case SILC_PARAM_OFFSET:
+ case SILC_BUFFER_PARAM_UI8_STRING:
+ case SILC_BUFFER_PARAM_UI16_STRING:
+ case SILC_BUFFER_PARAM_UI32_STRING:
+ case SILC_BUFFER_PARAM_UI8_STRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
+ {
+ unsigned char *x = va_arg(ap, unsigned char *);
+ SilcUInt32 tmp_len = strlen(x);
+ FORMAT_HAS_SPACE(dst, tmp_len);
+ silc_buffer_put(dst, x, tmp_len);
+ silc_buffer_pull(dst, tmp_len);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI8_NSTRING:
+ case SILC_BUFFER_PARAM_UI16_NSTRING:
+ case SILC_BUFFER_PARAM_UI32_NSTRING:
+ case SILC_BUFFER_PARAM_UI_XNSTRING:
+ case SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
{
- int offst = va_arg(ap, int);
- if (!offst)
- break;
- if (offst > 1) {
- if (offst > silc_buffer_len(dst))
- goto fail;
- silc_buffer_pull(dst, offst);
- flen += offst;
- } else {
- silc_buffer_push(dst, -(offst));
- flen += -(offst);
+ unsigned char *x = va_arg(ap, unsigned char *);
+ SilcUInt32 len = va_arg(ap, SilcUInt32);
+ if (x && len) {
+ FORMAT_HAS_SPACE(dst, len);
+ silc_buffer_put(dst, x, len);
+ silc_buffer_pull(dst, len);
}
break;
}
- case SILC_PARAM_ADVANCE:
- advance = TRUE;
- break;
- case SILC_PARAM_END:
+ case SILC_BUFFER_PARAM_END:
goto ok;
break;
default:
fail:
SILC_LOG_DEBUG(("Error occured while formatting data"));
- if (!advance)
- silc_buffer_push(dst, flen);
+ len = dst->data - start_ptr;
+ silc_buffer_push(dst, len);
return -1;
ok:
/* Push the buffer back to where it belongs. */
- if (!advance)
- silc_buffer_push(dst, flen);
- return flen;
+ len = dst->data - start_ptr;
+ silc_buffer_push(dst, len);
+ return len;
}
-
-/****************************** Unformatting ********************************/
+/* Unformats the buffer sent as argument. The unformatted data is returned
+ to the variable argument list of pointers. The buffer must point to the
+ start of the data area to be unformatted. Buffer maybe be safely free'd
+ after this returns succesfully. */
int silc_buffer_unformat(SilcBuffer src, ...)
{
int ret;
va_start(ap, src);
- ret = silc_buffer_sunformat_vp(NULL, src, ap);
+ ret = silc_buffer_unformat_vp(src, ap);
va_end(ap);
return ret;
}
int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
-{
- return silc_buffer_sunformat_vp(NULL, src, ap);
-}
-
-int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, src);
- ret = silc_buffer_sunformat_vp(stack, src, ap);
- va_end(ap);
-
- return ret;
-}
-
-int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
{
SilcBufferParamType fmt;
unsigned char *start_ptr = src->data;
int len = 0;
- SilcBool advance = FALSE;
/* Parse the arguments by formatting type. */
while(1) {
fmt = va_arg(ap, SilcBufferParamType);
switch(fmt) {
- case SILC_PARAM_FUNC:
- {
- SilcBufferUnformatFunc func = NULL;
- SilcBufferSUnformatFunc funcs = NULL;
- void **val;
- void *context;
- int tmp_len;
- if (!stack)
- func = va_arg(ap, SilcBufferUnformatFunc);
- else
- funcs = va_arg(ap, SilcBufferSUnformatFunc);
- val = va_arg(ap, void **);
- context = va_arg(ap, void *);
- if (!stack)
- tmp_len = func(src, val, context);
- else
- tmp_len = funcs(stack, src, val, context);
- if (tmp_len < 0)
- goto fail;
- if (tmp_len) {
- UNFORMAT_HAS_SPACE(src, tmp_len);
- silc_buffer_pull(src, tmp_len);
- }
- }
- case SILC_PARAM_UI_XNSTRING:
- case SILC_PARAM_DATA:
- {
- unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt32 len2 = va_arg(ap, SilcUInt32);
- UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(len2 && x))
- *x = src->data;
- silc_buffer_pull(src, len2);
- break;
- }
- case SILC_PARAM_UI_XNSTRING_ALLOC:
- case SILC_PARAM_DATA_ALLOC:
+ case SILC_BUFFER_PARAM_SI8_CHAR:
{
- unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt32 len2 = va_arg(ap, SilcUInt32);
- UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(len2 && x)) {
- *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
- memcpy(*x, src->data, len2);
- }
- silc_buffer_pull(src, len2);
+ char *x = va_arg(ap, char *);
+ UNFORMAT_HAS_SPACE(src, 1);
+ if (x)
+ *x = src->data[0];
+ silc_buffer_pull(src, 1);
break;
}
- case SILC_PARAM_UI8_CHAR:
+ case SILC_BUFFER_PARAM_UI8_CHAR:
{
unsigned char *x = va_arg(ap, unsigned char *);
UNFORMAT_HAS_SPACE(src, 1);
- if (silc_likely(x))
+ if (x)
*x = src->data[0];
silc_buffer_pull(src, 1);
break;
}
- case SILC_PARAM_UI16_SHORT:
+ case SILC_BUFFER_PARAM_SI16_SHORT:
{
- SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
+ SilcInt16 *x = va_arg(ap, SilcInt16 *);
UNFORMAT_HAS_SPACE(src, 2);
- if (silc_likely(x))
+ if (x)
SILC_GET16_MSB(*x, src->data);
silc_buffer_pull(src, 2);
break;
}
- case SILC_PARAM_UI32_INT:
+ case SILC_BUFFER_PARAM_UI16_SHORT:
{
- SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
- UNFORMAT_HAS_SPACE(src, 4);
- if (silc_likely(x))
- SILC_GET32_MSB(*x, src->data);
- silc_buffer_pull(src, 4);
- break;
- }
- case SILC_PARAM_UI64_INT:
- {
- SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
- UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
- if (silc_likely(x))
- SILC_GET64_MSB(*x, src->data);
- silc_buffer_pull(src, sizeof(SilcUInt64));
- break;
- }
- case SILC_PARAM_SI8_CHAR:
- {
- char *x = va_arg(ap, char *);
- UNFORMAT_HAS_SPACE(src, 1);
- if (silc_likely(x))
- *x = src->data[0];
- silc_buffer_pull(src, 1);
- break;
- }
- case SILC_PARAM_SI16_SHORT:
- {
- SilcInt16 *x = va_arg(ap, SilcInt16 *);
+ SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
UNFORMAT_HAS_SPACE(src, 2);
- if (silc_likely(x))
+ if (x)
SILC_GET16_MSB(*x, src->data);
silc_buffer_pull(src, 2);
break;
}
- case SILC_PARAM_SI32_INT:
+ case SILC_BUFFER_PARAM_SI32_INT:
{
SilcInt32 *x = va_arg(ap, SilcInt32 *);
UNFORMAT_HAS_SPACE(src, 4);
- if (silc_likely(x))
+ if (x)
+ SILC_GET32_MSB(*x, src->data);
+ silc_buffer_pull(src, 4);
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI32_INT:
+ {
+ SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
+ UNFORMAT_HAS_SPACE(src, 4);
+ if (x)
SILC_GET32_MSB(*x, src->data);
silc_buffer_pull(src, 4);
break;
}
- case SILC_PARAM_SI64_INT:
+ case SILC_BUFFER_PARAM_SI64_INT:
{
SilcInt64 *x = va_arg(ap, SilcInt64 *);
UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
- if (silc_likely(x))
+ if (x)
SILC_GET64_MSB(*x, src->data);
silc_buffer_pull(src, sizeof(SilcInt64));
break;
}
- case SILC_PARAM_UI8_STRING:
+ case SILC_BUFFER_PARAM_UI64_INT:
+ {
+ SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
+ UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
+ if (x)
+ SILC_GET64_MSB(*x, src->data);
+ silc_buffer_pull(src, sizeof(SilcUInt64));
+ break;
+ }
+ case SILC_BUFFER_PARAM_UI8_STRING:
{
SilcUInt8 len2;
unsigned char **x = va_arg(ap, unsigned char **);
len2 = (SilcUInt8)src->data[0];
silc_buffer_pull(src, 1);
UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(x))
+ if (x)
*x = src->data;
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI16_STRING:
+ case SILC_BUFFER_PARAM_UI16_STRING:
{
SilcUInt16 len2;
unsigned char **x = va_arg(ap, unsigned char **);
SILC_GET16_MSB(len2, src->data);
silc_buffer_pull(src, 2);
UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(x))
+ if (x)
*x = src->data;
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI8_STRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI8_STRING_ALLOC:
{
SilcUInt8 len2;
unsigned char **x = va_arg(ap, unsigned char **);
len2 = (SilcUInt8)src->data[0];
silc_buffer_pull(src, 1);
UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(x && len2)) {
- *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
+ if (x && len2) {
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
memcpy(*x, src->data, len2);
}
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI16_STRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
{
SilcUInt16 len2;
unsigned char **x = va_arg(ap, unsigned char **);
SILC_GET16_MSB(len2, src->data);
silc_buffer_pull(src, 2);
UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(x && len2)) {
- *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
+ if (x && len2) {
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
memcpy(*x, src->data, len2);
}
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI32_STRING:
+ case SILC_BUFFER_PARAM_UI32_STRING:
{
SilcUInt32 len2;
unsigned char **x = va_arg(ap, unsigned char **);
SILC_GET32_MSB(len2, src->data);
silc_buffer_pull(src, 4);
UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(x))
+ if (x)
*x = src->data;
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI32_STRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
{
SilcUInt32 len2;
unsigned char **x = va_arg(ap, unsigned char **);
SILC_GET32_MSB(len2, src->data);
silc_buffer_pull(src, 4);
UNFORMAT_HAS_SPACE(src, len2);
- if (silc_likely(x && len2)) {
- *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
+ if (x && len2) {
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
memcpy(*x, src->data, len2);
}
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI8_NSTRING:
+ case SILC_BUFFER_PARAM_UI8_NSTRING:
{
SilcUInt8 len2;
unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
+ SilcUInt8 *len = va_arg(ap, SilcUInt8 *);
UNFORMAT_HAS_SPACE(src, 1);
len2 = (SilcUInt8)src->data[0];
silc_buffer_pull(src, 1);
UNFORMAT_HAS_SPACE(src, len2);
- if (len3)
- *len3 = len2;
+ if (len)
+ *len = len2;
if (x)
*x = src->data;
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI16_NSTRING:
+ case SILC_BUFFER_PARAM_UI16_NSTRING:
{
SilcUInt16 len2;
unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
+ SilcUInt16 *len = va_arg(ap, SilcUInt16 *);
UNFORMAT_HAS_SPACE(src, 2);
SILC_GET16_MSB(len2, src->data);
silc_buffer_pull(src, 2);
UNFORMAT_HAS_SPACE(src, len2);
- if (len3)
- *len3 = len2;
+ if (len)
+ *len = len2;
if (x)
*x = src->data;
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI8_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC:
{
SilcUInt8 len2;
unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
+ SilcUInt8 *len = va_arg(ap, SilcUInt8 *);
UNFORMAT_HAS_SPACE(src, 1);
len2 = (SilcUInt8)src->data[0];
silc_buffer_pull(src, 1);
UNFORMAT_HAS_SPACE(src, len2);
- if (len3)
- *len3 = len2;
+ if (len)
+ *len = len2;
if (x && len2) {
- *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
memcpy(*x, src->data, len2);
}
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI16_NSTRING_ALLOC:
+ case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
{
SilcUInt16 len2;
unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
+ SilcUInt16 *len = va_arg(ap, SilcUInt16 *);
UNFORMAT_HAS_SPACE(src, 2);
SILC_GET16_MSB(len2, src->data);
silc_buffer_pull(src, 2);
UNFORMAT_HAS_SPACE(src, len2);
- if (len3)
- *len3 = len2;
+ if (len)
+ *len = len2;
if (x && len2) {
- *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
+ *x = silc_calloc(len2 + 1, sizeof(unsigned char));
memcpy(*x, src->data, len2);
}
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_UI32_NSTRING:
+ case SILC_BUFFER_PARAM_UI32_NSTRING:
{
SilcUInt32 len2;
unsigned char **x = va_arg(ap, unsigned char **);
- SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
+ SilcUInt32 *len = va_arg(ap, SilcUInt32 *);
UNFORMAT_HAS_SPACE(src, 4);
SILC_GET32_MSB(len2, src->data);
silc_buffer_pull(src, 4);
UNFORMAT_HAS_SPACE(src, len2);
- if (len3)
- *len3 = len2;
+ if (len)
+ *len = len2;
if (x)
*x = src->data;
silc_buffer_pull(src, len2);
break;
}
- case SILC_PARAM_BUFFER:
+ case SILC_BUFFER_PARAM_UI_XNSTRING:
{
- SilcBuffer x = va_arg(ap, SilcBuffer);
- SilcUInt32 len2;
- UNFORMAT_HAS_SPACE(src, 4);
- SILC_GET32_MSB(len2, src->data);
- silc_buffer_pull(src, 4);
- UNFORMAT_HAS_SPACE(src, len2);
- silc_buffer_set(x, src->data, len2);
- silc_buffer_pull(src, len2);
- }
- break;
- case SILC_PARAM_BUFFER_ALLOC:
- {
- SilcBuffer x = va_arg(ap, SilcBuffer);
- SilcUInt32 len2;
- UNFORMAT_HAS_SPACE(src, 4);
- SILC_GET32_MSB(len2, src->data);
- silc_buffer_pull(src, 4);
- UNFORMAT_HAS_SPACE(src, len2);
- silc_buffer_sformat(stack, x,
- SILC_STR_DATA(src->data, len2),
- SILC_STR_END);
- silc_buffer_pull(src, len2);
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SilcUInt32 len = va_arg(ap, SilcUInt32);
+ UNFORMAT_HAS_SPACE(src, len);
+ if (len && x)
+ *x = src->data;
+ silc_buffer_pull(src, len);
+ break;
}
- break;
- case SILC_PARAM_OFFSET:
+ case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
{
- int offst = va_arg(ap, int);
- if (!offst)
- break;
- if (offst > 1) {
- UNFORMAT_HAS_SPACE(src, offst);
- silc_buffer_pull(src, offst);
- } else {
- silc_buffer_push(src, -(offst));
+ unsigned char **x = va_arg(ap, unsigned char **);
+ SilcUInt32 len = va_arg(ap, SilcUInt32);
+ UNFORMAT_HAS_SPACE(src, len);
+ if (len && x) {
+ *x = silc_calloc(len + 1, sizeof(unsigned char));
+ memcpy(*x, src->data, len);
}
+ silc_buffer_pull(src, len);
break;
}
- case SILC_PARAM_ADVANCE:
- advance = TRUE;
- break;
- case SILC_PARAM_END:
+ case SILC_BUFFER_PARAM_END:
goto ok;
break;
default:
}
fail:
- SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
+ SILC_LOG_DEBUG(("Error occured while unformatting buffer"));
len = src->data - start_ptr;
silc_buffer_push(src, len);
return -1;
ok:
/* Push the buffer back to the start. */
- if (!advance) {
- len = src->data - start_ptr;
- silc_buffer_push(src, len);
- }
+ len = src->data - start_ptr;
+ silc_buffer_push(src, len);
return len;
}
-
-/**************************** Utility functions *****************************/
-
/* Formats strings into a buffer */
int silc_buffer_strformat(SilcBuffer dst, ...)
{
- int len = silc_buffer_truelen(dst);
- int hlen = silc_buffer_headlen(dst);
- va_list va;
-
- va_start(va, dst);
-
- /* Parse the arguments by formatting type. */
- while(1) {
- char *string = va_arg(va, char *);
- unsigned char *d;
- SilcInt32 slen;
-
- if (!string)
- continue;
- if (string == (char *)SILC_PARAM_END)
- goto ok;
-
- slen = strlen(string);
- d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
- if (silc_unlikely(!d))
- return -1;
- dst->head = d;
- memcpy(dst->head + len, string, slen);
- len += slen;
- dst->head[len] = '\0';
- }
-
- SILC_LOG_DEBUG(("Error occured while formatting buffer"));
- va_end(va);
- return -1;
-
- ok:
- dst->end = dst->head + len;
- dst->data = dst->head + hlen;
- dst->tail = dst->end;
-
- va_end(va);
- return len;
-}
-
-/* Formats strings into a buffer. Allocates memory from SilcStack. */
-
-int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
-{
- int len = silc_buffer_truelen(dst);
- int hlen = silc_buffer_headlen(dst);
+ int len = dst->truelen;
va_list va;
va_start(va, dst);
/* Parse the arguments by formatting type. */
while(1) {
- char *string = va_arg(va, char *);
- unsigned char *d;
- SilcInt32 slen;
+ char *string = (char *)va_arg(va, void *);
if (!string)
continue;
- if (string == (char *)SILC_PARAM_END)
+ if (string == (char *)SILC_BUFFER_PARAM_END)
goto ok;
- slen = strlen(string);
- d = silc_srealloc_ua(stack, len + 1, dst->head,
- sizeof(*dst->head) * (slen + len + 1));
- if (silc_unlikely(!d))
+ dst->head = silc_realloc(dst->head, sizeof(*dst->head) *
+ (strlen(string) + len + 1));
+ if (!dst->head)
return -1;
- dst->head = d;
- memcpy(dst->head + len, string, slen);
- len += slen;
+ memcpy(dst->head + len, string, strlen(string));
+ len += strlen(string);
dst->head[len] = '\0';
}
ok:
dst->end = dst->head + len;
- dst->data = dst->head + hlen;
+ dst->data = dst->head;
dst->tail = dst->end;
+ dst->len = dst->truelen = len;
va_end(va);
return len;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2004 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
*
* DESCRIPTION
*
- * SILC Buffer Format API provides functions for formatting different data
- * types into a buffer and retrieving different data types from a buffer
- * into specified data types. It is especially useful to format packets,
- * protocol payloads and such.
- *
- * As the SilcBuffer API is not thread-safe these routines may not be used
- * in multithreaded environment with a same SilcBuffer context without
- * concurrency control.
+ * SILC Buffer Format API provides a few functions for formatting
+ * various different data types into a buffer, and retrieving
+ * various data from buffer into specific data types. It is usefull
+ * to format for example packets and later unformat them.
*
***/
#ifndef SILCBUFFMT_H
#define SILCBUFFMT_H
-/****f* silcutil/SilcBufferFormatAPI/SilcBufferFormatFunc
- *
- * SYNOPSIS
- *
- * typedef int (*SilcBufferFormatFunc)(SilcBuffer buffer,
- * void *value,
- * void *context);
- *
- * DESCRIPTION
- *
- * Formatting function callback given with SILC_STR_FUNC type. The
- * `buffer' is the buffer being formatted at the location where the
- * SILC_STR_FUNC was placed in formatting. The function should call
- * silc_buffer_enlarge before it adds the data to the buffer to make
- * sure that it has enough space. The buffer->head points to the
- * start of the buffer and silc_buffer_headlen() gives the length
- * of the currently formatted data area. It is also possible to use
- * silc_buffer_format with `buffer' which will enlarge the buffer if
- * needed.
- *
- * The `value' is the value given to SILC_STR_FUNC that is to be formatted
- * into the buffer. It may be NULL if the function is not formatting
- * new data into the buffer. The `context' is caller specific context.
- * Returns -1 on error and length of the formatted value otherwise, and
- * 0 if nothing was formatted.
- *
- ***/
-typedef int (*SilcBufferFormatFunc)(SilcBuffer buffer, void *value,
- void *context);
-
-/****f* silcutil/SilcBufferFormatAPI/SilcBufferSFormatFunc
- *
- * SYNOPSIS
- *
- * typedef int (*SilcBufferSFormatFunc)(SilcStack stack,
- * SilcBuffer buffer,
- * void *value,
- * void *context);
- *
- * DESCRIPTION
- *
- * Formatting function callback given with SILC_STR_FUNC type. The
- * `buffer' is the buffer being formatted at the location where the
- * SILC_STR_FUNC was placed in formatting. The function should call
- * silc_buffer_senlarge before it adds the data to the buffer to make
- * sure that it has enough space. The buffer->head points to the
- * start of the buffer and silc_buffer_headlen() gives the length
- * of the currently formatted data area. It is also possible to use
- * silc_buffer_sformat with `buffer' which will enlarge the buffer if
- * needed.
- *
- * The `value' is the value given to SILC_STR_FUNC that is to be formatted
- * into the buffer. It may be NULL if the function is not formatting
- * new data into the buffer. The `context' is caller specific context.
- * Returns -1 on error and length of the formatted value otherwise, and
- * 0 if nothing was formatted.
- *
- * This is same as SilcBufferFormatFunc except the SilcStack will be
- * delivered. This callback must be used when SilcStack is used with
- * formatting.
- *
- ***/
-typedef int (*SilcBufferSFormatFunc)(SilcStack stack, SilcBuffer buffer,
- void *value, void *context);
-
-/****f* silcutil/SilcBufferFormatAPI/SilcBufferUnformatFunc
- *
- * SYNOPSIS
- *
- * typedef int (*SilcBufferUnformatFunc)(SilcBuffer buffer,
- * void **value,
- * void *context);
- *
- * DESCRIPTION
- *
- * Unformatting function callback given with SILC_STR_FUNC type. The
- * `buffer' is the buffer being unformatted and is at the location where
- * the SILC_STR_FUNC was placed in unformatting. The function should
- * check there is enough data in the `buffer' before trying to decode
- * from it.
- *
- * If this function unformats anything from the buffer its value is to
- * be returned to the `value' pointer. The implementation should itself
- * decide whether the unformatted value is allocated or not. If this
- * function does not unformat anything, nothing is returned to `value'
- *
- * The `context' is caller specific context. Returns -1 on error, and
- * length of the unformatted value otherwise, and 0 if nothing was
- * unformatted.
- *
- ***/
-typedef int (*SilcBufferUnformatFunc)(SilcBuffer buffer, void **value,
- void *context);
-
-/****f* silcutil/SilcBufferFormatAPI/SilcBufferSUnformatFunc
- *
- * SYNOPSIS
- *
- * typedef int (*SilcBufferSUnformatFunc)(SilcStack stack,
- * SilcBuffer buffer,
- * void **value,
- * void *context);
- *
- * DESCRIPTION
- *
- * Unformatting function callback given with SILC_STR_FUNC type. The
- * `buffer' is the buffer being unformatted and is at the location where
- * the SILC_STR_FUNC was placed in unformatting. The function should
- * check there is enough data in the `buffer' before trying to decode
- * from it.
- *
- * If this function unformats anything from the buffer its value is to
- * be returned to the `value' pointer. The implementation should itself
- * decide whether the unformatted value is allocated or not. If this
- * function does not unformat anything, nothing is returned to `value'
- *
- * The `context' is caller specific context. Returns -1 on error, and
- * length of the unformatted value otherwise, and 0 if nothing was
- * unformatted.
- *
- * This is same as SilcBufferUnformatFunc except the SilcStack will be
- * delivered. This callback must be used when SilcStack is used with
- * unformatting.
- *
- ***/
-typedef int (*SilcBufferSUnformatFunc)(SilcStack stack, SilcBuffer buffer,
- void **value, void *context);
-
/* Prototypes */
/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format
* DESCRIPTION
*
* Formats a buffer from a variable argument list. Returns -1 on error
- * and the length of the formatted buffer otherwise. The buffer is
- * enlarged automatically during formatting, if it doesn't already have
- * enough space.
+ * and the length of the formatted buffer otherwise.
*
* EXAMPLE
*
- * Three basic ways of using silc_buffer_format:
- *
- * // Statically allocated zero size buffer
- * SilcBufferStruct buffer;
- *
- * memset(&buffer, 0, sizeof(buffer));
- * ret = silc_buffer_format(&buffer,
- * SILC_STR_UI_INT(intval),
+ * ret = silc_buffer_format(buffer,
+ * SILC_STR_INT(intval),
* SILC_STR_CHAR(charval),
- * SILC_STR_UI_INT(intval),
+ * SILC_STR_INT(intval),
* SILC_STR_SHORT(str_len),
- * SILC_STR_DATA(str, str_len),
- * SILC_STR_END);
- * if (ret < 0)
- * error;
- *
- * // Free the allocated data
- * silc_buffer_purge(&buffer);
- *
- * // Dynamically allocated zero size buffer
- * SilcBuffer buf;
- * buf = silc_buffer_alloc(0);
- * ret = silc_buffer_format(buf,
- * SILC_STR_UI_INT(intval),
- * SILC_STR_CHAR(charval),
- * SILC_STR_END);
- * if (ret < 0)
- * error;
- *
- * // Free the allocated buffer
- * silc_buffer_free(buf);
- *
- * // Dynamically allocated buffer with enough space
- * SilcBuffer buf;
- * buf = silc_buffer_alloc(2 + str_len);
- * ret = silc_buffer_format(buf,
- * SILC_STR_UI_SHORT(str_len),
- * SILC_STR_DATA(str, str_len),
+ * SILC_STR_UI_XNSTRING(str, str_len),
* SILC_STR_END);
* if (ret < 0)
* error;
***/
int silc_buffer_format(SilcBuffer dst, ...);
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_sformat
- *
- * SYNOPSIS
- *
- * int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...);
- *
- * DESCRIPTION
- *
- * Same as silc_buffer_format but uses `stack' to allocate the memory.
- * if `stack' is NULL reverts back to silc_buffer_format call.
- *
- ***/
-int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...);
-
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format_vp
- *
- * SYNOPSIS
- *
- * int silc_buffer_format_vp(SilcBuffer dst, va_list vp);
- *
- * DESCRIPTION
- *
- * Formats a buffer from a variable argument list indicated by the `ap'.
- * Returns -1 on error and the length of the formatted buffer otherwise.
- *
- ***/
-int silc_buffer_format_vp(SilcBuffer dst, va_list ap);
-
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_sformat_vp
- *
- * SYNOPSIS
- *
- * int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list vp);
- *
- * DESCRIPTION
- *
- * Same as silc_buffer_format_vp but uses `stack' to allocate the memory.
- * if `stack' is NULL reverts back to silc_buffer_format_vp call.
- *
- ***/
-int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap);
-
/****f* silcutil/SilcBufferFormatAPI/silc_buffer_unformat
*
* SYNOPSIS
* EXAMPLE
*
* ret = silc_buffer_unformat(buffer,
- * SILC_STR_UI_INT(&intval),
+ * SILC_STR_INT(&intval),
* SILC_STR_CHAR(&charval),
- * SILC_STR_OFFSET(4),
+ * SILC_STR_INT(&intval2),
* SILC_STR_UI16_NSTRING_ALLOC(&str, &str_len),
* SILC_STR_END);
* if (ret < 0)
***/
int silc_buffer_unformat(SilcBuffer src, ...);
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_sunformat
+/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format_vp
*
* SYNOPSIS
*
- * int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...);
+ * int silc_buffer_format_vp(SilcBuffer dst, va_list vp);
*
* DESCRIPTION
*
- * Same as silc_buffer_unformat but uses `stack' to allocate the memory.
- * if `stack' is NULL reverts back to silc_buffer_format call.
+ * Formats a buffer from a variable argument list indicated by the `ap'.
+ * Returns -1 on error and the length of the formatted buffer otherwise.
*
***/
-int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...);
+int silc_buffer_format_vp(SilcBuffer dst, va_list ap);
/****f* silcutil/SilcBufferFormatAPI/silc_buffer_unformat_vp
*
***/
int silc_buffer_unformat_vp(SilcBuffer src, va_list ap);
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_sunformat_vp
- *
- * SYNOPSIS
- *
- * int silc_buffer_sunformat_vp(SilcBuffer src, va_list vp);
- *
- * DESCRIPTION
- *
- * Same as silc_buffer_unformat_vp but uses `stack' to allocate the
- * memory. if `stack' is NULL reverts back to silc_buffer_format_vp call.
- *
- ***/
-int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap);
-
/****f* silcutil/SilcBufferFormatAPI/silc_buffer_strformat
*
* SYNOPSIS
*
- * int silc_buffer_strformat(SilcBuffer dst, ...);
+ * int silc_buffer_strformat(SilcBuffer dst, ...);
*
* DESCRIPTION
*
- * Formats a buffer from variable argument list of strings. Each
- * string must be NULL-terminated and the variable argument list must
- * be end with SILC_STRFMT_END argument. This allows that a string in
- * the list can be NULL, in which case it is skipped. This automatically
- * allocates the space for the buffer data but `dst' must be already
- * allocated by the caller.
+ * Formats a buffer from variable argument list of strings. Each
+ * string must be NULL-terminated and the variable argument list must
+ * be end with SILC_STRFMT_END argument. This allows that a string in
+ * the list can be NULL, in which case it is skipped. This automatically
+ * allocates the space for the buffer data but `dst' must be already
+ * allocated by the caller.
*
* EXAMPLE
*
***/
int silc_buffer_strformat(SilcBuffer dst, ...);
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_sstrformat
- *
- * SYNOPSIS
- *
- * int silc_buffer_strformat(SilcStack stack, SilcBuffer dst, ...);
- *
- * DESCRIPTION
- *
- * Formats a buffer from variable argument list of strings. Each
- * string must be NULL-terminated and the variable argument list must
- * be end with SILC_STRFMT_END argument. This allows that a string in
- * the list can be NULL, in which case it is skipped. This automatically
- * allocates the space for the buffer data but `dst' must be already
- * allocated by the caller. This function is equivalent to
- * silc_buffer_strformat but allocates memory from `stack'.
- *
- ***/
-int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...);
+/* Macros for expanding parameters into variable function argument list.
+ These are passed to silc_buffer_format and silc_buffer_unformat
+ functions. */
-/****d* silcutil/SilcBufferFormatAPI/SilcBufferParamType
- *
- * NAME
- *
- * typedef enum { ... } SilcBufferParamType;
- *
- * DESCRIPTION
- *
- * Buffer parameter types. These are not needed when formatting or
- * unformatting buffers. Use the macros such as SILC_STR_UI_CHAR and
- * others instead. These types may be used when describing what a
- * buffer looks like, and how it may be formatted and unformatted.
- *
- * SOURCE
- */
+/* Buffer parameter types.
+
+ _SI_ = signed
+ _UI_ = unsigned
+
+ Any XXX_STRING_ALLOC types will allocate space for the data and
+ memcpy the data to the pointer sent as argument (in unformatting).
+
+ Any XXX_STRING will not allocate or copy any data. Instead it
+ will set the pointer to the data. Note that the data pointer
+ returned (in unformatting) must not be freed.
+
+*/
typedef enum {
- SILC_PARAM_SI8_CHAR, /* Signed 8-bit char */
- SILC_PARAM_UI8_CHAR, /* Unsigned 8-bit char */
- SILC_PARAM_SI16_SHORT, /* Signed 16-bit int */
- SILC_PARAM_UI16_SHORT, /* Unsigned 16-bit int */
- SILC_PARAM_SI32_INT, /* Signed 32-bit int */
- SILC_PARAM_UI32_INT, /* Unsigned 32-bit int */
- SILC_PARAM_SI64_INT, /* Signed 64-bit int */
- SILC_PARAM_UI64_INT, /* Unsigned 64-bit int */
- SILC_PARAM_UI8_STRING, /* String (max len 8-bits)*/
- SILC_PARAM_UI16_STRING, /* String (max len 16-bits) */
- SILC_PARAM_UI32_STRING, /* String (max len 32-bits) */
- SILC_PARAM_BUFFER, /* SilcBuffer */
-
- /* Internal types */
- SILC_PARAM_DATA, /* Binary data */
- SILC_PARAM_UI8_NSTRING, /* String (max len 8-bits) */
- SILC_PARAM_UI16_NSTRING, /* String (max len 16-bits) */
- SILC_PARAM_UI32_NSTRING, /* String (max len 32-bits) */
- SILC_PARAM_UI8_STRING_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_UI16_STRING_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_UI32_STRING_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_UI8_NSTRING_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_UI16_NSTRING_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_UI32_NSTRING_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_DATA_ALLOC, /* Alloc + memcpy */
- SILC_PARAM_BUFFER_ALLOC, /* Alloc + memcpy */
-
- SILC_PARAM_OFFSET,
- SILC_PARAM_ADVANCE,
- SILC_PARAM_FUNC,
-
- SILC_PARAM_UI_XNSTRING,
- SILC_PARAM_UI_XNSTRING_ALLOC,
-
- SILC_PARAM_END
+ SILC_BUFFER_PARAM_SI8_CHAR,
+ SILC_BUFFER_PARAM_UI8_CHAR,
+
+ SILC_BUFFER_PARAM_SI16_SHORT,
+ SILC_BUFFER_PARAM_UI16_SHORT,
+
+ SILC_BUFFER_PARAM_SI32_INT,
+ SILC_BUFFER_PARAM_UI32_INT,
+
+ SILC_BUFFER_PARAM_SI64_INT,
+ SILC_BUFFER_PARAM_UI64_INT,
+
+ SILC_BUFFER_PARAM_UI8_STRING, /* No copy */
+ SILC_BUFFER_PARAM_UI8_STRING_ALLOC, /* Alloc + memcpy */
+ SILC_BUFFER_PARAM_UI16_STRING, /* No copy */
+ SILC_BUFFER_PARAM_UI16_STRING_ALLOC, /* Alloc + memcpy */
+ SILC_BUFFER_PARAM_UI32_STRING, /* No copy */
+ SILC_BUFFER_PARAM_UI32_STRING_ALLOC, /* Alloc + memcpy */
+ SILC_BUFFER_PARAM_UI8_NSTRING, /* No copy */
+ SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC, /* Alloc + memcpy */
+ SILC_BUFFER_PARAM_UI16_NSTRING, /* No copy */
+ SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC, /* Alloc + memcpy */
+ SILC_BUFFER_PARAM_UI32_NSTRING, /* No copy */
+ SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC, /* Alloc + memcpy */
+ SILC_BUFFER_PARAM_UI_XNSTRING, /* No copy */
+ SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, /* Alloc + memcpy */
+
+ SILC_BUFFER_PARAM_END
} SilcBufferParamType;
-/***/
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_CHAR
*
* SILC_STR_UI_CHAR(unsigned char *)
*
***/
-#define SILC_STR_SI_CHAR(x) SILC_PARAM_SI8_CHAR, (x)
-#define SILC_STR_UI_CHAR(x) SILC_PARAM_UI8_CHAR, (x)
+#define SILC_STR_SI_CHAR(x) SILC_BUFFER_PARAM_SI8_CHAR, (x)
+#define SILC_STR_UI_CHAR(x) SILC_BUFFER_PARAM_UI8_CHAR, (x)
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_SHORT
*
*
* DESCRIPTION
*
- * SilcInt16/SilcUInt16.
+ * Signed/SilcUInt16.
*
- * Formatting: SILC_STR_SI_SHORT(SilcInt16)
+ * Formatting: SILC_STR_SI_SHORT(short)
* SILC_STR_UI_SHORT(SilcUInt16)
- * Unformatting: SILC_STR_SI_SHORT(SilcInt16 *)
+ * Unformatting: SILC_STR_SI_SHORT(short *)
* SILC_STR_UI_SHORT(SilcUInt16 *)
*
***/
-#define SILC_STR_SI_SHORT(x) SILC_PARAM_SI16_SHORT, (x)
-#define SILC_STR_UI_SHORT(x) SILC_PARAM_UI16_SHORT, (x)
+#define SILC_STR_SI_SHORT(x) SILC_BUFFER_PARAM_SI16_SHORT, (x)
+#define SILC_STR_UI_SHORT(x) SILC_BUFFER_PARAM_UI16_SHORT, (x)
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_INT
*
*
* DESCRIPTION
*
- * SilcInt32/SilcUInt32.
+ * Signed/SilcUInt32.
*
- * Formatting: SILC_STR_SI_INT(SilcInt32)
+ * Formatting: SILC_STR_SI_INT(int)
* SILC_STR_UI_INT(SilcUInt32)
- * Unformatting: SILC_STR_SI_INT(SilcInt32 *)
+ * Unformatting: SILC_STR_SI_INT(int *)
* SILC_STR_UI_INT(SilcUInt32 *)
*
***/
-#define SILC_STR_SI_INT(x) SILC_PARAM_SI32_INT, (x)
-#define SILC_STR_UI_INT(x) SILC_PARAM_UI32_INT, (x)
+#define SILC_STR_SI_INT(x) SILC_BUFFER_PARAM_SI32_INT, (x)
+#define SILC_STR_UI_INT(x) SILC_BUFFER_PARAM_UI32_INT, (x)
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_INT64
*
*
* DESCRIPTION
*
- * SilcInt64/SilcUInt64.
+ * Signed/SilcUInt64.
*
- * Formatting: SILC_STR_SI_INT64(SilcInt64)
- * SILC_STR_UI_INT64(SilcUInt64)
- * Unformatting: SILC_STR_SI_INT64(SilcInt64 *)
- * SILC_STR_UI_INT64(SilcUInt64 *)
+ * Formatting: SILC_STR_SI_INT64(int)
+ * SILC_STR_UI_INT64(SilcUInt32)
+ * Unformatting: SILC_STR_SI_INT64(int *)
+ * SILC_STR_UI_INT64(SilcUInt32 *)
*
***/
-#define SILC_STR_SI_INT64(x) SILC_PARAM_SI64_INT, (x)
-#define SILC_STR_UI_INT64(x) SILC_PARAM_UI64_INT, (x)
+#define SILC_STR_SI_INT64(x) SILC_BUFFER_PARAM_SI64_INT, (x)
+#define SILC_STR_UI_INT64(x) SILC_BUFFER_PARAM_UI64_INT, (x)
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_STRING
*
* as argument in unformatting.
*
***/
-#define SILC_STR_UI8_STRING(x) SILC_PARAM_UI8_STRING, (x)
-#define SILC_STR_UI8_STRING_ALLOC(x) SILC_PARAM_UI8_STRING_ALLOC, (x)
-#define SILC_STR_UI16_STRING(x) SILC_PARAM_UI16_STRING, (x)
-#define SILC_STR_UI16_STRING_ALLOC(x) SILC_PARAM_UI16_STRING_ALLOC, (x)
-#define SILC_STR_UI32_STRING(x) SILC_PARAM_UI32_STRING, (x)
-#define SILC_STR_UI32_STRING_ALLOC(x) SILC_PARAM_UI32_STRING_ALLOC, (x)
+#define SILC_STR_UI8_STRING(x) SILC_BUFFER_PARAM_UI8_STRING, (x)
+#define SILC_STR_UI8_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI8_STRING_ALLOC, (x)
+#define SILC_STR_UI16_STRING(x) SILC_BUFFER_PARAM_UI16_STRING, (x)
+#define SILC_STR_UI16_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI16_STRING_ALLOC, (x)
+#define SILC_STR_UI32_STRING(x) SILC_BUFFER_PARAM_UI32_STRING, (x)
+#define SILC_STR_UI32_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI32_STRING_ALLOC, (x)
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_NSTRING
*
* as argument in unformatting.
*
***/
-#define SILC_STR_UI8_NSTRING(x, l) SILC_PARAM_UI8_NSTRING, (x), (l)
+#define SILC_STR_UI8_NSTRING(x, l) SILC_BUFFER_PARAM_UI8_NSTRING, (x), (l)
#define SILC_STR_UI8_NSTRING_ALLOC(x, l) \
- SILC_PARAM_UI8_NSTRING_ALLOC, (x), (l)
-#define SILC_STR_UI16_NSTRING(x, l) SILC_PARAM_UI16_NSTRING, (x), (l)
+ SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC, (x), (l)
+#define SILC_STR_UI16_NSTRING(x, l) SILC_BUFFER_PARAM_UI16_NSTRING, (x), (l)
#define SILC_STR_UI16_NSTRING_ALLOC(x, l) \
- SILC_PARAM_UI16_NSTRING_ALLOC, (x), (l)
-#define SILC_STR_UI32_NSTRING(x, l) SILC_PARAM_UI32_NSTRING, (x), (l)
+ SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC, (x), (l)
+#define SILC_STR_UI32_NSTRING(x, l) SILC_BUFFER_PARAM_UI32_NSTRING, (x), (l)
#define SILC_STR_UI32_NSTRING_ALLOC(x, l) \
- SILC_PARAM_UI32_NSTRING_ALLOC, (x), (l)
+ SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC, (x), (l)
-/****d* silcutil/SilcBufferFormatAPI/SILC_STR_DATA
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_UI_XNSTRING
*
* NAME
*
- * #define SILC_STR_DATA() ...
- * #define SILC_STR_DATA_ALLOC() ...
+ * #define SILC_STR_UI_XNSTRING() ...
+ * #define SILC_STR_UI_XNSTRING_ALLOC() ...
*
* DESCRIPTION
*
- * Binary data formatting. Second argument is the length of the data.
+ * Extended Unsigned string formatting. Second argument is the length of
+ * the string.
*
- * Formatting: SILC_STR_DATA(unsigned char *, SilcUInt32)
- * Unformatting: SILC_STR_DATA(unsigned char **, SilcUInt32)
+ * Formatting: SILC_STR_UI_XNSTRING(unsigned char *, SilcUInt32)
+ * Unformatting: SILC_STR_UI_XNSTRING(unsigned char **, SilcUInt32)
*
- * This type can be used to take arbitrary size data block from the buffer
- * by sending the requested amount of bytes as argument.
+ * This type can be used to take arbitrary length string from the buffer
+ * by sending the requested amount of bytes as argument. This differs
+ * from *_STRING and *_NSTRING so that this doesn't try to find the
+ * length of the data from the buffer but the length of the data is
+ * sent as argument. This a handy way to unformat fixed length strings
+ * from the buffer without having the length of the string formatted
+ * in the buffer.
*
* _ALLOC routines automatically allocates memory for the variable sent
* as argument in unformatting.
*
***/
-#define SILC_STR_DATA(x, l) SILC_PARAM_DATA, (x), (l)
-#define SILC_STR_DATA_ALLOC(x, l) SILC_PARAM_DATA_ALLOC, (x), (l)
-
-/* Deprecated */
-#define SILC_STR_UI_XNSTRING(x, l) SILC_PARAM_UI_XNSTRING, (x), (l)
-#define SILC_STR_UI_XNSTRING_ALLOC(x, l) SILC_PARAM_UI_XNSTRING_ALLOC, (x), (l)
-
-/****d* silcutil/SilcBufferFormatAPI/SILC_STR_BUFFER
- *
- * NAME
- *
- * #define SILC_STR_BUFFER() ...
- * #define SILC_STR_BUFFER_ALLOC() ...
- *
- * DESCRIPTION
- *
- * SilcBuffer formatting.
- *
- * Formatting: SILC_STR_BUFFER(SilcBuffer)
- * Unformatting: SILC_STR_BUFFER(SilcBuffer)
- *
- * This type can be used to format and unformat SilcBuffer. Note that, the
- * length of the buffer will be automatically encoded into the buffer as
- * a 32-bit integer. In unformatting the SilcBuffer context must be
- * pre-allocated.
- *
- * _ALLOC routines automatically allocates memory inside SilcBuffer in
- * unformatting.
- *
- ***/
-#define SILC_STR_BUFFER(x) SILC_PARAM_BUFFER, (x)
-#define SILC_STR_BUFFER_ALLOC(x) SILC_PARAM_BUFFER_ALLOC, (x)
-
-/****d* silcutil/SilcBufferFormatAPI/SILC_STR_FUNC
- *
- * NAME
- *
- * #define SILC_STR_FUNC() ...
- *
- * DESCRIPTION
- *
- * SilcBuffer formatting.
- *
- * Formatting: SILC_STR_FUNC(function, void *value, void *context)
- * Unformatting: SILC_STR_FUNC(function, void **value, void *context)
- *
- * This type can be used to call the `function' of the type
- * SilcBufferFormatFunc or SilcBufferUnformatFunc to encode or decode
- * the `value'. In encoding the `value' will be passed to the `function'
- * and can be encoded into the buffer. The buffer will be passed as
- * well to the `function' at the location where SILC_STR_FUNC is placed
- * in formatting. The `context' delivers caller specific context to
- * the `function'
- *
- * In unformatting the `function' will decode the encoded type and
- * return it to `value' pointer. The decoding function should decide
- * itself whether to allocate or not the decoded value.
- *
- * The `function' does not have to encode anything and passing `value'
- * as NULL is allowed. The `function' could for example modify the
- * existing buffer.
- *
- * EXAMPLE
- *
- * // Encode payload, encrypt and compute MAC.
- * silc_buffer_format(buf,
- * SILC_STR_FUNC(foo_encode_id, id, ctx),
- * SILC_STR_UI_SHORT(len),
- * SILC_STR_DATA(data, len),
- * SILC_STR_FUNC(foo_buf_encrypt, NULL, key),
- * SILC_STR_FUNC(foo_buf_hmac, NULL, hmac),
- * SILC_STR_DATA(iv, iv_len);
- * SILC_STR_END);
- *
- * // Check MAC, decrypt and decode payload
- * silc_buffer_unformat(buf,
- * SILC_STR_FUNC(foo_buf_hmac, NULL, hmac),
- * SILC_STR_FUNC(foo_buf_decrypt, NULL, key),
- * SILC_STR_FUNC(foo_decode_id, &id, ctx),
- * SILC_STR_UI_SHORT(&len),
- * SILC_STR_END);
- *
- ***/
-#define SILC_STR_FUNC(func, val, context) SILC_PARAM_FUNC, \
- func, (val), (context)
-
-/****d* silcutil/SilcBufferFormatAPI/SILC_STR_OFFSET
- *
- * NAME
- *
- * #define SILC_STR_OFFSET() ...
- *
- * DESCRIPTION
- *
- * Offset in buffer. This can be used in formatting and unformatting to
- * move the data pointer of the buffer either forwards (positive offset)
- * or backwards (negative offset). It can be used to for example skip
- * some types during unformatting.
- *
- * Example:
- *
- * ..., SILC_STR_OFFSET(5), ...
- * ..., SILC_STR_OFFSET(-3), ...
- *
- * Moves the data pointer at the point of the offset either forward
- * or backward and then moves to the next type. Multiple SILC_STR_OFFSETs
- * can be used in formatting and unformatting at the same time.
- *
- ***/
-#define SILC_STR_OFFSET(x) SILC_PARAM_OFFSET, (x)
-
-/****d* silcutil/SilcBufferFormatAPI/SILC_STR_ADVANCE
- *
- * NAME
- *
- * #define SILC_STR_ADVANCE ...
- *
- * DESCRIPTION
- *
- * Advance the buffer to the end of the data after the formatting is
- * done. In normal operation when the formatted data is written the
- * buffer is located at the start of the data. With SILC_STR_ADVANCE
- * the buffer will be located at the end of the data. This makes it
- * easy to add new data immediately after the previously added data.
- * The SILC_STR_ADVANCE may also be used in unformatting.
- *
- * EXAMPLE
- *
- * do {
- * len = read(fd, buf, sizeof(buf));
- * if (len > 0)
- * // Add read data to the buffer
- * silc_buffer_format(buffer,
- * SILC_STR_ADVANCE,
- * SILC_STR_DATA(buf, len),
- * SILC_STR_END);
- * } while (len > 0);
- *
- * // Move to beginning of buffer
- * silc_buffer_start(buffer);
- *
- ***/
-#define SILC_STR_ADVANCE SILC_PARAM_ADVANCE
+#define SILC_STR_UI_XNSTRING(x, l) SILC_BUFFER_PARAM_UI_XNSTRING, (x), (l)
+#define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
+ SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
/****d* silcutil/SilcBufferFormatAPI/SILC_STR_END
*
* argument list or error will occur.
*
***/
-#define SILC_STR_END SILC_PARAM_END
+#define SILC_STR_END SILC_BUFFER_PARAM_END
/****d* silcutil/SilcBufferFormatAPI/SILC_STRFMT_END
*
+++ /dev/null
-/*
-
- silccond.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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* silcutil/SILC Condition Variable Interface
- *
- * DESCRIPTION
- *
- * A condition variable interface for multi-thread synchronization.
- * Condition variables enable threads to suspend execution and yield
- * the processors until some predicate on some shared data is satisfied.
- *
- ***/
-
-#ifndef SILCCOND_H
-#define SILCCOND_H
-
-/****s* silcutil/SilcCondAPI/SilcCond
- *
- * NAME
- *
- * typedef struct SilcCondStruct *SilcCond;
- *
- * DESCRIPTION
- *
- * This context is the actual condition variable and is allocated
- * by silc_cond_alloc and given as argument to all silc_cond_*
- * functions. It is freed by the silc_cond_free function.
- *
- ***/
-typedef struct SilcCondStruct *SilcCond;
-
-/****s* silcutil/SilcCondAPI/silc_cond_alloc
- *
- * SYNOPSIS
- *
- * SilcBool silc_cond_alloc(SilcCond *cond);
- *
- * DESCRIPTION
- *
- * Allocates SILC Condition variable context. The condition must
- * be allocated before it can be used. It is freed by the
- * silc_cond_free function. This returns TRUE and allocated
- * condition in to the `cond' pointer and FALSE on error.
- *
- ***/
-SilcBool silc_cond_alloc(SilcCond *cond);
-
-/****s* silcutil/SilcCondAPI/silc_cond_free
- *
- * SYNOPSIS
- *
- * void silc_cond_free(SilcCond cond);
- *
- * DESCRIPTION
- *
- * Free condition variable context. If `cond' is NULL this function
- * has no effect.
- *
- ***/
-void silc_cond_free(SilcCond cond);
-
-/****s* silcutil/SilcCondAPI/silc_cond_wait
- *
- * SYNOPSIS
- *
- * void silc_cond_wait(SilcCond cond, SilcMutex mutex);
- *
- * DESCRIPTION
- *
- * Waits for condition variable `cond' to be signalled. This function
- * will block the calling thread until the condition variable is
- * signalled. The `mutex' must be locked before calling this function.
- * The `mutex' will be unlocked inside this function. After this
- * function returns the `mutex' is in locked state again.
- *
- * EXAMPLE
- *
- * silc_mutex_lock(lock);
- * while (c->a == NULL)
- * silc_cond_wait(cond, lock);
- * ...
- * silc_mutex_unlock(lock);
- *
- ***/
-void silc_cond_wait(SilcCond cond, SilcMutex mutex);
-
-/****s* silcutil/SilcCondAPI/silc_cond_timedwait
- *
- * SYNOPSIS
- *
- * void silc_cond_timedwait(SilcCond cond, SilcMutex mutex, int timeout);
- *
- * DESCRIPTION
- *
- * Waits for condition variable `cond' to be signalled or for the
- * `timeout' to expire. The timeout is in milliseconds. If it is 0
- * no timeout exist. Returns FALSE if timeout expired, TRUE when
- * signalled. This function will block the calling thread until the
- * condition variable is signalled. The `mutex' must be locked before
- * calling this function. The `mutex' will be unlocked inside this
- * function. After this function returns the `mutex' is in locked
- * state again.
- *
- ***/
-SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex, int timeout);
-
-/****s* silcutil/SilcCondAPI/silc_cond_signal
- *
- * SYNOPSIS
- *
- * void silc_cond_signal(SilcCond cond);
- *
- * DESCRIPTION
- *
- * Signals a waiting thread and wakes it up. If there are no waiters
- * this function has no effect. In case of multiple waiters only one
- * is signalled. To signal all of them use silc_cond_broadcast.
- *
- * NOTES
- *
- * Before calling this function the mutex used with the silc_cond_wait
- * must be acquired.
- *
- * EXAMPLE
- *
- * silc_mutex_lock(lock);
- * c->a = context;
- * silc_cond_signal(cond);
- * silc_mutex_unlock(lock);
- *
- ***/
-void silc_cond_signal(SilcCond cond);
-
-/****s* silcutil/SilcCondAPI/silc_cond_broadcast
- *
- * SYNOPSIS
- *
- * void silc_cond_broadcast(SilcCond cond);
- *
- * DESCRIPTION
- *
- * Signals and wakes up all waiters. If there are no waiters this
- * function has no effect.
- *
- * NOTES
- *
- * Before calling this function the mutex used with the silc_cond_wait
- * must be acquired.
- *
- ***/
-void silc_cond_broadcast(SilcCond cond);
-
-#endif /* SILCCOND_H */
Author: Giovanni Giacobbi <giovanni@giacobbi.net>
- Copyright (C) 2002 - 2006 Giovanni Giacobbi
+ Copyright (C) 2002 - 2003 Giovanni Giacobbi
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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* limit debug logging verbosity */
#if 0
char *p; /* the Parser poitner */
SilcUInt32 len; /* fixed length of the whole file */
SilcUInt32 line; /* current parsing line, strictly linked to p */
- SilcBool included; /* wether this file is main or included */
+ bool included; /* wether this file is main or included */
};
/* We need the entity to base our block-style parsing on */
static void my_trim_spaces(SilcConfigFile *file)
{
register char *r = file->p;
- while ((*r != '\0' && *r != EOF) && isspace((int)*r))
+ while ((*r != '\0' && *r != EOF) && isspace(*r))
if (*r++ == '\n') file->line++;
file->p = r;
}
-
/* Skips the current line until newline (lf or cr) */
static void my_skip_line(SilcConfigFile *file)
{
file->p = ((*r != '\0' && *r != EOF) ? r + 1 : r);
file->line++;
}
-
/* Obtains a text token from the current position until first separator.
* a separator is any non alphanumeric character nor "_" or "-" */
static char *my_next_token(SilcConfigFile *file, char *to)
register char *o;
my_trim_spaces(file);
o = file->p;
- while (isalnum((int)*o) || (*o == '_') || (*o == '-'))
+ while (isalnum(*o) || (*o == '_') || (*o == '-'))
*to++ = *o++;
*to = '\0';
file->p = o;
return to;
}
-
/* Obtains a string from the current position. The only difference from
* next_token() is that quoted-strings are also accepted */
static char *my_get_string(SilcConfigFile *file, char *to)
/* we don't need quote parsing, fall-back to token extractor */
my_next_token(file, to);
return to;
-}
-
+};
/* Skips all comment lines and spaces lines until first useful character */
static void my_skip_comments(SilcConfigFile *file)
{
}
return NULL;
}
-
/* Converts a string in the type specified. returns a dynamically
* allocated pointer. */
static void *silc_config_marshall(SilcConfigType type, const char *val)
{
void *pt;
int val_int;
- SilcBool val_boolean;
+ bool val_bool;
char *val_tmp;
SilcUInt32 val_size;
case SILC_CONFIG_ARG_TOGGLE:
if (!strcasecmp(val, "yes") || !strcasecmp(val, "true") ||
!strcasecmp(val, "on") || !strcasecmp(val, "1")) {
- val_boolean = TRUE;
+ val_bool = TRUE;
}
else if (!strcasecmp(val, "no") || !strcasecmp(val, "false") ||
!strcasecmp(val, "off") || !strcasecmp(val, "0")) {
- val_boolean = FALSE;
+ val_bool = FALSE;
}
else
return NULL;
- pt = silc_calloc(1, sizeof(val_boolean));
- *(SilcBool *)pt = (SilcBool) val_boolean;
+ pt = silc_calloc(1, sizeof(val_bool));
+ *(bool *)pt = (bool) val_bool;
return pt;
case SILC_CONFIG_ARG_INT:
val_int = (int) strtol(val, &val_tmp, 0);
if (val == val_tmp)
return NULL; /* really wrong, there must be at least one digit */
/* Search for a designator */
- switch (tolower((int)val_tmp[0])) {
+ switch (tolower(val_tmp[0])) {
case '\0': /* None */
break;
case 'k': /* Kilobytes */
ret = silc_calloc(1, sizeof(*ret));
ret->file = file;
return ret;
-}
+};
/* Returns the original filename of the object file */
/* (Private) destroy a SilcConfigEntity */
-static void silc_config_destroy(SilcConfigEntity ent, SilcBool destroy_opts)
+static void silc_config_destroy(SilcConfigEntity ent, bool destroy_opts)
{
SilcConfigOption *oldopt, *nextopt;
SILC_CONFIG_DEBUG(("Freeing config entity [ent=0x%x] [opts=0x%x]",
/* Registers a new option in the specified entity.
* Returns TRUE on success, FALSE if already registered. */
-SilcBool silc_config_register(SilcConfigEntity ent, const char *name,
+bool silc_config_register(SilcConfigEntity ent, const char *name,
SilcConfigType type, SilcConfigCallback cb,
const SilcConfigTable *subtable, void *context)
{
/* Register a new option table in the specified config entity */
-SilcBool silc_config_register_table(SilcConfigEntity ent,
+bool silc_config_register_table(SilcConfigEntity ent,
const SilcConfigTable table[], void *context)
{
int i;
*
* SYNOPSIS
*
- * SilcBool silc_config_register(SilcConfigEntity ent, const char *name,
+ * bool silc_config_register(SilcConfigEntity ent, const char *name,
* SilcConfigType type, SilcConfigCallback cb,
* const SilcConfigTable *subtable,
* void *context);
* silc_config_register_table
*
***/
-SilcBool silc_config_register(SilcConfigEntity ent, const char *name,
+bool silc_config_register(SilcConfigEntity ent, const char *name,
SilcConfigType type, SilcConfigCallback cb,
const SilcConfigTable *subtable, void *context);
*
* SYNOPSIS
*
- * SilcBool silc_config_register_table(SilcConfigEntity ent,
+ * bool silc_config_register_table(SilcConfigEntity ent,
* const SilcConfigTable table[],
* void *context);
*
* SilcConfigTable
*
***/
-SilcBool silc_config_register_table(SilcConfigEntity ent,
+bool silc_config_register_table(SilcConfigEntity ent,
const SilcConfigTable table[], void *context);
/****f* silcutil/SilcConfigAPI/silc_config_main
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2006 Pekka Riikonen
+ Copyright (C) 2000 - 2003 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
* will automatically allocate list entries. Normal SILC List API cannot
* be used for this purpose because in that case the context passed to the
* list must be defined as list structure already. This is not the case in
- * SilcDList. But SilcDList is a bit slower than SilcList because it
- * requires memory allocation when adding new entries to the list.
+ * SilcDList.
*
- * SILC Dynamic List is not thread-safe. If the same list context must be
- * used in multithreaded environment concurrency control must be employed.
+ * This is slower than SilcList because this requires one extra memory
+ * allocation when adding new entries to the list. The context is probably
+ * allocated already and the new list entry requires one additional memory
+ * allocation. The memory allocation and freeing is done automatically in
+ * the API and does not show to the caller.
*
***/
*/
typedef struct SilcDListStruct {
SilcList list;
- void *current;
- void *prev;
} *SilcDList;
/***/
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;
void silc_dlist_start(SilcDList list)
{
silc_list_start(list->list);
- list->current = list->prev = NULL;
}
/****f* silcutil/SilcDListAPI/silc_dlist_end
void silc_dlist_end(SilcDList list)
{
silc_list_end(list->list);
- list->current = list->prev = NULL;
}
/****f* silcutil/SilcDListAPI/silc_dlist_add
* SYNOPSIS
*
* static inline
- * SilcBool silc_dlist_add(SilcDList list, void *context);
+ * void silc_dlist_add(SilcDList list, void *context);
*
* DESCRIPTION
*
***/
static inline
-SilcBool silc_dlist_add(SilcDList list, void *context)
+void silc_dlist_add(SilcDList list, void *context)
{
SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
- if (silc_unlikely(!e))
- return FALSE;
+ if (!e)
+ return;
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 (silc_unlikely(!e))
- return FALSE;
- e->context = context;
- silc_list_insert(list->list, list->prev, e);
- return TRUE;
}
/****f* silcutil/SilcDListAPI/silc_dlist_del
#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;
}
static inline
void *silc_dlist_get(SilcDList list)
{
- SilcDListEntry e;
- list->prev = list->current;
- list->current = e = (SilcDListEntry)silc_list_get(list->list);
+ SilcDListEntry e = (SilcDListEntry)silc_list_get(list->list);
if (e != SILC_LIST_END)
return e->context;
return SILC_LIST_END;
+++ /dev/null
-/*
-
- silcfdstream.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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"
-
-/************************** Types and definitions ***************************/
-
-#define SILC_IS_FD_STREAM(s) (s->ops == &silc_fd_stream_ops)
-
-const SilcStreamOps silc_fd_stream_ops;
-
-/* FD stream context */
-typedef struct {
- const SilcStreamOps *ops;
- SilcSchedule schedule;
- SilcStreamNotifier notifier;
- void *notifier_context;
- int fd1;
- int fd2;
- int error;
-} *SilcFDStream;
-
-
-/************************ Static utility functions **************************/
-
-/* The IO process callback that calls the notifier callback to upper layer. */
-
-SILC_TASK_CALLBACK(silc_fd_stream_io)
-{
- SilcFDStream stream = context;
-
- if (!stream->notifier)
- return;
-
- switch (type) {
- case SILC_TASK_READ:
- stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context);
- break;
-
- case SILC_TASK_WRITE:
- stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context);
- break;
-
- default:
- break;
- }
-}
-
-
-/****************************** Public API **********************************/
-
-/* Create file descriptor stream */
-
-SilcStream silc_fd_stream_create(int fd)
-{
- if (fd < 1)
- return NULL;
- return silc_fd_stream_create2(fd, 0);
-}
-
-/* Create stream with two file descriptors */
-
-SilcStream silc_fd_stream_create2(int read_fd, int write_fd)
-{
- SilcFDStream stream;
-
- if (read_fd < 1)
- return NULL;
-
- stream = silc_calloc(1, sizeof(*stream));
- if (!stream)
- return NULL;
-
- SILC_LOG_DEBUG(("Creating new fd stream %p", stream));
-
- stream->ops = &silc_fd_stream_ops;
- stream->fd1 = read_fd;
- stream->fd2 = write_fd;
-
- return stream;
-}
-
-/* Create by opening file */
-
-SilcStream silc_fd_stream_file(const char *filename,
- SilcBool reading, SilcBool writing)
-{
- int fd, flags = 0;
-
- if (!filename)
- return NULL;
-
- if (reading)
- flags |= O_RDONLY;
- if (writing)
- flags |= O_CREAT | O_WRONLY;
- if (reading && writing)
- flags = O_CREAT | O_RDWR;
-
- fd = silc_file_open(filename, flags);
- if (fd < 0)
- return NULL;
-
- return silc_fd_stream_create(fd);
-}
-
-/* Return fds */
-
-SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd,
- int *write_fd)
-{
- SilcFDStream fd_stream = stream;
-
- if (!SILC_IS_FD_STREAM(fd_stream))
- return FALSE;
-
- if (read_fd)
- *read_fd = fd_stream->fd1;
- if (write_fd)
- *write_fd = fd_stream->fd2;
-
- return TRUE;
-}
-
-/* Return errno */
-
-int silc_fd_stream_get_error(SilcStream stream)
-{
- SilcFDStream fd_stream = stream;
-
- if (!SILC_IS_FD_STREAM(fd_stream))
- return 0;
-
- return fd_stream->error;
-}
-
-/* Read */
-
-int silc_fd_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- SilcFDStream fd_stream = stream;
- int len = 0;
-
- if (!fd_stream->notifier)
- return -2;
-
- SILC_LOG_DEBUG(("Reading data from fd %d", fd_stream->fd1));
-
- len = silc_file_read(fd_stream->fd1, buf, buf_len);
- if (len < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
- silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd1,
- SILC_TASK_READ, FALSE);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot read from fd: %d:%s",
- fd_stream->fd1, strerror(errno)));
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
- fd_stream->error = errno;
- return -2;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes", len));
-
- if (!len)
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
-
- return len;
-}
-
-/* Write */
-
-int silc_fd_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcFDStream fd_stream = stream;
- int ret;
-
- if (!fd_stream->notifier)
- return -2;
-
- SILC_LOG_DEBUG(("Writing data to fd %d", fd_stream->fd2));
-
- ret = silc_file_write(fd_stream->fd2, data, data_len);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
- silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
- SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot write to fd: %s", strerror(errno)));
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
- fd_stream->error = errno;
- return -2;
- }
-
- SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
-
- if (fd_stream->fd1 == fd_stream->fd2)
- silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
- SILC_TASK_READ, FALSE);
- else
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
-
- return ret;
-}
-
-/* Close stream */
-
-SilcBool silc_fd_stream_close(SilcStream stream)
-{
- SilcFDStream fd_stream = stream;
-
- if (fd_stream->fd1 > 0) {
- silc_file_close(fd_stream->fd1);
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
- }
- if (fd_stream->fd2 > 0 && fd_stream->fd2 != fd_stream->fd1) {
- silc_file_close(fd_stream->fd2);
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
- }
-
- return TRUE;
-}
-
-/* Destroy stream */
-
-void silc_fd_stream_destroy(SilcStream stream)
-{
- silc_fd_stream_close(stream);
- silc_free(stream);
-}
-
-/* Sets stream notification callback for the stream */
-
-SilcBool silc_fd_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
-{
- SilcFDStream fd_stream = stream;
-
- SILC_LOG_DEBUG(("Setting stream notifier callback"));
-
- 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);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
- }
-
- return TRUE;
-}
-
-/* Return schedule */
-
-SilcSchedule silc_fd_stream_get_schedule(SilcStream stream)
-{
- SilcFDStream fd_stream = stream;
- return fd_stream->schedule;
-}
-
-/* File descriptor stream operations */
-const SilcStreamOps silc_fd_stream_ops =
-{
- silc_fd_stream_read,
- silc_fd_stream_write,
- silc_fd_stream_close,
- silc_fd_stream_destroy,
- silc_fd_stream_notifier,
- silc_fd_stream_get_schedule
-};
+++ /dev/null
-/*
-
- silcfdstream.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* silcutil/SILC File Descriptor Stream Interface
- *
- * DESCRIPTION
- *
- * Implementation of SILC File Descriptor Stream. The file descriptor
- * stream can be used read from and write to a file descriptor. This
- * interface should be used only with real file descriptors, not with
- * sockets. Use the SILC Socket Stream for sockets.
- *
- * SILC File Descriptor Stream is not thread-safe. If same stream must be
- * used in multithreaded environment concurrency control must be employed.
- *
- ***/
-
-#ifndef SILCFDSTREAM_H
-#define SILCFDSTREAM_H
-
-/****f* silcutil/SilcFDStreamAPI/silc_fd_stream_create
- *
- * SYNOPSIS
- *
- * SilcStream silc_fd_stream_create(int fd);
- *
- * DESCRIPTION
- *
- * Creates file descriptor stream for the open file descriptor indicated
- * 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);
-
-/****f* silcutil/SilcFDStreamAPI/silc_fd_stream_create2
- *
- * SYNOPSIS
- *
- * SilcStream silc_fd_stream_create2(int read_fd, int write_fd);
- *
- * DESCRIPTION
- *
- * Creates file descriptor stream for the open file descriptors indicated
- * by `read_fd' and `write_fd'. The `read_fd' must be opened for reading
- * 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);
-
-/****f* silcutil/SilcFDStreamAPI/silc_fd_stream_file
- *
- * SYNOPSIS
- *
- * SilcStream silc_fd_stream_file(const char *filename, SilcBool reading,
- * SilcBool writing);
- *
- * DESCRIPTION
- *
- * Same as silc_fd_stream_create but creates the stream by opening the
- * file indicated by `filename'. If the `reading' is TRUE the file is
- * 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);
-
-/****f* silcutil/SilcFDStreamAPI/silc_fd_stream_get_info
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_fd_stream_get_info(SilcStream stream, int *read_fd, int *write_fd);
- *
- * DESCRIPTION
- *
- * Returns the file descriptors associated with the stream. The 'write_fd'
- * is available only if the stream was created with silc_fd_stream_create2
- * function.
- *
- ***/
-SilcBool silc_fd_stream_get_info(SilcStream stream,
- int *read_fd, int *write_fd);
-
-/****f* silcutil/SilcFDStreamAPI/silc_fd_stream_get_error
- *
- * SYNOPSIS
- *
- * int silc_fd_stream_get_error(SilcStream stream);
- *
- * DESCRIPTION
- *
- * If error occurred during file descriptor stream operations, this
- * function can be used to retrieve the error number that occurred.
- *
- ***/
-int silc_fd_stream_get_error(SilcStream stream);
-
-#endif /* SILCFDSTREAM_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005 Pekka Riikonen
+ Copyright (C) 1997 - 2003 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* Opens a file indicated by the filename `filename' with flags indicated
by the `flags'. */
int silc_file_open(const char *filename, int flags)
{
- return silc_file_open_mode(filename, flags, 0600);
+ int fd = open(filename, flags, 0600);
+ return fd;
}
/* Opens a file indicated by the filename `filename' with flags indicated
return -1;
}
- fsync(fd);
+ silc_file_close(fd);
- return silc_file_close(fd);
+ return 0;
}
/* Writes a buffer to the file. If the file is created specific mode is
return -1;
}
- fsync(fd);
+ silc_file_close(fd);
- return silc_file_close(fd);
+ return 0;
}
/* Reads a file to a buffer. The allocated buffer is returned. Length of
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005 Pekka Riikonen
+ Copyright (C) 1997 - 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
* DESCRIPTION
*
* Opens a file indicated by the filename `filename' with flags indicated
- * by `flags'. The opening permission defaults to 0600. The `flags'
- * are defined in open(2).
+ * by `flags'. The opening permission defaults to 0600.
*
***/
int silc_file_open(const char *filename, int flags);
*
* Opens a file indicated by the filename `filename' with flags indicated
* by `flags'. The argument `mode' specifies the permissions to use in
- * case a new file is created. The `flags' are defined in open(2).
+ * case a new file is created.
*
***/
int silc_file_open_mode(const char *filename, int flags, int mode);
***/
int silc_file_close(int fd);
-/****f* silcutil/SilcFileUtilAPI/silc_file_set_nonblock
- *
- * SYNOPSIS
- *
- * int silc_file_set_nonblock(int fd);
- *
- * DESCRIPTION
- *
- * Sets the file descriptor to non-blocking mode.
- *
- ***/
-int silc_file_set_nonblock(int fd);
-
/****f* silcutil/SilcFileUtilAPI/silc_file_readfile
*
* SYNOPSIS
+++ /dev/null
-/*
-
- silcfsm.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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"
-
-SILC_TASK_CALLBACK(silc_fsm_run);
-SILC_TASK_CALLBACK(silc_fsm_finish_fsm);
-SILC_TASK_CALLBACK(silc_fsm_event_timedout);
-SILC_TASK_CALLBACK(silc_fsm_start_real_thread);
-static void silc_fsm_thread_termination_signal(SilcFSMEvent event);
-static void silc_fsm_event_ref(SilcFSMEvent event);
-static void silc_fsm_event_unref(SilcFSMEvent event);
-void *silc_fsm_thread(void *context);
-
-/* Allocate FSM */
-
-SilcFSM silc_fsm_alloc(void *fsm_context,
- SilcFSMDestructor destructor,
- void *destructor_context,
- SilcSchedule schedule)
-{
- SilcFSM fsm;
-
- fsm = silc_calloc(1, sizeof(*fsm));
- if (silc_unlikely(!fsm))
- return NULL;
-
- if (silc_unlikely(!silc_fsm_init(fsm, fsm_context, destructor,
- destructor_context, schedule))) {
- silc_free(fsm);
- return NULL;
- }
-
- return fsm;
-}
-
-/* Initialize FSM */
-
-SilcBool silc_fsm_init(SilcFSM fsm,
- 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;
- fsm->thread = FALSE;
- fsm->async_call = FALSE;
- fsm->started = FALSE;
- fsm->u.m.lock = NULL;
- silc_atomic_init32(&fsm->u.m.threads, 0);
-
- return TRUE;
-}
-
-/* Allocate FSM thread. Internally machine and thread use same context. */
-
-SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
- void *thread_context,
- SilcFSMThreadDestructor destructor,
- void *destructor_context,
- SilcBool real_thread)
-{
- SilcFSMThread thread;
-
- thread = silc_calloc(1, sizeof(*thread));
- if (silc_unlikely(!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. */
-
-void silc_fsm_thread_init(SilcFSMThread thread,
- SilcFSM fsm,
- void *thread_context,
- SilcFSMThreadDestructor destructor,
- void *destructor_context,
- SilcBool real_thread)
-{
- SILC_LOG_DEBUG(("Initializing new thread %p (%s)",
- thread, real_thread ? "real" : "FSM"));
-
- SILC_ASSERT(!fsm->thread);
-
- thread->fsm_context = thread_context;
- thread->state_context = NULL;
- thread->destructor = (SilcFSMDestructor)destructor;
- thread->destructor_context = destructor_context;
- thread->schedule = fsm->schedule;
- thread->thread = TRUE;
- thread->async_call = FALSE;
- thread->started = FALSE;
- thread->real_thread = real_thread;
- thread->u.t.fsm = fsm;
-
- /* Add to machine */
- silc_atomic_add_int32(&fsm->u.m.threads, 1);
-
- /* Allocate lock for the machine if using real threads. */
- if (real_thread && !fsm->u.m.lock)
- if (!silc_mutex_alloc(&fsm->u.m.lock))
- thread->real_thread = FALSE;
-}
-
-/* FSM is destroyed through scheduler to make sure that all dying
- real system threads will have their finish callbacks scheduled before
- this one (when SILC_FSM_THREAD_WAIT was used). */
-
-SILC_TASK_CALLBACK(silc_fsm_free_final)
-{
- SilcFSM f = context;
-
-#if defined(SILC_DEBUG)
- /* We must be finished */
- SILC_ASSERT(f->finished);
-
- /* Machine must not have active threads */
- if (!f->thread && silc_atomic_get_int32(&f->u.m.threads))
- SILC_ASSERT(silc_atomic_get_int32(&f->u.m.threads) == 0);
-#endif /* SILC_DEBUG */
-
- if (!f->thread && f->u.m.lock)
- silc_mutex_free(f->u.m.lock);
-
- if (f->thread && f->u.t.event)
- silc_fsm_event_free(f->u.t.event);
-
- silc_free(f);
-}
-
-/* Free FSM */
-
-void silc_fsm_free(void *fsm)
-{
- SilcFSM f = fsm;
- if (!f->thread)
- if (silc_schedule_task_add_timeout(f->schedule, silc_fsm_free_final,
- f, 0, 0))
- return;
- silc_fsm_free_final(f->schedule, silc_schedule_get_context(f->schedule),
- 0, 0, f);
-}
-
-/* Task to start real thread. We start threads through scheduler, not
- directly in silc_fsm_start. */
-
-SILC_TASK_CALLBACK(silc_fsm_start_real_thread)
-{
- SilcFSM f = context;
-
-#ifdef SILC_THREADS
- if (silc_thread_create(silc_fsm_thread, f, FALSE))
- return;
-#endif /* SILC_THREADS */
-
- SILC_LOG_DEBUG(("Could not create real thread, using normal FSM thread"));
-
- /* Normal FSM operation */
- f->real_thread = FALSE;
- silc_fsm_continue_sync(f);
-}
-
-/* Start FSM in the specified state */
-
-void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state)
-{
- SilcFSM f = fsm;
-
- SILC_LOG_DEBUG(("Starting %s %p", f->thread ? "thread" : "FSM", fsm));
-
- f->finished = FALSE;
- f->next_state = start_state;
- f->synchronous = FALSE;
- f->started = TRUE;
-
- /* Start real thread through scheduler */
- if (f->thread && f->real_thread) {
- if (!silc_schedule_task_add_timeout(f->schedule,
- silc_fsm_start_real_thread,
- f, 0, 0))
- silc_fsm_start_real_thread(f->schedule,
- silc_schedule_get_context(f->schedule),
- 0, 0, f);
- return;
- }
-
- /* Normal FSM operation */
- if (!silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f, 0, 0))
- silc_fsm_run(f->schedule, silc_schedule_get_context(f->schedule), 0, 0, f);
-
- /* Wakeup scheduler in case we are starting this thread from another
- real thread. */
- if (f->thread)
- silc_schedule_wakeup(f->schedule);
-}
-
-/* Start FSM in the specified state synchronously */
-
-void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state)
-{
- SilcFSM f = fsm;
-
- SILC_LOG_DEBUG(("Starting %s %p", f->thread ? "thread" : "FSM", fsm));
-
- f->finished = FALSE;
- f->next_state = start_state;
- f->synchronous = TRUE;
- f->started = TRUE;
-
- /* Start real thread directly */
- if (f->thread && f->real_thread) {
- silc_fsm_start_real_thread(f->schedule,
- silc_schedule_get_context(f->schedule),
- 0, 0, f);
- return;
- }
-
- /* Normal FSM operation */
- silc_fsm_run(f->schedule, silc_schedule_get_context(f->schedule), 0, 0, f);
-}
-
-/* Set next FSM state */
-
-void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state)
-{
- SilcFSM f = fsm;
- f->next_state = next_state;
-}
-
-/* Continue after timeout */
-
-void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
- SilcUInt32 seconds, SilcUInt32 useconds)
-{
- 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);
- f->next_later = TRUE;
-}
-
-/* Continue after callback or async operation */
-
-void silc_fsm_continue(void *fsm)
-{
- SilcFSM f = fsm;
- if (f->next_later) {
- silc_schedule_task_del_by_all(f->schedule, 0, silc_fsm_run, f);
- f->next_later = FALSE;
- }
- if (!silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f, 0, 0))
- silc_fsm_run(f->schedule, silc_schedule_get_context(f->schedule), 0, 0, f);
-}
-
-/* Continue after callback or async operation immediately */
-
-void silc_fsm_continue_sync(void *fsm)
-{
- SilcFSM f = fsm;
- if (f->next_later) {
- silc_schedule_task_del_by_all(f->schedule, 0, silc_fsm_run, f);
- f->next_later = FALSE;
- }
- silc_fsm_run(f->schedule, silc_schedule_get_context(f->schedule), 0, 0, f);
-}
-
-/* Finish FSM */
-
-void silc_fsm_finish(void *fsm)
-{
- SilcFSM f = fsm;
-
- SILC_ASSERT(!f->finished);
-
- /* Machine must not have active threads */
- if (!f->thread && silc_atomic_get_int32(&f->u.m.threads))
- assert(silc_atomic_get_int32(&f->u.m.threads) == 0);
-
- f->started = FALSE;
- f->finished = TRUE;
-
- silc_schedule_task_del_by_all(f->schedule, 0, silc_fsm_run, f);
- f->next_later = FALSE;
-
- /* If we are thread and using real threads, the FSM thread will finish
- after the real thread has finished, in the main thread. */
- if (f->thread && f->real_thread) {
- /* Stop the real thread's scheduler to finish the thread */
- silc_schedule_stop(f->schedule);
- silc_schedule_wakeup(f->schedule);
- return;
- }
-
- /* Normal FSM operation */
- if (!f->synchronous)
- if (silc_schedule_task_add_timeout(f->schedule, silc_fsm_finish_fsm,
- f, 0, 0))
- return;
-
- silc_fsm_finish_fsm(f->schedule, silc_schedule_get_context(f->schedule),
- 0, 0, fsm);
-}
-
-/* Return associated scheduler */
-
-SilcSchedule silc_fsm_get_schedule(void *fsm)
-{
- SilcFSM f = fsm;
- return f->schedule;
-}
-
-/* Return thread's machine */
-
-SilcFSM silc_fsm_get_machine(SilcFSMThread thread)
-{
- SILC_ASSERT(thread->thread);
- return (SilcFSM)thread->u.t.fsm;
-}
-
-/* Returns TRUE if FSM is started */
-
-SilcBool silc_fsm_is_started(void *fsm)
-{
- SilcFSM f = fsm;
- return f->started;
-}
-
-/* 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)
-{
- SilcFSM f = fsm;
- return f->fsm_context;
-}
-
-/* Set state context */
-
-void silc_fsm_set_state_context(void *fsm, void *state_context)
-{
- SilcFSM f = fsm;
- 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 */
-
-SilcBool silc_fsm_thread_wait(void *fsm, void *thread)
-{
- SilcFSM t = thread;
-
- SILC_ASSERT(t->thread);
-
- t->u.t.event = silc_fsm_event_alloc(t->u.t.fsm);
- if (!t->u.t.event)
- return FALSE;
-
- SILC_LOG_DEBUG(("Waiting for thread %p to terminate", thread));
- silc_fsm_event_wait(t->u.t.event, fsm);
- return TRUE;
-}
-
-/* The machine */
-
-SILC_TASK_CALLBACK(silc_fsm_run)
-{
- SilcFSM fsm = context;
- SilcFSMStatus status;
-
- SILC_LOG_DEBUG(("Running %s %p", fsm->thread ? "thread" : "FSM", fsm));
-
- /* Run the states */
- do
- status = fsm->next_state(fsm, fsm->fsm_context, fsm->state_context);
- while (status == SILC_FSM_ST_CONTINUE);
-
- switch (status) {
- case SILC_FSM_ST_YIELD:
- /* Continue through scheduler */
- silc_fsm_continue(fsm);
- break;
-
- case SILC_FSM_ST_WAIT:
- /* The machine is in hold */
- SILC_LOG_DEBUG(("State wait %p", fsm));
- fsm->synchronous = FALSE;
- break;
-
- case SILC_FSM_ST_FINISH:
- /* Finish the state machine */
- SILC_LOG_DEBUG(("State finish %p", fsm));
- silc_fsm_finish(fsm);
- break;
-
- default:
- break;
- }
-}
-
-/* Finishes the FSM. This is always executed in the main thread, even
- for FSM threads that were run in real threads. */
-
-SILC_TASK_CALLBACK(silc_fsm_finish_fsm)
-{
- SilcFSM fsm = context;
-
- SILC_LOG_DEBUG(("%s %p, is finished", fsm->thread ? "Thread" : "FSM", fsm));
-
- fsm->next_state = NULL;
-
- if (fsm->thread) {
- /* This is thread, send signal */
- if (fsm->u.t.event) {
- silc_fsm_thread_termination_signal(fsm->u.t.event);
- silc_fsm_event_free(fsm->u.t.event);
- fsm->u.t.event = NULL;
- }
-
- /* Remove the thread from machine */
- silc_atomic_sub_int32(&fsm->u.t.fsm->u.m.threads, 1);
-
- /* Call the destructor callback only if the underlaying machine is
- still valid. */
- if (fsm->destructor && fsm->u.t.fsm->finished == FALSE)
- fsm->destructor(fsm, fsm->fsm_context, fsm->destructor_context);
-
- } else {
- if (fsm->u.m.lock) {
- silc_mutex_free(fsm->u.m.lock);
- fsm->u.m.lock = NULL;
- }
- silc_atomic_uninit32(&fsm->u.m.threads);
-
- /* Call the destructor callback. */
- if (fsm->destructor)
- fsm->destructor(fsm, fsm->fsm_context, fsm->destructor_context);
- }
-}
-
-/* Allocate FSM event */
-
-SilcFSMEvent silc_fsm_event_alloc(SilcFSM fsm)
-{
- SilcFSMEvent event;
-
- event = silc_calloc(1, sizeof(*event));
- if (silc_unlikely(!event))
- return NULL;
-
- silc_fsm_event_init(event, fsm);
- event->allocated = TRUE;
-
- return event;
-}
-
-/* Initializes FSM event */
-
-void silc_fsm_event_init(SilcFSMEvent event, SilcFSM fsm)
-{
- SILC_LOG_DEBUG(("Initializing event %p", event));
- SILC_ASSERT(!fsm->thread);
- memset(event, 0, sizeof(*event));
- event->fsm = fsm;
- event->refcnt = 0;
- silc_list_init(event->waiters, struct SilcFSMObject, next);
-}
-
-/* Free event */
-
-void silc_fsm_event_free(SilcFSMEvent event)
-{
- if (event->refcnt > 0)
- return;
- if (silc_list_count(event->waiters) > 0)
- return;
- silc_free(event);
-}
-
-/* Reference event */
-
-static void silc_fsm_event_ref(SilcFSMEvent event)
-{
- event->refcnt++;
-}
-
-/* Unreference event */
-
-static void silc_fsm_event_unref(SilcFSMEvent event)
-{
- event->refcnt--;
- if (event->refcnt == 0 && event->allocated)
- silc_fsm_event_free(event);
-}
-
-/* Wait until event is non-zero. */
-
-SilcUInt32 silc_fsm_event_wait(SilcFSMEvent event, void *fsm)
-{
- SilcMutex lock = event->fsm->u.m.lock;
-
- silc_mutex_lock(lock);
-
- if (!event->value) {
-#if defined(SILC_DEBUG)
- SilcFSM entry;
- silc_list_start(event->waiters);
- while ((entry = silc_list_get(event->waiters)))
- SILC_ASSERT(entry != fsm);
-#endif /* SILC_DEBUG */
-
- SILC_LOG_DEBUG(("Waiting for event %p", event));
-
- /* Add the FSM to waiter list */
- silc_list_add(event->waiters, fsm);
- silc_mutex_unlock(lock);
- return 0;
- }
-
- SILC_LOG_DEBUG(("Received event %p", event));
-
- /* Remove from waiting */
- silc_list_del(event->waiters, fsm);
-
- /* Decrease the counter only after all waiters have acquired the signal. */
- if (!silc_list_count(event->waiters))
- event->value--;
-
- silc_mutex_unlock(lock);
- return 1;
-}
-
-/* Wait util event is non-zero, or timeout occurs. */
-
-SilcUInt32 silc_fsm_event_timedwait(SilcFSMEvent event, void *fsm,
- SilcUInt32 seconds, SilcUInt32 useconds,
- SilcBool *ret_to)
-{
- SilcMutex lock = event->fsm->u.m.lock;
- SilcFSM f = fsm;
- SilcUInt32 value;
-
- silc_mutex_lock(lock);
-
- if (f->event_timedout) {
- SILC_LOG_DEBUG(("Event waiting timedout"));
- f->event_timedout = FALSE;
- if (ret_to)
- *ret_to = TRUE;
- silc_mutex_unlock(lock);
- return 1;
- }
-
- silc_mutex_unlock(lock);
-
- value = silc_fsm_event_wait(event, fsm);
- if (!value) {
- silc_schedule_task_add_timeout(f->schedule, silc_fsm_event_timedout,
- f, seconds, useconds);
- f->event = event;
- }
-
- if (ret_to)
- *ret_to = FALSE;
-
- return value;
-}
-
-/* Event timedout */
-
-SILC_TASK_CALLBACK(silc_fsm_event_timedout)
-{
- SilcFSM fsm = context;
- SilcMutex lock = fsm->event->fsm->u.m.lock;
-
- SILC_LOG_DEBUG(("Event %p timedout", fsm->event));
-
- /* Remove the waiter from the event waiters list */
- silc_mutex_lock(lock);
- silc_list_del(fsm->event->waiters, fsm);
-
- /* Continue */
- if (fsm->event) {
- silc_fsm_continue(fsm);
- fsm->event_timedout = TRUE;
- fsm->event = NULL;
- }
-
- silc_mutex_unlock(lock);
-}
-
-/* Signalled, event */
-
-SILC_TASK_CALLBACK(silc_fsm_signal)
-{
- SilcFSMEventSignal p = context;
- SilcMutex lock = p->event->fsm->u.m.lock;
- SilcFSM fsm;
-
- /* We have to check for couple of things before delivering the signal. */
-
- /* If the event value has went to zero while we've been waiting this
- callback, the event has been been signalled already. It can happen
- when using real threads because the FSM may not be in waiting state
- when the event is signalled. */
- silc_mutex_lock(lock);
- if (!p->event->value) {
- silc_mutex_unlock(lock);
- silc_fsm_event_unref(p->event);
- silc_free(p);
- return;
- }
-
- /* If the waiter is not waiting anymore, don't deliver the signal. It
- can happen if there were multiple signallers and the waiter went away
- after the first signal. */
- silc_list_start(p->event->waiters);
- while ((fsm = silc_list_get(p->event->waiters)))
- if (fsm == p->fsm)
- break;
- if (!fsm) {
- silc_mutex_unlock(lock);
- silc_fsm_event_unref(p->event);
- 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_event_unref(p->event);
- silc_free(p);
-}
-
-/* Signal event */
-
-void silc_fsm_event_signal(SilcFSMEvent event)
-{
- SilcFSM fsm;
- SilcFSMEventSignal p;
- SilcMutex lock = event->fsm->u.m.lock;
-
- SILC_LOG_DEBUG(("Signal event %p", event));
-
- silc_mutex_lock(lock);
-
- event->value++;
- silc_list_start(event->waiters);
- while ((fsm = silc_list_get(event->waiters))) {
- if (fsm->event) {
- silc_schedule_task_del_by_all(fsm->schedule, 0, silc_fsm_event_timedout,
- fsm);
- fsm->event = NULL;
- }
-
- p = silc_calloc(1, sizeof(*p));
- if (silc_unlikely(!p))
- continue;
- p->event = event;
- p->fsm = fsm;
- silc_fsm_event_ref(event);
-
- /* 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, 0);
- silc_schedule_wakeup(fsm->schedule);
- }
-
- silc_mutex_unlock(lock);
-}
-
-/* Post thread termination event. Special function used only to
- signal thread termination when SILC_FSM_THREAD_WAIT was used. */
-
-static void silc_fsm_thread_termination_signal(SilcFSMEvent event)
-{
- SilcFSM fsm;
- SilcMutex lock = event->fsm->u.m.lock;
-
- SILC_LOG_DEBUG(("Post thread terminate event %p", event));
-
- silc_mutex_lock(lock);
-
- silc_list_start(event->waiters);
- while ((fsm = silc_list_get(event->waiters))) {
- /* Signal on thread termination. Wake up destination scheduler in case
- caller is a real thread. */
- silc_list_del(event->waiters, fsm);
- silc_fsm_continue(fsm);
- silc_schedule_wakeup(fsm->schedule);
- }
-
- silc_mutex_unlock(lock);
-}
-
-/* Real thread */
-
-void *silc_fsm_thread(void *context)
-{
- SilcFSM fsm = context;
- SilcSchedule old = fsm->schedule;
-
- SILC_LOG_DEBUG(("Starting FSM thread in real thread"));
-
- /* We allocate new SilcSchedule for the FSM, as the old SilcSchedule
- cannot be used in this thread. Application may still use it if it
- wants but we use our own. */
- fsm->schedule = silc_schedule_init(0, old);
- if (silc_unlikely(!fsm->schedule))
- return NULL;
-
- /* Start the FSM thread */
- if (silc_unlikely(!silc_schedule_task_add_timeout(fsm->schedule,
- silc_fsm_run, fsm, 0, 0)))
- return NULL;
-
- /* Run the scheduler */
- silc_schedule(fsm->schedule);
-
- /* Free resources */
- silc_schedule_uninit(fsm->schedule);
-
- fsm->schedule = old;
-
- /* Finish the FSM thread in the main thread */
- SILC_ASSERT(fsm->finished);
- silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_finish_fsm,
- fsm, 0, 0);
- silc_schedule_wakeup(fsm->schedule);
-
- return NULL;
-}
+++ /dev/null
-/*
-
- silcfsm.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005, 2006, 2007 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* silcutil/SILC Finite State Machine
- *
- * DESCRIPTION
- *
- * SILC FSM Interface implements a finite state machine. The FSM can be
- * used to implement all kinds of machines and protocols. The FSM supports
- * also threads and can be synchronized by using mutex locks. The FSM
- * also supports real system threads. It is possible to create new FSM
- * thread and then execute in real system thread, if platform supports
- * threads.
- *
- * The FSM provides also asynchronous events that can be used to wait for
- * some events or states to occur. The FSM events may be used as condition
- * variables and signallers. The FSM events can safely be used in FSM
- * threads that are executed in real system threads.
- *
- * To synchronize machines that use FSM threads that are executed in real
- * system threads the SILC Mutex API (silcmutex.h) may be used. Normal
- * multi-threaded coding conventions apply when programming with real FSM
- * threads. If the FSM threads are not real system threads, synchronization
- * is not required.
- *
- ***/
-
-#ifndef SILCFSM_H
-#define SILCFSM_H
-
-/****s* silcutil/SilcFSMAPI/SilcFSM
- *
- * NAME
- *
- * typedef struct SilcFSMObject *SilcFSM;
- *
- * DESCRIPTION
- *
- * The actual FSM context and is allocated with silc_fsm_alloc and
- * given as argument to all silc_fsm_* functions. It is freed by
- * silc_fsm_free function. It is also possible to use pre-allocated
- * FSM context by using SilcFSMStruct instead of SilcFSM.
- *
- ***/
-typedef struct SilcFSMObject *SilcFSM;
-
-/****s* silcutil/SilcFSMAPI/SilcFSMStruct
- *
- * NAME
- *
- * typedef struct SilcFSMObject SilcFSMStruct;
- *
- * DESCRIPTION
- *
- * The actual FSM context and can be used as pre-allocated FSM context,
- * instead of SilcFSM context. This context is initialized with the
- * silc_fsm_init function. It need not be uninitialized.
- *
- ***/
-typedef struct SilcFSMObject SilcFSMStruct;
-
-/****s* silcutil/SilcFSMAPI/SilcFSMThread
- *
- * NAME
- *
- * typedef struct SilcFSMObject *SilcFSMThread;
- *
- * DESCRIPTION
- *
- * FSM thread context. The SILC FSM supports threads, virtual machine
- * threads (inside FSM) and actual real system threads if platorm
- * supports them. In a complex machine certain complex operations may
- * be desired to execute in a thread. The SilcFSMThread is allocated
- * by silc_fsm_thread_alloc and feed by silc_fsm_free. It is also
- * possible to use pre-allocated thread by using SilcFSMThreadStruct
- * instead of SilcFSMThread.
- *
- ***/
-typedef struct SilcFSMObject *SilcFSMThread;
-
-/****s* silcutil/SilcFSMAPI/SilcFSMThreadStruct
- *
- * NAME
- *
- * typedef struct SilcFSMObject SilcFSMThreadStruct;
- *
- * DESCRIPTION
- *
- * FSM thread context and can be used as a pre-allocated FSM thread context,
- * instead of SilcFSMThread context. This context is initialized with the
- * silc_fsm_thread_init function. It need not be uninitialized.
- *
- ***/
-typedef struct SilcFSMObject SilcFSMThreadStruct;
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_CONTINUE
- *
- * NAME
- *
- * #define SILC_FSM_CONTINUE ...
- *
- * DESCRIPTION
- *
- * Moves to next state synchronously. This type is used is returned
- * from state functions to immediately move to next state.
- *
- * EXAMPLE
- *
- * SILC_FSM_STATE(silc_foo_state)
- * {
- * ...
- *
- * // Move to next state now
- * silc_fsm_next(fsm, silc_foo_next_state);
- * return SILC_FSM_CONTINUE;
- * }
- *
- ***/
-#if defined(SILC_DEBUG)
-#define SILC_FSM_CONTINUE \
- fsm->next_state(fsm, fsm->fsm_context, fsm->state_context);
-#else
-#define SILC_FSM_CONTINUE SILC_FSM_ST_CONTINUE;
-#endif /* SILC_DEBUG */
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_YIELD
- *
- * NAME
- *
- * #define SILC_FSM_YIELD ...
- *
- * DESCRIPTION
- *
- * Moves to next state through the machine scheduler. Other threads
- * running in the machine will get running time with SILC_FSM_YIELD.
- * When using real threads, using SILC_FSM_YIELD is usually unnecessary.
- * This type is returned in the state function.
- *
- ***/
-#define SILC_FSM_YIELD SILC_FSM_ST_YIELD;
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_WAIT
- *
- * NAME
- *
- * #define SILC_FSM_WAIT ...
- *
- * DESCRIPTION
- *
- * Suspends the machine or thread until it is awaken. This is used
- * when asynchronous call is made or timer is set, or something else
- * that requires waiting. This type is returned in the state function.
- *
- ***/
-#define SILC_FSM_WAIT SILC_FSM_ST_WAIT
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_FINISH
- *
- * NAME
- *
- * #define SILC_FSM_FINISH ...
- *
- * DESCRIPTION
- *
- * Finishes the machine or thread and calls its destructor, if defined.
- * If the machine is finished when it has running threads the machine
- * will fatally fail. User must always finish the threads before
- * finishing the machine. This type is returned in the state function.
- *
- ***/
-#define SILC_FSM_FINISH SILC_FSM_ST_FINISH
-
-/****f* silcutil/SilcFSMAPI/SilcFSMDestructor
- *
- * SYNOPSIS
- *
- * typedef void (*SilcFSMDestructor)(SilcFSM fsm, void *fsm_context,
- * void *destructor_context);
- *
- * DESCRIPTION
- *
- * The destructor callback that was set in silc_fsm_alloc or in
- * silc_fsm_init function. It will be called when a state function
- * returns SILC_FSM_FINISH. This function will be called through
- * the scheduler; it will not be called immediately after the state
- * function returns SILC_FSM_FINISH, but will be called later. The
- * `fsm' can be freed in this function.
- *
- ***/
-typedef void (*SilcFSMDestructor)(SilcFSM fsm, void *fsm_context,
- void *destructor_context);
-
-/****f* silcutil/SilcFSMAPI/SilcFSMThreadDestructor
- *
- * SYNOPSIS
- *
- * typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
- * void *thread_context,
- * void *destructor_context);
- *
- * DESCRIPTION
- *
- * The destructor callback that was set in silc_fsm_thread_alloc or in
- * silc_fsm_thread_init function. It will be called when a state function
- * returns SILC_FSM_FINISH. This function will be called through the
- * scheduler; it will not be called immediately after the state function
- * returns SILC_FSM_FINISH, but will be called later. The `thread' can
- * be freed in this function.
- *
- * NOTES
- *
- * Even if the `thread' was executed in real system thread, this callback
- * is always received in the main machine thread, not in the created
- * thread.
- *
- ***/
-typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
- void *thread_context,
- void *destructor_context);
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_STATE
- *
- * NAME
- *
- * #define SILC_FSM_STATE(name)
- *
- * DESCRIPTION
- *
- * This macro is used to declare an 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) \
-int name(struct SilcFSMObject *fsm, void *fsm_context, void *state_context)
-/***/
-
-/* State function callback */
-typedef int (*SilcFSMStateCallback)(struct SilcFSMObject *fsm,
- void *fsm_context,
- void *state_context);
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_CALL
- *
- * NAME
- *
- * SILC_FSM_CALL(function)
- *
- * DESCRIPTION
- *
- * Macro used to call asynchronous calls from state function. If the
- * call is not really asynchronous then this will cause the machine to
- * directly proceed to next state. If the call is truly asynchronous
- * then this will set the machine to wait state. The silc_fsm_next
- * must be called before this macro, so that the next state is set.
- *
- * NOTES
- *
- * The state function returns in this macro.
- *
- * EXAMPLE
- *
- * // Simple example
- * silc_fsm_next(fsm, some_next_state);
- * SILC_FSM_CALL(silc_some_async_call(server, some_callback, context));
- *
- * // More complex example
- * silc_fsm_next(fsm, some_next_state);
- * SILC_FSM_CALL((some_context->operation =
- * silc_some_async_call(server, some_callback, context)));
- *
- ***/
-#define SILC_FSM_CALL(function) \
-do { \
- assert(!silc_fsm_set_call(fsm, TRUE)); \
- function; \
- if (!silc_fsm_set_call(fsm, FALSE)) \
- return SILC_FSM_CONTINUE; \
- return SILC_FSM_WAIT; \
-} while(0)
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE
- *
- * NAME
- *
- * SILC_FSM_CALL_CONTINUE(fsm)
- *
- * DESCRIPTION
- *
- * Macro used to proceed after asynchornous call. This is called in the
- * callback of the asynchronous call to continue in the state machine.
- *
- * EXAMPLE
- *
- * void some_callback(void *context) {
- * SilcFSM fsm = context;
- * ...
- * // Continue to the next state
- * SILC_FSM_CALL_CONTINUE(fsm);
- * }
- *
- ***/
-#define SILC_FSM_CALL_CONTINUE(fsm) \
-do { \
- if (!silc_fsm_set_call(fsm, FALSE)) \
- silc_fsm_continue(fsm); \
-} while(0)
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE_SYNC
- *
- * NAME
- *
- * SILC_FSM_CALL_CONTINUE_SYNC(fsm)
- *
- * DESCRIPTION
- *
- * Macro used to proceed after asynchornous call. This is called in the
- * callback of the asynchronous call to continue in the state machine.
- * This continues to the next state synchronously, not through the
- * scheduler.
- *
- * EXAMPLE
- *
- * void some_callback(void *context) {
- * SilcFSM fsm = context;
- * ...
- * // Continue to the next state immediately
- * SILC_FSM_CALL_CONTINUE_SYNC(fsm);
- * }
- *
- ***/
-#define SILC_FSM_CALL_CONTINUE_SYNC(fsm) \
-do { \
- if (!silc_fsm_set_call(fsm, FALSE)) \
- silc_fsm_continue_sync(fsm); \
-} while(0)
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_THREAD_WAIT
- *
- * NAME
- *
- * SILC_FSM_THREAD_WAIT(thread)
- *
- * DESCRIPTION
- *
- * Macro used to wait for the `thread' to terminate. The machine or
- * thread will be suspended while it is waiting for the thread to
- * terminate.
- *
- * NOTES
- *
- * The state function returns in this macro.
- *
- * 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
- * FSM events to signal from the thread before SILC_FSM_FINISH is returned
- * 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. In this case using this
- * macro is strongly recommended.
- *
- ***/
-#define SILC_FSM_THREAD_WAIT(thread) \
-do { \
- silc_fsm_thread_wait(fsm, thread); \
- return SILC_FSM_WAIT; \
-} while(0)
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_alloc
- *
- * SYNOPSIS
- *
- * SilcFSM silc_fsm_alloc(void *fsm_context,
- * SilcFSMDestructor destructor,
- * void *destructor_context,
- * SilcSchedule schedule);
- *
- * DESCRIPTION
- *
- * Allocates SILC Finite State Machine context. The `destructor' with
- * `destructor_context' will be called when the machines finishes. The
- * caller must free the returned context with silc_fsm_free. The
- * `fsm_context' is delivered to every FSM state function. The `schedule'
- * is the caller's scheduler and the FSM will be run in the scheduler.
- *
- * EXAMPLE
- *
- * SilcAsyncOperation silc_async_call(Callback callback, void *cb_context)
- * {
- * SilcAsyncOperation op;
- * SilcFSM fsm;
- * ...
- *
- * // Allocate async operation so that caller can control us, like abort
- * op = silc_async_alloc(silc_async_call_abort, NULL, ourcontext);
- *
- * // Start FSM
- * fsm = silc_fsm_alloc(ourcontext, fsm_destructor, ourcontext,
- * schedule);
- * silc_fsm_start(fsm, first_state);
- * ...
- *
- * // Return async operation for upper layer
- * return op;
- * }
- *
- ***/
-SilcFSM silc_fsm_alloc(void *fsm_context,
- SilcFSMDestructor destructor,
- void *destructor_context,
- SilcSchedule schedule);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_init
- *
- * SYNOPSIS
- *
- * SilcBool silc_fsm_init(SilcFSM fsm,
- * void *fsm_context,
- * SilcFSMDestructor destructor,
- * void *destructor_context,
- * SilcSchedule schedule);
- *
- * DESCRIPTION
- *
- * Initializes a pre-allocated SilcFSM context. This call is equivalent
- * to silc_fsm_alloc except that this takes the pre-allocated context
- * as argument. The silc_fsm_free must not be called if this was called.
- * Returns TRUE if the initialization is Ok or FALSE if error occurred.
- * This function does not allocate any memory. The `schedule' is the
- * caller's scheduler and the FSM will be run in the scheduler.
- *
- * EXAMPLE
- *
- * SilcFSMStruct fsm;
- *
- * silc_fsm_init(&fsm, application, fsm_destructor, application, schedule);
- * silc_fsm_start(&fsm, first_state);
- *
- ***/
-SilcBool silc_fsm_init(SilcFSM fsm,
- void *fsm_context,
- SilcFSMDestructor destructor,
- void *destructor_context,
- SilcSchedule schedule);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_thread_alloc
- *
- * SYNOPSIS
- *
- * SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
- * void *thread_context,
- * SilcFSMThreadDestructor destructor,
- * void *destructor_context,
- * SilcBool real_thread);
- *
- * DESCRIPTION
- *
- * Allocates FSM thread context. The thread will be executed in the
- * FSM machine indicated by `fsm'. The caller must free the returned
- * thread context with silc_fsm_free. If the 'real_thread' is TRUE
- * then the thread will actually be executed in real thread, if platform
- * supports them. The `thread_context' is delivered to every state
- * function in the thread.
- *
- * NOTES
- *
- * If the system does not support threads, then this function will revert
- * back to normal FSM threads.
- *
- * If the `real_thread' is TRUE then FSM will allocate new SilcSchedule
- * for the FSM thread. If you need scheduler in the real thread it is
- * strongly recommended that you use the SilcSchedule that is allocated
- * for the thread. You can retrieve the SilcSchedule from the thread
- * using silc_fsm_get_schedule function. Note that, the allocated
- * SilcSchedule will become invalid after the thread finishes.
- *
- * If `real_thread' is FALSE the silc_fsm_get_schedule will return
- * the SilcSchedule that was originally given to silc_fsm_alloc or
- * silc_fsm_init.
- *
- * EXAMPLE
- *
- * SILC_FSM_STATE(silc_foo_state)
- * {
- * SilcFSMThread thread;
- * ...
- *
- * // Execute the route lookup in thread
- * thread = silc_fsm_thread_alloc(fsm, fsm_context, NULL, NULL, FALSE);
- * silc_fsm_start(thread, silc_route_lookup_start);
- *
- * // Wait here for the thread to terminate. Set the state where to go
- * // after the thread has terminated.
- * silc_fsm_next(fsm, silc_foo_route_lookup_finished);
- * SILC_FSM_THREAD_WAIT(thread);
- * }
- *
- ***/
-SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
- void *thread_context,
- SilcFSMThreadDestructor destructor,
- void *destructor_context,
- SilcBool real_thread);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_thread_init
- *
- * SYNOPSIS
- *
- * void silc_fsm_thread_init(SilcFSMThread thread,
- * SilcFSM fsm,
- * void *thread_context,
- * SilcFSMThreadDestructor destructor,
- * void *destructor_context,
- * SilcBool real_thread);
- *
- * DESCRIPTION
- *
- * Initializes a pre-allocated SilcFSMThread context. This call is
- * equivalent to silc_fsm_thread_alloc except that this takes the
- * pre-allocated context as argument. The silc_fsm_free must not be
- * called if this was called. If the `real_thread' is TRUE then the
- * thread will actually be executed in real thread, if platform supports
- * them.
- *
- * NOTES
- *
- * See the notes from the silc_fsm_thread_alloc.
- *
- * EXAMPLE
- *
- * SilcFSMThreadStruct thread;
- *
- * silc_fsm_thread_init(&thread, fsm, application, NULL, NULL, FALSE);
- * silc_fsm_start(&thread, first_state);
- *
- ***/
-void silc_fsm_thread_init(SilcFSMThread thread,
- SilcFSM fsm,
- void *thread_context,
- SilcFSMThreadDestructor destructor,
- void *destructor_context,
- SilcBool real_thread);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_free
- *
- * SYNOPSIS
- *
- * void silc_fsm_free(void *fsm);
- *
- * DESCRIPTION
- *
- * Free the SILC FSM context that was allocated with silc_fsm_alloc,
- * or free the SILC FSM thread context that was allocated with
- * silc_fsm_thread_alloc. This function is used with both SilcFSM
- * and SilcFSMThread contexts.
- *
- * NOTES
- *
- * When freeing FSM, it must not have any active threads.
- *
- ***/
-void silc_fsm_free(void *fsm);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_start
- *
- * SYNOPSIS
- *
- * void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state);
- *
- * DESCRIPTION
- *
- * This function must be called after the SILC FSM context was created.
- * This actually starts the state machine. Note that, the machine is
- * started later after this function returns. The `start_state' is the
- * state where the machine or thread is started. This function is used
- * with both SilcFSM and SilcFSMThread contexts.
- *
- * EXAMPLE
- *
- * SilcFSM fsm;
- *
- * fsm = silc_fsm_alloc(context, destructor, context, schedule);
- * silc_fsm_start(fsm, first_state);
- *
- ***/
-void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_start_sync
- *
- * SYNOPSIS
- *
- * void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state);
- *
- * DESCRIPTION
- *
- * This function is same as silc_fsm_start, except that the FSM will
- * be started immediately inside this function. After this function
- * returns the `start_state' has already been executed. If the machine
- * is completely synchronous (no waiting used in the machine) then
- * the machine will have finished once this function returns. Also
- * note that if the machine is completely synchronous the destructor
- * will also be called from inside this function. This function is used
- * with both SilcFSM and SilcFSMThread contexts.
- *
- ***/
-void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_next
- *
- * SYNOPSIS
- *
- * void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
- *
- * DESCRIPTION
- *
- * Set the next state to be executed. If the state function that
- * call this function returns SILC_FSM_CONTINUE, the `next_state'
- * will be executed immediately. If it returns SILC_FSM_YIELD it
- * yields the thread and the `next_state' will be run after other
- * threads have run first. This function must always be used to set
- * the next state in the machine or thread. This function is used
- * with both SilcFSM and SilcFSMThread contexts.
- *
- * EXAMPLE
- *
- * // Move to next state
- * silc_fsm_next(fsm, next_state);
- * return SILC_FSM_CONTINUE;
- *
- ***/
-void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_next_later
- *
- * SYNOPSIS
- *
- * void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
- * SilcUInt32 seconds, SilcUInt32 useconds);
- *
- * DESCRIPTION
- *
- * Set the next state to be executed later, at the specified time.
- * The SILC_FSM_WAIT must be returned in the state function if this
- * function is called. If any other state is returned machine operation
- * is undefined. The machine or thread will move to `next_state' after
- * 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.
- *
- * If silc_fsm_continue or silc_fsm_continue_sync is called while the
- * machine or thread is in SILC_FSM_WAIT state the timeout is automatically
- * canceled and the state moves to the next state.
- *
- * EXAMPLE
- *
- * // Move to next state after 10 seconds
- * silc_fsm_next_later(fsm, next_state, 10, 0);
- * return SILC_FSM_WAIT;
- *
- ***/
-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_finish
- *
- * SYNOPSIS
- *
- * void silc_fsm_finish(void *fsm);
- *
- * DESCRIPTION
- *
- * Finishes the `fsm'. This function may be used in case the FSM
- * needs to be finished outside FSM states. Usually FSM is finished
- * by returning SILC_FSM_FINISH from the state, but if this is not
- * possible this function may be called. This function is used with
- * both SilcFSM and SilcFSMThread contexts.
- *
- * If the `fsm' is a machine and it has running threads, the machine
- * will fatally fail. The caller must first finish the threads and
- * then the machine.
- *
- ***/
-void silc_fsm_finish(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
- *
- * void *silc_fsm_get_context(void *fsm);
- *
- * DESCRIPTION
- *
- * Returns the context associated with the `fsm'. It is the context that
- * was given to silc_fsm_alloc, silc_fsm_init, silc_fsm_thread_alloc or
- * silc_fsm_thread_init. This function is used with both SilcFSM and
- * SilcFSMThread contexts.
- *
- ***/
-void *silc_fsm_get_context(void *fsm);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_set_state_context
- *
- * SYNOPSIS
- *
- * void silc_fsm_set_state_context(void *fsm, void *state_context);
- *
- * DESCRIPTION
- *
- * 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_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
- *
- * SYNOPSIS
- *
- * SilcSchedule silc_fsm_get_schedule(void *fsm);
- *
- * DESCRIPTION
- *
- * Returns the SilcSchedule that has been associated with the `fsm'.
- * If caller needs scheduler it may retrieve it with this function. This
- * function is used with both SilcFSM and SilcFSMThread contexts.
- *
- * If the `fsm' is thread and real system threads are being used, and this
- * is called from the thread, it will return the SilcSchedule that was
- * allocated by the FSM for the thread. It is strongly recommended to
- * use this SilcSchedule if you are using real threads, and you need
- * scheduler in the thread. Note that, once the thread finishes the
- * returned SilcSchedule becomes invalid.
- *
- * 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);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_is_started
- *
- * SYNOPSIS
- *
- * SilcBool silc_fsm_is_started(void *fsm);
- *
- * DESCRIPTION
- *
- * Returns TRUE if the machine or thread `fsm' has been started and has
- * not been finished yet. This function is used with both SilcFSM and
- * SilcFSMThread contexts.
- *
- ***/
-SilcBool silc_fsm_is_started(void *fsm);
-
-/* FSM Events */
-
-/****s* silcutil/SilcFSMAPI/SilcFSMEvent
- *
- * NAME
- *
- * typedef struct SilcFSMEventObject *SilcFSMEvent;
- *
- * DESCRIPTION
- *
- * The FSM event context allocated with silc_fsm_event_alloc. The
- * caller must free it with silc_fsm_event_free. It is also possible
- * to use pre-allocated SilcFSMEventStruct instead of SilcFSMEvent context.
- *
- ***/
-typedef struct SilcFSMEventObject *SilcFSMEvent;
-
-/****s* silcutil/SilcFSMAPI/SilcFSMEventStruct
- *
- * NAME
- *
- * typedef struct SilcFSMEventObject SilcFSMEventStruct;
- *
- * DESCRIPTION
- *
- * The FSM event context that can be used as pre-allocated context.
- * It is initialized with silc_fsm_event_init. It need not be
- * uninitialized.
- *
- ***/
-typedef struct SilcFSMEventObject SilcFSMEventStruct;
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_event_alloc
- *
- * SYNOPSIS
- *
- * SilcFSMEvent silc_fsm_event_alloc(SilcFSM fsm);
- *
- * DESCRIPTION
- *
- * Allocates asynchronous FSM event. FSM events are asynchronous events
- * that can be waited and signalled. They can be used as condition
- * variables and signallers. They can be used for example to wait that
- * some event happens, some thread moves to a specific state or similar.
- * The FSM Events may also be used in FSM threads that are executed in
- * real system threads. It is safe to wait and signal the event from
- * threads.
- *
- * Use the macros SILC_FSM_EVENT_WAIT and SILC_FSM_EVENT_TIMEDWAIT to wait
- * for the event. Use the SILC_FSM_EVENT_SIGNAL macro to signal all the
- * waiters.
- *
- ***/
-SilcFSMEvent silc_fsm_event_alloc(SilcFSM fsm);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_event_init
- *
- * SYNOPSIS
- *
- * void silc_fsm_event_init(SilcFSMEvent event, SilcFSM fsm);
- *
- * DESCRIPTION
- *
- * Initializes a pre-allocates FSM event context. This call is
- * equivalent to silc_fsm_event_alloc except this use the pre-allocated
- * context. This fuction does not allocate any memory.
- *
- ***/
-void silc_fsm_event_init(SilcFSMEvent event, SilcFSM fsm);
-
-/****f* silcutil/SilcFSMAPI/silc_fsm_event_free
- *
- * SYNOPSIS
- *
- * void silc_fsm_event_free(SilcFSMEvent event);
- *
- * DESCRIPTION
- *
- * Free the event allocated by silc_fsm_event_alloc function.
- *
- ***/
-void silc_fsm_event_free(SilcFSMEvent event);
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_EVENT_WAIT
- *
- * NAME
- *
- * SILC_FSM_EVENT_WAIT(event)
- *
- * DESCRIPTION
- *
- * Macro used to wait for the `event' to be signalled. The machine
- * or thread will be suspended while it is waiting for the event.
- * This macro can only be used in FSM state functions. When the
- * event is signalled the FSM will re-enter the current state (or
- * state that was set with silc_fsm_next before waiting).
- *
- * EXAMPLE
- *
- * // Signalling example
- * ctx->async_event = silc_fsm_event_alloc(fsm);
- * ...
- *
- * SILC_FSM_STATE(silc_foo_state)
- * {
- * ...
- *
- * // Wait here for async call to complete
- * SILC_FSM_EVENT_WAIT(ctx->async_event);
- *
- * // Async call completed
- * if (ctx->async_success == FALSE)
- * fatal(error);
- * ...
- * }
- *
- ***/
-#define SILC_FSM_EVENT_WAIT(event) \
-do { \
- if (silc_fsm_event_wait(event, fsm) == 0) \
- return SILC_FSM_WAIT; \
-} while(0)
-
-/****d* silcutil/SilcFSMAPI/SILC_FSM_EVENT_TIMEDWAIT
- *
- * NAME
- *
- * SILC_FSM_EVENT_TIMEDWAIT(event, seconds, useconds, timedout)
- *
- * DESCRIPTION
- *
- * Macro used to wait for the `event' to be signalled, or until
- * the timeout specified by `seconds' and `useconds' has elapsed. If
- * the timeout occurs before the event is signalled, the machine
- * 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 event is signalled or timedout the FSM will re-enter
- * the current state (or state that was set with silc_fsm_next before
- * waiting).
- *
- * EXAMPLE
- *
- * SILC_FSM_STATE(silc_foo_state)
- * {
- * SilcBool timedout;
- * ...
- *
- * // Wait here for async call to complete, or 10 seconds for timeout
- * SILC_FSM_EVENT_TIMEDWAIT(ctx->async_event, 10, 0, &timedout);
- *
- * // See if timeout occurred
- * if (timedout == TRUE)
- * fatal(error);
- *
- * // Async call completed
- * if (ctx->async_success == FALSE)
- * fatal(error);
- * ...
- * }
- *
- ***/
-#define SILC_FSM_EVENT_TIMEDWAIT(event, seconds, useconds, ret_to) \
-do { \
- if (silc_fsm_event_timedwait(event, fsm, seconds, useconds, ret_to) == 0) \
- return SILC_FSM_WAIT; \
-} while(0)
-
-/****f* silcutil/SilcFSMAPI/SILC_FSM_EVENT_SIGNAL
- *
- * SYNOPSIS
- *
- * SILC_FSM_EVENT_SIGNAL(event)
- *
- * DESCRIPTION
- *
- * Signals the `event' and awakens everybody that are waiting for this
- * event. This macro never blocks. It can be safely called at any place
- * in state function and in asynchronous callbacks or other functions.
- *
- * EXAMPLE
- *
- * SILC_FSM_STATE(silc_foo_async_completion)
- * {
- * ...
- *
- * // Notify all waiters
- * ctx->async_success = TRUE;
- * SILC_FSM_EVENT_SIGNAL(ctx->async_event);
- * ...
- * }
- *
- ***/
-#define SILC_FSM_EVENT_SIGNAL(event) \
-do { \
- silc_fsm_event_signal(event); \
-} while(0)
-
-#include "silcfsm_i.h"
-
-#endif /* SILCFSM_H */
+++ /dev/null
-/*
-
- silcfsm_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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 SILCFSM_I_H
-#define SILCFSM_I_H
-
-#ifndef SILCFSM_H
-#error "Do not include this header directly"
-#endif
-
-/* FSM state status */
-typedef enum {
- SILC_FSM_ST_CONTINUE, /* Continue immediately to next state */
- SILC_FSM_ST_YIELD, /* Continue to next state through scheduler */
- SILC_FSM_ST_WAIT, /* Wait for some async call or timeout */
- SILC_FSM_ST_FINISH, /* Finish state machine and call destructor
- through scheduler */
-} SilcFSMStatus;
-
-/* Event structure, holds list of FSM machines that are waiting for this
- event. The SilcFSM has *next; pointer that is used with SilcList.
- Internally events act as semaphore counters. */
-struct SilcFSMEventObject {
- SilcFSM fsm; /* Machine */
- SilcList waiters; /* List of SilcFSM pointers */
- unsigned int value : 21; /* Current event semaphore value */
- unsigned int refcnt : 10; /* Reference counter */
- unsigned int allocated : 1; /* Set if allocated */
-};
-
-/* FSM and FSM thread context */
-struct SilcFSMObject {
- struct SilcFSMObject *next;
- void *fsm_context; /* Caller's context */
- SilcSchedule schedule; /* Scheduler */
- SilcFSMEvent event; /* Valid if waiting event timeout */
- SilcFSMStateCallback next_state; /* Next state in machine */
- void *state_context; /* Extra state specific context */
- SilcFSMDestructor destructor; /* Destructor */
- void *destructor_context;
- union {
- /* Machine */
- struct {
- SilcAtomic32 threads; /* Number of threads */
- SilcMutex lock; /* Lock, valid if using real threads */
- } m;
-
- /* Thread */
- struct {
- struct SilcFSMObject *fsm; /* Machine */
- SilcFSMEvent event; /* Event for waiting termination */
- } t;
- } u;
- unsigned int thread : 1; /* Set if this is thread */
- unsigned int real_thread : 1; /* Set if to use real threads */
- unsigned int async_call : 1; /* Set if called real async call */
- unsigned int finished : 1; /* Set if SILC_FSM_FINISH returned */
- unsigned int event_timedout : 1; /* Set if waiting event timedout */
- unsigned int synchronous : 1; /* Set if silc_fsm_start_sync called */
- unsigned int next_later : 1; /* Set if silc_fsm_next_later called */
- unsigned int started : 1; /* Set when started and not finished */
-};
-
-/* Event signal context */
-typedef struct {
- SilcFSMEvent event; /* Event */
- SilcFSM fsm; /* Signalled FSM */
-} *SilcFSMEventSignal;
-
-/* Used internally by the SILC_FSM_CALL macros to detect whether async
- call is really async or not. */
-static inline
-SilcBool silc_fsm_set_call(struct SilcFSMObject *fsm, SilcBool async_call)
-{
- SilcBool old = fsm->async_call;
- fsm->async_call = async_call;
- return old;
-}
-
-/* Wait for thread to terminate */
-SilcBool silc_fsm_thread_wait(void *fsm, void *thread);
-
-/* Events */
-SilcUInt32 silc_fsm_event_wait(SilcFSMEvent event, void *fsm);
-SilcUInt32 silc_fsm_event_timedwait(SilcFSMEvent event, void *fsm,
- SilcUInt32 seconds, SilcUInt32 useconds,
- SilcBool *ret_to);
-void silc_fsm_event_signal(SilcFSMEvent event);
-
-#endif /* SILCFSM_I_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2006 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
hash table. */
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silchashtable.h"
/* Define to 1 if you want hash table debug enabled */
void *foreach_user_context)
{
SilcHashTableEntry e, tmp;
- SilcBool auto_rehash, found = FALSE;
+ bool auto_rehash, found = FALSE;
SilcUInt32 i = SILC_HASH_TABLE_HASH(hash, hash_user_context);
SILC_HT_DEBUG(("index %d key %p", i, key));
/* Internal routine to add new key to the hash table */
-static inline SilcBool
+static inline bool
silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
SilcHashFunction hash,
void *hash_user_context)
/* Internal routine to replace old key with new one (if it exists) */
-static inline SilcBool
+static inline bool
silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
SilcHashFunction hash,
void *hash_user_context)
void *compare_user_context,
SilcHashDestructor destructor,
void *destructor_user_context,
- SilcBool auto_rehash)
+ bool auto_rehash)
{
SilcHashTable ht;
SilcUInt32 size_index = SILC_HASH_TABLE_SIZE;
hash table. This function quarantees that the entry is always added
to the hash table reliably (it is collision resistant). */
-SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context)
+void silc_hash_table_add(SilcHashTable ht, void *key, void *context)
{
- return silc_hash_table_add_internal(ht, key, context, ht->hash,
- ht->hash_user_context);
+ 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. */
-SilcBool silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
- SilcHashFunction hash,
- void *hash_user_context)
+void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
+ SilcHashFunction hash, void *hash_user_context)
{
- return silc_hash_table_add_internal(ht, key, context,
- hash, hash_user_context);
+ 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
the `context. The destructor function will be called for the
replaced key and context. */
-SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
+void silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
{
- return silc_hash_table_replace_internal(ht, key, context, ht->hash,
- ht->hash_user_context);
+ silc_hash_table_replace_internal(ht, key, context, ht->hash,
+ ht->hash_user_context);
}
/* Same as above but with specific hash function. */
-SilcBool silc_hash_table_replace_ext(SilcHashTable ht, void *key,
- void *context,
- SilcHashFunction hash,
- void *hash_user_context)
+void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
+ SilcHashFunction hash,
+ void *hash_user_context)
{
- return silc_hash_table_replace_internal(ht, key, context,
- hash, hash_user_context);
+ 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
call the destructor funtion for the found entry. Return TRUE if the
entry was removed successfully and FALSE otherwise. */
-SilcBool silc_hash_table_del(SilcHashTable ht, void *key)
+bool silc_hash_table_del(SilcHashTable ht, void *key)
{
SilcHashTableEntry *entry, prev, e;
/* Same as above but with specific hash and compare functions. */
-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)
+bool 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)
{
SilcHashTableEntry *entry, prev, e;
have duplicate keys. In that case the `context' may be used to check
whether the correct entry is being deleted. */
-SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
- void *context)
+bool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
+ void *context)
{
SilcHashTableEntry *entry, prev, e;
/* Same as above but with specific hash and compare functions. */
-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)
+bool 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)
{
SilcHashTableEntry *entry, prev, e;
respectively. If the `ret_key and `ret_context' are NULL then this
maybe used only to check whether given key exists in the table. */
-SilcBool silc_hash_table_find(SilcHashTable ht, void *key,
- void **ret_key, void **ret_context)
+bool silc_hash_table_find(SilcHashTable ht, void *key,
+ void **ret_key, void **ret_context)
{
return silc_hash_table_find_ext(ht, key, ret_key, ret_context,
NULL, NULL, NULL, NULL);
/* Same as above but with specified hash and comparison functions. */
-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)
+bool 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)
{
SilcHashTableEntry *entry;
/* Same as silc_hash_table_find but finds with specific context. */
-SilcBool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
- void *context, void **ret_key)
+bool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
+ void *context, void **ret_key)
{
return silc_hash_table_find_by_context_ext(ht, key, context, ret_key,
NULL, NULL, NULL, NULL);
/* Same as above but with specified hash and comparison functions. */
-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)
+bool 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)
{
SilcHashTableEntry *entry;
{
SilcHashTableEntry e, tmp;
int i;
- SilcBool auto_rehash;
+ bool auto_rehash;
if (!foreach)
return;
int i;
SilcHashTableEntry *table, e, tmp;
SilcUInt32 table_size, size_index;
- SilcBool auto_rehash;
+ bool auto_rehash;
SILC_HT_DEBUG(("Start"));
int i;
SilcHashTableEntry *table, e, tmp;
SilcUInt32 table_size, size_index;
- SilcBool auto_rehash;
+ bool auto_rehash;
SILC_HT_DEBUG(("Start"));
`context' and TRUE. If this returns FALSE then there are no anymore
any entrys. Usage: while (silc_hash_table_get(&htl, &key, &context)) */
-SilcBool silc_hash_table_get(SilcHashTableList *htl, void **key,
- void **context)
+bool silc_hash_table_get(SilcHashTableList *htl, void **key, void **context)
{
SilcHashTableEntry entry = (SilcHashTableEntry)htl->entry;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2006 Pekka Riikonen
+ Copyright (C) 2001 - 2003 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
* 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
*
* SYNOPSIS
*
- * typedef SilcBool (*SilcHashCompare)(void *key1, void *key2,
- * void *user_context);
+ * typedef bool (*SilcHashCompare)(void *key1, void *key2,
+ * void *user_context);
*
* DESCRIPTION
*
* to the callback.
*
***/
-typedef SilcBool (*SilcHashCompare)(void *key1, void *key2,
- void *user_context);
+typedef bool (*SilcHashCompare)(void *key1, void *key2, void *user_context);
/****f* silcutil/SilcHashTableAPI/SilcHashDestructor
*
* void *compare_user_context,
* SilcHashDestructor destructor,
* void *destructor_user_context,
- * SilcBool auto_rehash);
+ * bool auto_rehash);
*
* DESCRIPTION
*
void *compare_user_context,
SilcHashDestructor destructor,
void *destructor_user_context,
- SilcBool auto_rehash);
+ bool auto_rehash);
/****f* silcutil/SilcHashTableAPI/silc_hash_table_free
*
*
* SYNOPSIS
*
- * SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context);
+ * void silc_hash_table_add(SilcHashTable ht, void *key, void *context);
*
* DESCRIPTION
*
* to the hash table reliably (it is collision resistant).
*
***/
-SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context);
+void silc_hash_table_add(SilcHashTable ht, void *key, void *context);
/****f* silcutil/SilcHashTableAPI/silc_hash_table_replace
*
* SYNOPSIS
*
- * SilcBool silc_hash_table_replace(SilcHashTable ht, void *key,
- * void *context);
+ * void silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
*
* DESCRIPTION
*
* replaced key and context.
*
***/
-SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
+void silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
/****f* silcutil/SilcHashTableAPI/silc_hash_table_del
*
* SYNOPSIS
*
- * SilcBool silc_hash_table_del(SilcHashTable ht, void *key);
+ * bool silc_hash_table_del(SilcHashTable ht, void *key);
*
* DESCRIPTION
*
* entry was removed successfully and FALSE otherwise.
*
***/
-SilcBool silc_hash_table_del(SilcHashTable ht, void *key);
+bool silc_hash_table_del(SilcHashTable ht, void *key);
/****f* silcutil/SilcHashTableAPI/silc_hash_table_del_by_context
*
* SYNOPSIS
*
- * SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
- * void *context);
+ * bool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
+ * void *context);
*
* DESCRIPTION
*
* be used to check whether the correct entry is being deleted.
*
***/
-SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
- void *context);
+bool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
+ 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);
+ * bool silc_hash_table_find(SilcHashTable ht, void *key,
+ * void **ret_key, void **ret_context);
*
* DESCRIPTION
*
* maybe used only to check whether given key exists in the table.
*
***/
-SilcBool silc_hash_table_find(SilcHashTable ht, void *key,
- void **ret_key, void **ret_context);
+bool silc_hash_table_find(SilcHashTable ht, void *key,
+ 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);
+ * bool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
+ * void *context, void **ret_key);
*
* DESCRIPTION
*
* the caller already knows the context.
*
***/
-SilcBool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
- void *context, void **ret_key);
+bool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
+ void *context, void **ret_key);
/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach
*
*
* SYNOPSIS
*
- * SilcBool silc_hash_table_get(SilcHashTableList *htl, void **key,
- * void **context);
+ * bool silc_hash_table_get(SilcHashTableList *htl, void **key,
+ * void **context);
*
* DESCRIPTION
*
* Returns always the next entry in the hash table into the `key' and
- * `context' and TRUE. If this returns FALSE then there are no more
- * entries.
- *
- * EXAMPLE
- *
- * SilcHashTableList htl;
- * silc_hash_table_list(hash_table, &htl);
- * while (silc_hash_table_get(&htl, (void *)&key, (void *)&context))
- * ...
- * silc_hash_table_list_reset(&htl);
+ * `context' and TRUE. If this returns FALSE then there are no anymore
+ * any entrys.
*
***/
-SilcBool silc_hash_table_get(SilcHashTableList *htl,
- void **key, void **context);
+bool silc_hash_table_get(SilcHashTableList *htl, void **key, void **context);
/* Extended hash table interface (same as above but with specific
*
* SYNOPSIS
*
- * SilcBool silc_hash_table_add_ext(SilcHashTable ht, void *key,
- * void *context,
- * SilcHashFunction hash,
- * void *hash_user_context);
+ * void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
+ * SilcHashFunction hash,
+ * void *hash_user_context);
*
* DESCRIPTION
*
* function. If not provided the hash table's default is used.
*
***/
-SilcBool silc_hash_table_add_ext(SilcHashTable ht,
- void *key, void *context,
- SilcHashFunction hash,
- void *hash_user_context);
+void 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
*
- * SilcBool silc_hash_table_replace_ext(SilcHashTable ht, void *key,
- * void *context,
- * SilcHashFunction hash,
- * void *hash_user_context);
+ * void silc_hash_table_replace_ext(SilcHashTable ht, void *key,
+ * void *context,
+ * SilcHashFunction hash,
+ * void *hash_user_context);
*
* DESCRIPTION
*
* function. If not provided the hash table's default is used.
*
***/
-SilcBool silc_hash_table_replace_ext(SilcHashTable ht,
- void *key, void *context,
- SilcHashFunction hash,
- void *hash_user_context);
+void 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);
+ * bool 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);
*
* DESCRIPTION
*
* specific destructor function.
*
***/
-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);
+bool 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);
/****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);
+ * bool 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
*
* specific destructor function.
*
***/
-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);
+bool 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);
/****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);
+ * bool 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);
*
* DESCRIPTION
*
* comparing function. If not provided the hash table's default is used.
*
***/
-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);
+bool 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);
/****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);
+ * bool 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
*
* comparing function. If not provided the hash table's default is used.
*
***/
-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);
+bool 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);
/****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach_ext
*
/*
- silclist.h
+ silclist.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2005 Pekka Riikonen
+ Copyright (C) 2002 - 2003 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
* Implementation of the SilcList interface. This interface provides
* simple linked list.
*
- * SILC List is not thread-safe. If the same list context must be used
- * in multithreaded environment concurrency control must be employed.
- *
***/
#ifndef SILCLIST_H
/****s* silcutil/SilcList/SilcList
*
* NAME
- *
+ *
* typedef struct { ... } SilcList;
*
* DESCRIPTION
void *head; /* Start of the list */
void *tail; /* End of the list */
void *current; /* Current pointer in list */
- SilcUInt16 next_offset; /* Offset to 'next' pointer */
- SilcUInt16 prev_offset; /* Offset to 'prev' pointer */
+ unsigned int next_offset : 16; /* Offset to 'next' pointer */
+ unsigned int prev_offset : 16; /* 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 */
/****d* silcutil/SilcList/SILC_LIST_END
*
* NAME
- *
+ *
* #define SILC_LIST_END ...
*
* DESCRIPTION
*
* DESCRIPTION
*
- * Adds new entry indicated by `entry' to the end of the list indicated
+ * Adds new entry indicated by `entry' to the end of the list indicated
* by `list'.
*
***/
(list).count++; \
} while(0)
-/****f* silcutil/SilcList/silc_list_insert
- *
- * SYNOPSIS
- *
- * #define silc_list_insert(list, current, entry) ...
- *
- * DESCRIPTION
- *
- * Insert new entry indicated by `entry' after the entry `current'
- * to the list indicated by `list'. If `current' is NULL, then the
- * `entry' is added at the head of the list. Use the silc_list_add
- * to add at the end of the list.
- *
- ***/
-#define silc_list_insert(list, current, entry) \
-do { \
- if (!(current)) { \
- if ((list).head) \
- *__silc_list_next(list, entry) = (list).head; \
- else \
- *__silc_list_next(list, entry) = NULL; \
- if ((list).prev_set && (list).head) \
- *__silc_list_prev(list, (list).head) = entry; \
- if (!(list).tail) \
- (list).tail = (entry); \
- (list).head = (entry); \
- if ((list).prev_set) \
- *__silc_list_prev(list, entry) = NULL; \
- } else { \
- *__silc_list_next(list, entry) = *__silc_list_next(list, current); \
- *__silc_list_next(list, current) = entry; \
- if ((list).prev_set) { \
- *__silc_list_prev(list, entry) = current; \
- if (*__silc_list_next(list, entry)) \
- *__silc_list_prev(list, *__silc_list_next(list, entry)) = entry; \
- } \
- if ((list).tail == (current)) \
- (list).tail = (entry); \
- } \
- (list).count++; \
-} while(0)
-
/****f* silcutil/SilcList/silc_list_del
*
* SYNOPSIS
*
* EXAMPLE
*
- * // Traverse the list from the beginning to the end
+ * // Traverse the list from the beginning to the end
* silc_list_start(list);
* while ((entry = silc_list_get(list)) != SILC_LIST_END) {
* ...
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* SilcLogSettings context */
typedef struct {
/* Cycle log file */
fprintf(log->fp,
"[%s] [%s] Cycling log file, over max log size (%lu kilobytes)\n",
- silc_time_string(0), log->typename,
- (unsigned long)log->maxsize / 1024);
+ silc_get_time(0), log->typename, (unsigned long)log->maxsize / 1024);
fflush(log->fp);
fclose(log->fp);
memset(newname, 0, sizeof(newname));
- silc_snprintf(newname, sizeof(newname) - 1, "%s.old", log->filename);
+ snprintf(newname, sizeof(newname) - 1, "%s.old", log->filename);
unlink(newname);
rename(log->filename, newname);
if (silclog.flushdelay < 2)
silclog.flushdelay = 2;
- silc_schedule_task_add_timeout(context, silc_log_fflush_callback, context,
- silclog.flushdelay, 0);
+ silc_schedule_task_add(context, 0, silc_log_fflush_callback, context,
+ silclog.flushdelay, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
/* Output log message to log file */
found:
if (silclog.timestamp)
- fprintf(fp, "[%s] [%s] %s\n", silc_time_string(0), typename, string);
+ fprintf(fp, "[%s] [%s] %s\n", silc_get_time(0), typename, string);
else
fprintf(fp, "[%s] %s\n", typename, string);
/* Set and initialize the specified log file. */
-SilcBool silc_log_set_file(SilcLogType type, char *filename,
- SilcUInt32 maxsize, SilcSchedule scheduler)
+bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
+ SilcSchedule scheduler)
{
FILE *fp = NULL;
SilcLog log;
/* Add flush timeout */
if (scheduler) {
silc_schedule_task_del_by_callback(scheduler, silc_log_fflush_callback);
- silc_schedule_task_add_timeout(scheduler, silc_log_fflush_callback,
- scheduler, 10, 0);
+ silc_schedule_task_add(scheduler, 0, silc_log_fflush_callback, scheduler,
+ 10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silclog.scheduled = TRUE;
}
/* Set timestamp */
-void silc_log_timestamp(SilcBool enable)
+void silc_log_timestamp(bool enable)
{
silclog.timestamp = enable;
}
/* Set quick logging */
-void silc_log_quick(SilcBool enable)
+void silc_log_quick(bool enable)
{
silclog.quick = enable;
}
/* Set debugging */
-void silc_log_debug(SilcBool enable)
+void silc_log_debug(bool enable)
{
silclog.debug = enable;
}
/* Set debug hexdump */
-void silc_log_debug_hexdump(SilcBool enable)
+void silc_log_debug_hexdump(bool enable)
{
silclog.debug_hexdump = enable;
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
*
* SYNOPSIS
*
- * typedef SilcBool (*SilcLogCb)(SilcLogType type, char *message,
- * void *context);
+ * typedef bool (*SilcLogCb)(SilcLogType type, char *message,
+ * void *context);
*
* DESCRIPTION
*
* silc_log_set_callback
*
***/
-typedef SilcBool (*SilcLogCb)(SilcLogType type, char *message, void *context);
+typedef bool (*SilcLogCb)(SilcLogType type, char *message, void *context);
/****f* silcutil/SilcLogAPI/SilcLogDebugCb
*
* SYNOPSIS
*
- * typedef SilcBool (*SilcLogDebugCb)(char *file, char *function, int line,
- * char *message, void *context);
+ * typedef bool (*SilcLogDebugCb)(char *file, char *function, int line,
+ * char *message, void *context);
*
* DESCRIPTION
*
* silc_debug, silc_log_set_debug_callbacks
*
***/
-typedef SilcBool (*SilcLogDebugCb)(char *file, char *function, int line,
- char *message, void *context);
+typedef bool (*SilcLogDebugCb)(char *file, char *function, int line,
+ char *message, void *context);
/****f* silcutil/SilcLogAPI/SilcLogHexdumpCb
*
* SYNOPSIS
*
- * typedef SilcBool
- * (*SilcDebugHexdumpCb)(char *file, char *function, int line,
- * unsigned char *data,
- * SilcUInt32 data_len,
- * char *message, void *context;
+ * typedef bool (*SilcDebugHexdumpCb)(char *file, char *function, int line,
+ * unsigned char *data,
+ * SilcUInt32 data_len,
+ * char *message, void *context;
*
* DESCRIPTION
*
* silc_debug_hexdump, silc_log_set_debug_callbacks
*
***/
-typedef SilcBool (*SilcLogHexdumpCb)(char *file, char *function, int line,
- unsigned char *data, SilcUInt32 data_len,
- char *message, void *context);
+typedef bool (*SilcLogHexdumpCb)(char *file, char *function, int line,
+ unsigned char *data, SilcUInt32 data_len,
+ char *message, void *context);
/* Macros */
#endif /* SILC_DEBUG */
/***/
-/****d* silcutil/SilcLogAPI/SILC_ASSERT
- *
- * NAME
- *
- * #define SILC_ASSERT(experssion)
- *
- * DESCRIPTION
- *
- * Assert macro that prints error message to stderr and calls abort()
- * if the `expression' is false (ie. compares equal to zero). If
- * SILC_DEBUG is not defined this macro has no effect.
- *
- * SOURCE
- */
-#if defined(SILC_DEBUG)
-#define SILC_ASSERT(expr) assert((expr));
-#else
-#define SILC_ASSERT(expr) do { } while(0)
-#endif /* SILC_DEBUG */
-/***/
-
/* Prototypes */
/****f* silcutil/SilcLogAPI/silc_log_set_file
*
* SYNOPSIS
*
- * SilcBool silc_log_set_file(SilcLogType type, char *filename,
+ * bool silc_log_set_file(SilcLogType type, char *filename,
* SilcUInt32 maxsize,
* SilcSchedule scheduler);
*
* save HD activity.
*
***/
-SilcBool silc_log_set_file(SilcLogType type, char *filename,
- SilcUInt32 maxsize, SilcSchedule scheduler);
+bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
+ SilcSchedule scheduler);
/****f* silcutil/SilcLogAPI/silc_log_get_file
*
*
* NAME
*
- * void silc_log_timestamp(SilcBool enable);
+ * void silc_log_timestamp(bool enable);
*
* DESCRIPTION
*
* timestamp and to FALSE to disable it. Default is TRUE.
*
***/
-void silc_log_timestamp(SilcBool enable);
+void silc_log_timestamp(bool enable);
/****f* silcutil/SilcLogAPI/silc_log_flushdelay
*
*
* NAME
*
- * void silc_log_quick(SilcBool enable);
+ * void silc_log_quick(bool enable);
*
* DESCRIPTION
*
* Default is FALSE.
*
***/
-void silc_log_quick(SilcBool enable);
+void silc_log_quick(bool enable);
/****v* silcutil/SilcLogAPI/silc_log_debug
*
* NAME
*
- * void silc_log_debug(SilcBool enable);
+ * void silc_log_debug(bool enable);
*
* DESCRIPTION
*
* SILC_LOG_DEBUG
*
***/
-void silc_log_debug(SilcBool enable);
+void silc_log_debug(bool enable);
/****v* silcutil/SilcLogAPI/silc_log_debug_hexdump
*
* NAME
*
- * void silc_log_debug_hexdump(SilcBool enable);
+ * void silc_log_debug_hexdump(bool enable);
*
* DESCRIPTION
*
* SILC_LOG_HEXDUMP
*
***/
-void silc_log_debug_hexdump(SilcBool enable);
+void silc_log_debug_hexdump(bool enable);
#endif /* !SILCLOG_H */
/*
- silcmemory.c
+ silcmemory.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2006 Pekka Riikonen
+ Copyright (C) 1999 - 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#ifndef SILC_STACKTRACE
void *silc_malloc(size_t size)
{
void *addr;
- if (silc_unlikely(size <= 0 || size >= SILC_MAX_ALLOC)) {
- SILC_LOG_ERROR(("Invalid memory allocation"));
- return NULL;
- }
+ assert(size >= 0 && size <= SILC_MAX_ALLOC);
addr = malloc(size);
- if (silc_unlikely(!addr))
- SILC_LOG_ERROR(("System out of memory"));
+ assert(addr != NULL);
return addr;
}
void *silc_calloc(size_t items, size_t size)
{
void *addr;
- if (silc_unlikely(size * items <= 0 || size * items >= SILC_MAX_ALLOC)) {
- SILC_LOG_ERROR(("Invalid memory allocation"));
- return NULL;
- }
+ assert(size * items >= 0 && size * items <= SILC_MAX_ALLOC);
addr = calloc(items, size);
- if (silc_unlikely(!addr))
- SILC_LOG_ERROR(("System out of memory"));
+ assert(addr != NULL);
return addr;
}
void *silc_realloc(void *ptr, size_t size)
{
void *addr;
- if (silc_unlikely(size <= 0 || size >= SILC_MAX_ALLOC)) {
- SILC_LOG_ERROR(("Invalid memory allocation"));
- return NULL;
- }
+ assert(size >= 0 && size <= SILC_MAX_ALLOC);
addr = realloc(ptr, size);
- if (silc_unlikely(!addr))
- SILC_LOG_ERROR(("System out of memory"));
+ assert(addr != NULL);
return addr;
}
{
unsigned char *addr;
addr = silc_malloc(size + 1);
- if (silc_unlikely(!addr)) {
- SILC_LOG_ERROR(("System out of memory"));
- return NULL;
- }
+ assert(addr != NULL);
memcpy((void *)addr, ptr, size);
addr[size] = '\0';
return (void *)addr;
}
#endif /* !SILC_STACKTRACE */
-
-/* SilcStack aware routines */
-
-void *silc_smalloc(SilcStack stack, SilcUInt32 size)
-{
- return stack ? silc_stack_malloc(stack, size, TRUE) : silc_malloc(size);
-}
-
-void *silc_smalloc_ua(SilcStack stack, SilcUInt32 size)
-{
- return stack ? silc_stack_malloc(stack, size, FALSE) : silc_malloc(size);
-}
-
-void *silc_scalloc(SilcStack stack, SilcUInt32 items, SilcUInt32 size)
-{
- unsigned char *addr;
-
- if (!stack)
- return silc_calloc(items, size);
-
- addr = silc_stack_malloc(stack, items * size, TRUE);
- if (silc_unlikely(!addr))
- return NULL;
- memset(addr, 0, items * size);
- return (void *)addr;
-}
-
-void *silc_srealloc(SilcStack stack, SilcUInt32 old_size,
- void *ptr, SilcUInt32 size)
-{
- return stack ? silc_stack_realloc(stack, old_size, ptr, size, TRUE) :
- silc_realloc(ptr, size);
-}
-
-void *silc_srealloc_ua(SilcStack stack, SilcUInt32 old_size,
- void *ptr, SilcUInt32 size)
-{
- return stack ? silc_stack_realloc(stack, old_size, ptr, size, FALSE) :
- silc_realloc(ptr, size);
-}
-
-void *silc_smemdup(SilcStack stack, const void *ptr, SilcUInt32 size)
-{
- unsigned char *addr;
-
- if (!stack)
- return silc_memdup(ptr, size);
-
- addr = silc_stack_malloc(stack, size + 1, TRUE);
- if (silc_unlikely(!addr))
- return NULL;
- memcpy((void *)addr, ptr, size);
- addr[size] = '\0';
- return (void *)addr;
-}
-
-char *silc_sstrdup(SilcStack stack, const char *str)
-{
- SilcInt32 size = strlen(str);
- char *addr;
-
- if (!stack)
- return silc_memdup(str, size);
-
- addr = silc_stack_malloc(stack, size + 1, FALSE);
- if (silc_unlikely(!addr))
- return NULL;
- memcpy((void *)addr, str, size);
- addr[size] = '\0';
- return addr;
-}
/*
- silcmemory.h
+ silcmemory.h
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1999 - 2005 Pekka Riikonen
+ Copyright (C) 1999 - 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
* applications use these functions when they need to allocate, manipulate
* and free memory.
*
+ * Currently all allocation routines assert() that the memory was allocated
+ * successfully. Hence, if memory allocation fails it is fatal error.
+ *
***/
#ifndef SILCMEMORY_H
* DESCRIPTION
*
* Allocates memory of `size' bytes and returns pointer to the allocated
- * memory area. Free the memory by calling silc_free. Returns NULL on
- * error.
+ * memory area. Free the memory by calling silc_free.
*
***/
void *silc_malloc(size_t size);
*
* Allocates memory of for an array of `items' elements of `size' bytes
* and returns pointer to the allocated memory area. The memory area is
- * also zeroed. Free the memory by calling silc_free. Returns NULL on
- * error.
+ * also zeroed. Free the memory by calling silc_free.
*
***/
void *silc_calloc(size_t items, size_t size);
#include "stacktrace.h"
#endif /* SILC_STACKTRACE */
-
-/* Following functions that use SilcStack as memory source. */
-
-/****f* silcutil/SilcMemoryAPI/silc_smalloc
- *
- * SYNOPSIS
- *
- * void *silc_smalloc(SilcStack stack, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Allocate memory block of size of `size' from the stack indicated by
- * `stack' and return pointer to it. Returns NULL on error. This
- * function allocates aligned memory so it can be used to allocate
- * memory for structures, for example. If you allocate strings or
- * data buffers using silc_smalloc_ua is recommended instead of this
- * function.
- *
- * NOTES
- *
- * Be careful with this function: do not free the returned pointer
- * explicitly and do not save the returned pointer to a permanent
- * location.
- *
- * If `stack' is NULL this function calls silc_malloc.
- *
- ***/
-void *silc_smalloc(SilcStack stack, SilcUInt32 size);
-
-/****f* silcutil/SilcMemoryAPI/silc_smalloc_ua
- *
- * SYNOPSIS
- *
- * void *silc_smalloc_ua(SilcStack stack, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Allocate unaligned memory block of size of `size' from the stack
- * indicated by `stack' and return pointer to it. Returns NULL on error.
- *
- * NOTES
- *
- * This function must not be used to allocate memory for structures.
- * Use this function only for strings and data buffers.
- *
- * Be careful with this function: do not free the returned pointer
- * explicitly and do not save the returned pointer to a permanent
- * location.
- *
- * If `stack' is NULL this function calls silc_malloc.
- *
- ***/
-void *silc_smalloc_ua(SilcStack stack, SilcUInt32 size);
-
-/****f* silcutil/SilcMemoryAPI/silc_scalloc
- *
- * SYNOPSIS
- *
- * void *silc_scalloc(SilcStack stack, SilcUInt32 items, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Allocate memory block of size of `size' from the stack indicated by
- * `stack', zero the memory area and return pointer to it. This
- * function allocates aligned memory. Returns NULL on error.
- *
- * NOTES
- *
- * Be careful with this function: do not free the returned pointer
- * explicitly and do not save the returned pointer to a permanent
- * location.
- *
- * If `stack' is NULL this function calls silc_calloc.
- *
- ***/
-void *silc_scalloc(SilcStack stack, SilcUInt32 items, SilcUInt32 size);
-
-/****f* silcutil/SilcMemoryAPI/silc_srealloc
- *
- * SYNOPSIS
- *
- * void *silc_srealloc(SilcStack stack, SilcUInt32 old_size,
- * void *ptr, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Change the size of the memory block indicated by `ptr' to the new
- * size of `size' bytes. The contents of `ptr' will not be changed.
- * If `ptr' is NULL the call is equivalent to silc_smalloc. If `size'
- * is zero (0) error will occur. Returns NULL on error and the old
- * pointer remain intact.
- *
- * NOTES
- *
- * This function reallocates successfully only if the previous allocation
- * to `stack' was `ptr'. If there was another memory allocation between
- * allocating `ptr' and this call, this routine will return NULL. The
- * NULL is also returned if the `size' does not fit to current stack
- * and allocating new block would require slow copying of the data. It
- * is left to the caller to decide whether to allocate new pointer and
- * copy the old data in case this function returns NULL.
- *
- * This function can be used to reallocate only aligned memory allocated
- * with silc_smalloc.
- *
- * If `stack' is NULL this function calls silc_realloc.
- *
- ***/
-void *silc_srealloc(SilcStack stack, SilcUInt32 old_size,
- void *ptr, SilcUInt32 size);
-
-/****f* silcutil/SilcMemoryAPI/silc_srealloc_ua
- *
- * SYNOPSIS
- *
- * void *silc_srealloc_ua(SilcStack stack, SilcUInt32 old_size,
- * void *ptr, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Same as silc_srealloc but reallocates unaligned memory.
- *
- * NOTES
- *
- * This function can be used to reallocate only unaligned memory
- * allocated with silc_smalloc_ua.
- *
- * If `stack' is NULL this function calls silc_realloc.
- *
- ***/
-void *silc_srealloc_ua(SilcStack stack, SilcUInt32 old_size,
- void *ptr, SilcUInt32 size);
-
-/****f* silcutil/SilcMemoryAPI/silc_smemdup
- *
- * SYNOPSIS
- *
- * void *silc_smemdup(SilcStack stack, const void *ptr, SilcUInt32 size);
- *
- * DESCRIPTION
- *
- * Duplicates the memory area indicated by `ptr' which is the size of
- * `size' bytes. Returns pointer to the duplicated memory area. This
- * NULL terminates the dupped memory area by allocating `size' + 1
- * bytes, so this function can be used to duplicate strings that does not
- * have NULL termination. This function allocates aligned memory so
- * it can be used to duplicate also structures. Returns NULL on error.
- *
- * NOTES
- *
- * Be careful with this function: do not free the returned pointer
- * explicitly and do not save the returned pointer to a permanent
- * location.
- *
- * If `stack' is NULL this function calls silc_memdup.
- *
- ***/
-void *silc_smemdup(SilcStack stack, const void *ptr, SilcUInt32 size);
-
-/****f* silcutil/SilcMemoryAPI/silc_sstrdup
- *
- * SYNOPSIS
- *
- * char *silc_sstrdup(SilcStack stack, const char *str);
- *
- * DESCRIPTION
- *
- * Duplicates the string indicated by `str' and returns the duplicated
- * string. This function allocates unaligned memory. Returns NULL
- * on error.
- *
- * NOTES
- *
- * Be careful with this function: do not free the returned pointer
- * explicitly and do not save the returned pointer to a permanent
- * location.
- *
- * If `stack' is NULL this function calls silc_strdup.
- *
- ***/
-char *silc_sstrdup(SilcStack stack, const char *str);
-
#endif /* SILCMEMORY_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 - 2007 Pekka Riikonen
+ 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
*/
-#include "silc.h"
+#include "silcincludes.h"
+#include "silcmime.h"
-/************************ Static utility functions **************************/
+struct SilcMimeStruct {
+ SilcHashTable fields;
+ unsigned char *data;
+ SilcUInt32 data_len;
+ SilcDList multiparts;
+ char *boundary;
+ char *multitype;
+};
-/* MIME fields destructor */
+struct SilcMimeAssemblerStruct {
+ SilcHashTable fragments;
+};
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;
return mime;
}
-/* Free MIME context */
-
void silc_mime_free(SilcMime mime)
{
SilcMime m;
silc_free(mime);
}
-/* Allocate MIME assembler */
+static void silc_mime_assembler_dest(void *key, void *context,
+ void *user_context)
+{
+ silc_free(key);
+ silc_hash_table_free(context);
+}
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);
}
-/* Decode MIME message */
-
-SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
- SilcUInt32 data_len)
+SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len)
{
- SilcMime m = NULL;
+ SilcMime mime;
int i, k;
char *tmp, *field, *value, *line;
if (!data)
return NULL;
- if (!mime) {
- mime = silc_mime_alloc();
- if (!mime)
- return NULL;
- m = mime;
- }
+ mime = silc_mime_alloc();
+ if (!mime)
+ return NULL;
/* Parse the fields */
line = tmp = (char *)data;
line = strdup(value);
if (strrchr(line, '"')) {
*strrchr(line, '"') = '\0';
- silc_snprintf(b, sizeof(b) - 1, "--%s", line + 1);
+ snprintf(b, sizeof(b) - 1, "--%s", line + 1);
mime->boundary = strdup(line + 1);
} else {
- silc_snprintf(b, sizeof(b) - 1, "--%s", line);
+ snprintf(b, sizeof(b) - 1, "--%s", line);
mime->boundary = strdup(line);
}
silc_free(line);
k -= 2;
/* Parse the part */
- p = silc_mime_decode(NULL, line, k - i);
+ p = silc_mime_decode(line, k - i);
if (!p)
goto err;
}
}
} else {
- /* Get data area. If we are at the end and we have fields present
- there is no data area present, but, if fields are not present we
- only have data area. */
- if (i >= data_len && !silc_hash_table_count(mime->fields))
+ /* Get data area */
+ if (i >= data_len)
i = 0;
SILC_LOG_DEBUG(("Data len %d", data_len - i));
- if (data_len - i)
- silc_mime_add_data(mime, tmp + i, data_len - i);
+ silc_mime_add_data(mime, tmp + i, data_len - i);
}
return mime;
err:
- if (m)
- silc_mime_free(m);
+ silc_mime_free(mime);
return NULL;
}
-/* Encode MIME message */
-
unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len)
{
SilcMime part;
/* Encode the headers. Order doesn't matter */
i = 0;
silc_hash_table_list(mime->fields, &htl);
- while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) {
+ while (silc_hash_table_get(&htl, (void **)&field, (void **)&value)) {
memset(tmp, 0, sizeof(tmp));
SILC_LOG_DEBUG(("Header %s: %s", field, value));
- silc_snprintf(tmp, sizeof(tmp) - 1, "%s: %s\r\n", field, value);
+ snprintf(tmp, sizeof(tmp) - 1, "%s: %s\r\n", field, value);
silc_buffer_strformat(&buf, tmp, SILC_STRFMT_END);
i++;
}
silc_buffer_strformat(&buf, "\r\n", SILC_STRFMT_END);
/* Assemble the whole buffer */
- buffer = silc_buffer_alloc_size(mime->data_len + silc_buffer_len(&buf));
+ buffer = silc_buffer_alloc_size(mime->data_len + buf.len);
if (!buffer)
return NULL;
/* Add headers */
- if (silc_buffer_len(&buf)) {
- silc_buffer_put(buffer, buf.head, silc_buffer_len(&buf));
- silc_buffer_pull(buffer, silc_buffer_len(&buf));
+ if (buf.len) {
+ silc_buffer_put(buffer, buf.head, buf.len);
+ silc_buffer_pull(buffer, buf.len);
}
/* Add data */
/* If fields are not present, add extra CRLF */
if (!silc_hash_table_count(part->fields))
- silc_snprintf(tmp2, sizeof(tmp2) - 1, "\r\n");
- silc_snprintf(tmp, sizeof(tmp) - 1, "%s--%s\r\n%s",
+ snprintf(tmp2, sizeof(tmp2) - 1, "\r\n");
+ snprintf(tmp, sizeof(tmp) - 1, "%s--%s\r\n%s",
i != 0 ? "\r\n" : "", mime->boundary, tmp2);
i = 1;
- buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) +
- pd_len + strlen(tmp));
+ buffer = silc_buffer_realloc(buffer, buffer->truelen + pd_len +
+ strlen(tmp));
if (!buffer)
return NULL;
silc_buffer_put_tail(buffer, tmp, strlen(tmp));
}
memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary);
- buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) +
- strlen(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary);
+ buffer = silc_buffer_realloc(buffer, buffer->truelen + strlen(tmp));
if (!buffer)
return NULL;
silc_buffer_put_tail(buffer, tmp, strlen(tmp));
return ret;
}
-/* Assembles MIME message from partial MIME messages */
+static void silc_mime_assemble_dest(void *key, void *context,
+ void *user_context)
+{
+ silc_mime_free(context);
+}
SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial)
{
/* Find fragments with this ID. */
if (!silc_hash_table_find(assembler->fragments, (void *)id,
- NULL, (void *)&f)) {
+ NULL, (void **)&f)) {
/* This is new fragment to new message. Add to hash table and return. */
f = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
silc_mime_assemble_dest, NULL, TRUE);
/* Assemble the complete MIME message now. We get them in order from
the hash table. */
for (i = 1; i <= total; i++) {
- if (!silc_hash_table_find(f, SILC_32_TO_PTR(i), NULL, (void *)&p))
+ if (!silc_hash_table_find(f, SILC_32_TO_PTR(i), NULL, (void **)&p))
goto err;
/* The fragment is in the data portion of the partial message */
goto err;
silc_buffer_put(compbuf, data, data_len);
} else {
- compbuf = silc_buffer_realloc(compbuf, silc_buffer_truelen(compbuf) +
- data_len);
+ compbuf = silc_buffer_realloc(compbuf, compbuf->truelen + data_len);
if (!compbuf)
goto err;
silc_buffer_put_tail(compbuf, data, data_len);
}
/* Now parse the complete MIME message and deliver it */
- complete = silc_mime_decode(NULL, (const unsigned char *)compbuf->head,
- silc_buffer_truelen(compbuf));
+ complete = silc_mime_decode((const unsigned char *)compbuf->head,
+ compbuf->truelen);
if (!complete)
goto err;
return NULL;
}
-/* Encodes partial MIME messages */
-
SilcDList silc_mime_encode_partial(SilcMime mime, int max_size)
{
unsigned char *buf, *tmp;
memset(type, 0, sizeof(type));
gethostname(type, sizeof(type) - 1);
srand((time(NULL) + buf_len) ^ rand());
- silc_snprintf(id, sizeof(id) - 1, "%X%X%X%s",
+ snprintf(id, sizeof(id) - 1, "%X%X%X%s",
(unsigned int)rand(), (unsigned int)time(NULL),
(unsigned int)buf_len, type);
silc_mime_add_field(partial, "MIME-Version", "1.0");
memset(type, 0, sizeof(type));
- silc_snprintf(type, sizeof(type) - 1,
+ snprintf(type, sizeof(type) - 1,
"message/partial; id=\"%s\"; number=1", id);
silc_mime_add_field(partial, "Content-Type", type);
silc_mime_add_data(partial, buf, max_size);
silc_mime_add_field(partial, "MIME-Version", "1.0");
if (len > max_size) {
- silc_snprintf(type, sizeof(type) - 1,
+ snprintf(type, sizeof(type) - 1,
"message/partial; id=\"%s\"; number=%d",
id, num++);
silc_mime_add_data(partial, buf + off, max_size);
off += max_size;
len -= max_size;
} else {
- silc_snprintf(type, sizeof(type) - 1,
+ snprintf(type, sizeof(type) - 1,
"message/partial; id=\"%s\"; number=%d; total=%d",
id, num, num);
silc_mime_add_data(partial, buf + off, len);
return list;
}
-/* Free partial MIME list */
-
void silc_mime_partial_free(SilcDList partials)
{
SilcBuffer buf;
silc_dlist_uninit(partials);
}
-/* Add field */
-
void silc_mime_add_field(SilcMime mime, const char *field, const char *value)
{
if (!mime || !field || !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;
return NULL;
if (!silc_hash_table_find(mime->fields, (void *)field,
- NULL, (void *)&value))
+ NULL, (void **)&value))
return NULL;
return (const char *)value;
}
-/* Add data */
-
void silc_mime_add_data(SilcMime mime, const unsigned char *data,
SilcUInt32 data_len)
{
mime->data_len = data_len;
}
-/* Get data */
-
const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len)
{
if (!mime)
return mime->data;
}
-/* Steal data */
-
-unsigned char *silc_mime_steal_data(SilcMime mime, SilcUInt32 *data_len)
-{
- unsigned char *data;
-
- if (!mime)
- return NULL;
-
- if (data_len)
- *data_len = mime->data_len;
-
- data = mime->data;
-
- mime->data = NULL;
- mime->data_len = 0;
-
- return data;
-}
-
-/* Returns TRUE if partial message */
-
-SilcBool silc_mime_is_partial(SilcMime mime)
+bool silc_mime_is_partial(SilcMime mime)
{
const char *type = silc_mime_get_field(mime, "Content-Type");
if (!type)
return TRUE;
}
-/* Set as multipart message */
-
void silc_mime_set_multipart(SilcMime mime, const char *type,
const char *boundary)
{
return;
memset(tmp, 0, sizeof(tmp));
- silc_snprintf(tmp, sizeof(tmp) - 1, "multipart/%s; boundary=%s", type, boundary);
+ snprintf(tmp, sizeof(tmp) - 1, "multipart/%s; boundary=%s", type, boundary);
silc_mime_add_field(mime, "Content-Type", tmp);
silc_free(mime->boundary);
mime->boundary = strdup(boundary);
mime->multiparts = silc_dlist_init();
}
-/* Add multipart */
-
-SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part)
+bool silc_mime_add_multipart(SilcMime mime, SilcMime part)
{
if (!mime || !mime->multiparts || !part)
return FALSE;
return TRUE;
}
-/* Return TRUE if has multiparts */
-
-SilcBool silc_mime_is_multipart(SilcMime mime)
+bool silc_mime_is_multipart(SilcMime mime)
{
if (!mime)
return FALSE;
return mime->multiparts != NULL;
}
-/* Returns multiparts */
-
SilcDList silc_mime_get_multiparts(SilcMime mime, const char **type)
{
if (!mime)
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 - 2006 Pekka Riikonen
+ 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
* MIME messages, multipart MIME messages, including nested multiparts, and
* MIME fragmentation and defragmentation.
*
- * SILC Mime API is not thread-safe. If the same MIME context must be
- * used in multithreaded environment concurrency control must be employed.
- *
***/
#ifndef SILCMIME_H
*
* SYNOPSIS
*
- * SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
+ * SilcMime silc_mime_decode(const unsigned char *data,
* SilcUInt32 data_len);
*
* DESCRIPTION
*
* Decodes a MIME message and returns the parsed message into newly
- * 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.
+ * allocated SilcMime context.
*
* EXAMPLE
*
* // Parse MIME message and get its content type
- * mime = silc_mime_decode(NULL, data, data_len);
+ * mime = silc_mime_decode(data, data_len);
* type = silc_mime_get_field(mime, "Content-Type");
* ...
*
* // Assemble received MIME fragment
- * mime = silc_mime_decode(NULL, data, data_len);
+ * mime = silc_mime_decode(data, data_len);
* if (silc_mime_is_partial(mime) == TRUE)
* silc_mime_assmeble(assembler, mime);
*
***/
-SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
- SilcUInt32 data_len);
+SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len);
/****f* silcutil/SILCMIMEAPI/silc_mime_encode
*
***/
const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len);
-/****f* silcutil/SILCMIMEAPI/silc_mime_steal_data
- *
- * SYNOPSIS
- *
- * unsigned char *
- * silc_mime_steal_data(SilcMime mime, SilcUInt32 *data_len);
- *
- * DESCRIPTION
- *
- * Returns the MIME data from the `mime' message. The data will be
- * removed from the `mime' and the caller is responsible of freeing the
- * returned pointer.
- *
- ***/
-unsigned char *silc_mime_steal_data(SilcMime mime, SilcUInt32 *data_len);
-
/****f* silcutil/SILCMIMEAPI/silc_mime_is_partial
*
* SYNOPSIS
*
- * SilcBool silc_mime_is_partial(SilcMime mime);
+ * bool silc_mime_is_partial(SilcMime mime);
*
* DESCRIPTION
*
* Returns TRUE if the MIME message `mime' is a partial MIME fragment.
*
***/
-SilcBool silc_mime_is_partial(SilcMime mime);
+bool silc_mime_is_partial(SilcMime mime);
/****f* silcutil/SILCMIMEAPI/silc_mime_set_multipart
*
*
* SYNOPSIS
*
- * SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part);
+ * bool silc_mime_add_multipart(SilcMime mime, SilcMime part);
*
* DESCRIPTION
*
* silc_mime_add_multipart(mime, part);
*
***/
-SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part);
+bool silc_mime_add_multipart(SilcMime mime, SilcMime part);
/****f* silcutil/SILCMIMEAPI/silc_mime_is_multipart
*
* SYNOPSIS
*
- * SilcBool silc_mime_is_multipart(SilcMime mime);
+ * bool silc_mime_is_multipart(SilcMime mime);
*
* DESCRIPTION
*
* Its parts can be get by calling silc_mime_get_multiparts.
*
***/
-SilcBool silc_mime_is_multipart(SilcMime mime);
+bool silc_mime_is_multipart(SilcMime mime);
/****f* silcutil/SILCMIMEAPI/silc_mime_get_multiparts
*
***/
SilcDList silc_mime_get_multiparts(SilcMime mime, const char **type);
-#include "silcmime_i.h"
-
#endif /* SILCMIME_H */
+++ /dev/null
-/*
-
- 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 */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 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
*
* DESCRIPTION
*
- * Interface for mutual exclusion locks and read/write locks. This is
- * platform independent interface for applications that need concurrency
- * control.
+ * Interface for the SILC Mutex locking implementation. This is platform
+ * independent mutual exclusion interface for applications that need
+ * concurrency control.
*
***/
***/
typedef struct SilcMutexStruct *SilcMutex;
-/****s* silcutil/SilcMutexAPI/SilcRwLock
+/****d* silcutil/SilcMutexAPI/SILC_MUTEX_DEFINE
*
* NAME
*
- * typedef struct SilcRwLockStruct *SilcRwLock;
+ * #define SILC_MUTEX_DEFINE(name) ...
*
* DESCRIPTION
*
- * This context is the actual SILC read/write lock and is allocated
- * by silc_rwlock_alloc and given as argument to all silc_rwlock_*
- * functions. It is freed by the silc_rwlock_free function.
+ * This macro is used to define new mutex. Use this macro in an
+ * environment that can be compiled with or without the SILC Mutex
+ * API. This is equivalent to defining SilcMutex `name'; directly.
*
- ***/
-typedef struct SilcRwLockStruct *SilcRwLock;
+ * SOURCE
+ */
+#define SILC_MUTEX_DEFINE(name) SilcMutex name
+/***/
/****f* silcutil/SilcMutexAPI/silc_mutex_alloc
*
* SYNOPSIS
*
- * SilcBool silc_mutex_alloc(SilcMutex *mutex);
+ * bool silc_mutex_alloc(SilcMutex *mutex);
*
* DESCRIPTION
*
* Allocates SILC Mutex object. The mutex object must be allocated
* before it can be used. It is freed by the silc_mutex_free function.
* This returns TRUE and allocated mutex in to the `mutex' and FALSE
- * on error. If threads support is not compiled in this returns FALSE,
- * but should not be considered as an error.
+ * on error.
*
***/
-SilcBool silc_mutex_alloc(SilcMutex *mutex);
+bool silc_mutex_alloc(SilcMutex *mutex);
/****f* silcutil/SilcMutexAPI/silc_mutex_free
*
* NOTES
*
* The caller must not call the silc_mutex_unlock for an unlocked
- * mutex or mutex not locked by the current thread.
+ * mutex or mutex not locked by the current thread. It is fatal
+ * error if this occurs.
*
***/
void silc_mutex_unlock(SilcMutex mutex);
-/****f* silcutil/SilcMutexAPI/silc_mutex_assert_locked
- *
- * SYNOPSIS
- *
- * void silc_mutex_assert_locked(SilcMutex mutex);
- *
- * DESCRIPTION
- *
- * Asserts that the `mutex' is locked. It is fatal error if the mutex
- * is not locked. If debugging is not compiled in this function has
- * no effect (SILC_DEBUG define).
- *
- ***/
-void silc_mutex_assert_locked(SilcMutex mutex);
-
-/****f* silcutil/SilcMutexAPI/silc_rwlock_alloc
- *
- * SYNOPSIS
- *
- * SilcBool silc_rwlock_alloc(SilcRwLock *rwlock);
- *
- * DESCRIPTION
- *
- * Allocates SILC read/write lock. The read/write lock must be allocated
- * before it can be used. It is freed by the silc_rwlock_free function.
- * This returns TRUE and allocated read/write lock in to the `rwlock' and
- * FALSE on error.
- *
- ***/
-SilcBool silc_rwlock_alloc(SilcRwLock *rwlock);
-
-/****f* silcutil/SilcRwLockAPI/silc_rwlock_free
- *
- * SYNOPSIS
- *
- * void silc_rwlock_free(SilcRwLock rwlock);
- *
- * DESCRIPTION
- *
- * Free SILC Rwlock object and frees all allocated memory. If `rwlock'
- * is NULL this function has no effect.
- *
- ***/
-void silc_rwlock_free(SilcRwLock rwlock);
-
-/****f* silcutil/SilcRwLockAPI/silc_rwlock_rdlock
- *
- * SYNOPSIS
- *
- * void silc_rwlock_rdlock(SilcRwLock rwlock);
- *
- * DESCRIPTION
- *
- * Acquires read lock of the read/write lock `rwlock'. If the `rwlock'
- * is locked by a writer the current thread will block until the other
- * thread has issued silc_rwlock_unlock for the `rwlock'. This function
- * may be called multiple times to acquire the read lock. There must be
- * same amount of silc_rwlock_unlock calls. If `rwlock' is NULL this
- * function has no effect.
- *
- ***/
-void silc_rwlock_rdlock(SilcRwLock rwlock);
-
-/****f* silcutil/SilcRwLockAPI/silc_rwlock_wrlock
- *
- * SYNOPSIS
- *
- * void silc_rwlock_wrlock(SilcRwLock rwlock);
- *
- * DESCRIPTION
- *
- * Acquires write lock of the read/write lock `rwlock'. If the `rwlock'
- * is locked by a writer or a reader the current thread will block until
- * the other thread(s) have issued silc_rwlock_unlock for the `rwlock'.
- * If `rwlock' is NULL this function has no effect.
- *
- ***/
-void silc_rwlock_wrlock(SilcRwLock rwlock);
-
-/****f* silcutil/SilcRwLockAPI/silc_rwlock_unlock
- *
- * SYNOPSIS
- *
- * void silc_rwlock_unlock(SilcRwLock rwlock);
- *
- * DESCRIPTION
- *
- * Releases the lock of the read/write lock `rwlock'. If `rwlock' was
- * locked by a writer this will release the writer lock. Otherwise this
- * releases the reader lock. If `rwlock' is NULL this function has no
- * effect.
- *
- ***/
-void silc_rwlock_unlock(SilcRwLock rwlock);
-
#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 Pekka Riikonen
+ Copyright (C) 1997 - 2001 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
*/
/* $Id$ */
-#include "silc.h"
-
-/* Returns bound port from listener */
-
-SilcUInt16 *silc_net_listener_get_port(SilcNetListener listener,
- SilcUInt32 *port_count)
-{
- SilcUInt16 *ports;
- int i;
-
- ports = silc_calloc(listener->socks_count, sizeof(*ports));
- if (!ports)
- return NULL;
-
- for (i = 0; i < listener->socks_count; i++)
- ports[i] = silc_net_get_local_port(listener->socks[i]);
-
- if (port_count)
- *port_count = listener->socks_count;
-
- return ports;
-}
+#include "silcincludes.h"
+#include "silcnet.h"
/* Accepts a connection from a particular socket */
/* Get socket options */
-int silc_net_get_socket_opt(int sock, int level, int option,
+int silc_net_get_socket_opt(int sock, int level, int option,
void *optval, int *opt_len)
{
return getsockopt(sock, level, option, optval, opt_len);
/* Checks whether IP address sent as argument is valid IPv4 address. */
-SilcBool silc_net_is_ip4(const char *addr)
+bool silc_net_is_ip4(const char *addr)
{
int count = 0;
while (*addr) {
- if (*addr != '.' && !isdigit((int)*addr))
+ if (*addr != '.' && !isdigit(*addr))
return FALSE;
if (*addr == '.')
count++;
if (count != 3)
return FALSE;
-
+
return TRUE;
}
/* Checks whether IP address sent as argument is valid IPv6 address. */
-SilcBool silc_net_is_ip6(const char *addr)
+bool silc_net_is_ip6(const char *addr)
{
/* XXX does this work with all kinds of IPv6 addresses? */
while (*addr) {
- if (*addr != ':' && !isxdigit((int)*addr))
+ if (*addr != ':' && !isxdigit(*addr))
return FALSE;
addr++;
}
-
+
return TRUE;
}
/* Checks whether IP address sent as argument is valid IP address. */
-SilcBool silc_net_is_ip(const char *addr)
+bool silc_net_is_ip(const char *addr)
{
if (silc_net_is_ip4(addr))
return TRUE;
typedef struct {
SilcNetResolveCallback completion;
void *context;
- SilcBool prefer_ipv6;
+ bool prefer_ipv6;
SilcSchedule schedule;
char *input;
char *result;
r->result = strdup(tmp);
silc_schedule_task_add(schedule, 0, silc_net_resolve_completion, r, 0, 1,
- SILC_TASK_TIMEOUT);
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_schedule_wakeup(schedule);
return NULL;
}
r->result = strdup(tmp);
silc_schedule_task_add(schedule, 0, silc_net_resolve_completion, r, 0, 1,
- SILC_TASK_TIMEOUT);
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_schedule_wakeup(schedule);
return NULL;
}
/* Resolves IP address for hostname. */
-SilcBool silc_net_gethostbyname(const char *name,
- SilcBool prefer_ipv6, char *address,
- SilcUInt32 address_len)
+bool silc_net_gethostbyname(const char *name, bool prefer_ipv6, char *address,
+ SilcUInt32 address_len)
{
#ifdef HAVE_IPV6
struct addrinfo hints, *ai, *tmp, *ip4 = NULL, *ip6 = NULL;
memset(address, 0, address_len);
strncpy(address, tmp, strlen(tmp));
#endif
-
+
return TRUE;
}
/* Resolves IP address for hostname async. */
-void silc_net_gethostbyname_async(const char *name,
- SilcBool prefer_ipv6,
+void silc_net_gethostbyname_async(const char *name,
+ bool prefer_ipv6,
SilcSchedule schedule,
SilcNetResolveCallback completion,
void *context)
/* Resolves hostname by IP address. */
-SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
- SilcUInt32 name_len)
+bool silc_net_gethostbyaddr(const char *addr, char *name, SilcUInt32 name_len)
{
#ifdef HAVE_IPV6
struct addrinfo req, *ai;
-
+
memset(&req, 0, sizeof(req));
req.ai_socktype = SOCK_STREAM;
req.ai_flags = AI_CANONNAME;
-
+
if (getaddrinfo(addr, NULL, &req, &ai))
return FALSE;
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, name, name_len, NULL, 0, 0)) {
memset(name, 0, name_len);
strncpy(name, hp->h_name, strlen(hp->h_name));
#endif
-
+
return TRUE;
}
/* Resolves hostname by IP address async. */
-void silc_net_gethostbyaddr_async(const char *addr,
+void silc_net_gethostbyaddr_async(const char *addr,
SilcSchedule schedule,
SilcNetResolveCallback completion,
void *context)
silc_thread_create(silc_net_gethostbyaddr_thread, r, FALSE);
}
-#ifndef SILC_SYMBIAN
-
/* Performs lookups for remote name and IP address. This peforms reverse
lookup as well to verify that the IP has FQDN. */
-SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
- char **ip)
+bool silc_net_check_host_by_sock(int sock, char **hostname, char **ip)
{
char host[1024];
int rval, len;
/* Performs lookups for local name and IP address. This peforms reverse
lookup as well to verify that the IP has FQDN. */
-SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
- char **ip)
+bool silc_net_check_local_by_sock(int sock, char **hostname, char **ip)
{
char host[1024];
int rval, len;
/* Return remote port by socket. */
-SilcUInt16 silc_net_get_remote_port(SilcSocket sock)
+SilcUInt16 silc_net_get_remote_port(int sock)
{
#ifdef HAVE_IPV6
struct sockaddr_storage remote;
if (getnameinfo((struct sockaddr *)&remote, len, NULL, 0, s, sizeof(s),
NI_NUMERICSERV))
return 0;
-
+
return atoi(s);
#else
struct sockaddr_in remote;
/* Return local port by socket. */
-SilcUInt16 silc_net_get_local_port(SilcSocket sock)
+SilcUInt16 silc_net_get_local_port(int sock)
{
#ifdef HAVE_IPV6
struct sockaddr_storage local;
if (getnameinfo((struct sockaddr *)&local, len, NULL, 0, s, sizeof(s),
NI_NUMERICSERV))
return 0;
-
+
return atoi(s);
#else
struct sockaddr_in local;
return ntohs(local.sin_port);
#endif
}
-#endif /* !SILC_SYMBIAN */
/* Return name of localhost. */
/*
silcnet.h
-
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2007 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
* DESCRIPTION
*
* SILC Net API provides various network routines for applications. It
- * can be used to create TCP/IP and UDP/IP connections and listeners.
- * Various utility functions for resolving various information is also
- * provided.
+ * can be used to create TCP/IP connections and servers. Various utility
+ * functions for resolving various information is also provided.
*
* On WIN32 systems the SILC Net API must initialized by calling the
* silc_net_win32_init and uninitialized when the application ends by
/* Prototypes */
-/****s* silcutil/SilcNetAPI/SilcNetListener
- *
- * NAME
- *
- * typedef struct SilcNetListenerStruct *SilcNetListener;
- *
- * DESCRIPTION
- *
- * The network listenr context. This context is created with the
- * silc_net_create_listener function and destroyed with
- * silc_net_close_listener function.
- *
- ***/
-typedef struct SilcNetListenerStruct *SilcNetListener;
-
-/****d* silcutil/SilcNetAPI/SilcNetStatus
- *
- * NAME
- *
- * typedef enum { ... } SilcNetStatus;
- *
- * DESCRIPTION
- *
- * Status to indicate the result of the network operation creation. This
- * type is returned in the SilcNetCallback callback function.
- *
- * SOURCE
- */
-typedef enum {
- SILC_NET_OK, /* Everything Ok */
- SILC_NET_UNKNOWN_IP, /* Unknown IP address */
- SILC_NET_UNKNOWN_HOST, /* Unknown hostname */
- SILC_NET_HOST_UNREACHABLE, /* Destination unreachable */
- SILC_NET_CONNECTION_REFUSED, /* Connection refused */
- SILC_NET_CONNECTION_TIMEOUT, /* Connection timedout */
- SILC_NET_NO_MEMORY, /* System out of memory */
- SILC_NET_ERROR, /* Unknown error */
-} SilcNetStatus;
-/***/
-
-/****f* silcutil/SilcNetAPI/SilcNetCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcNetCallback)(SilcNetStatus status,
- * SilcStream stream, void *context);
- *
- * DESCRIPTION
- *
- * A callback of this type is returned by silc_net_tcp_create_listener
- * and silc_net_tcp_connect functions. For silc_net_tcp_create_listener
- * this callback means that new incoming connection was accepted, and the
- * `stream' is the socket stream representing the socket connection.
- *
- * For silc_net_tcp_connect this means that we have connected to the
- * remote host and the `stream' is the socket stream for the socket
- * connection. The SILC Stream API (such as silc_stream_read, etc.) can
- * be used to read and write to the stream. The created stream is socket
- * stream so various SilcSocketStream API functions can be used with
- * the `stream'.
- *
- ***/
-typedef void (*SilcNetCallback)(SilcNetStatus status,
- SilcStream stream, void *context);
-
-/****f* silcutil/SilcNetAPI/silc_net_tcp_create_listener
- *
- * SYNOPSIS
- *
- * SilcNetListener
- * silc_net_tcp_create_listener(const char **local_ip_addr,
- * SilcUInt32 local_ip_count, int port,
- * SilcBool lookup, SilcBool require_fqdn,
- * SilcSchedule schedule,
- * SilcNetCallback callback, void *context);
- *
- * DESCRIPTION
- *
- * This function creates TCP listener. This is used to create network
- * listener for incoming connections, and `callback' will be called
- * everytime new connection is received. If `local_ip_addr' is NULL any
- * address is used. If provided it can be used bind the listener to
- * `local_ip_count' many IP addresses provided in `local_ip_addr' table.
- * On success returns the SilcNetListener context, or NULL on error.
- * If `require_fqdn' is TRUE the listener will require that the incoming
- * connection has FQDN to be able to connect. If the `lookup' is TRUE
- * then the incoming connection hostname will be resolved. If the `port'
- * is zero (0), operating system will define it automatically.
- *
- * The `callback' always delivers valid new stream. It is not called
- * with an error status.
- *
- ***/
-SilcNetListener
-silc_net_tcp_create_listener(const char **local_ip_addr,
- SilcUInt32 local_ip_count, int port,
- SilcBool lookup, SilcBool require_fqdn,
- SilcSchedule schedule,
- SilcNetCallback callback, void *context);
-
-/****f* silcutil/SilcNetAPI/silc_net_listener_get_port
- *
- * SYNOPSIS
- *
- * SilcUInt16 silc_net_listener_get_port(SilcNetListener listener);
- *
- * DESCRIPTION
- *
- * Returns the ports to where the `listener' is bound. This can be used
- * to get the port if none was specified in silc_net_tcp_create_listener.
- * Returns an array of ports of size of `port_count'. The caller must
- * free the array with silc_free. There are as many ports in the array
- * as there were IP addresses provided in silc_net_tcp_create_listener.
- *
- ***/
-SilcUInt16 *silc_net_listener_get_port(SilcNetListener listener,
- SilcUInt32 *port_count);
-
-/****f* silcutil/SilcNetAPI/silc_net_close_listener
+/****f* silcutil/SilcNetAPI/silc_net_create_server
*
* SYNOPSIS
*
- * void silc_net_close_listener(SilcNetListener listener);
+ * int silc_net_create_server(int port, char *ip_addr);
*
* DESCRIPTION
*
- * Closes the network listener indicated by `listener'.
+ * This function creates server or daemon or listener or what ever. This
+ * does not fork a new process, it must be done by the caller if caller
+ * wants to create a child process. This is used by the SILC server.
+ * If argument `ip_addr' is NULL `any' address will be used. Returns
+ * the created socket or -1 on error.
*
***/
-void silc_net_close_listener(SilcNetListener listener);
+int silc_net_create_server(int port, const char *ip_addr);
-/****f* silcutil/SilcNetAPI/silc_net_tcp_connect
+/****f* silcutil/SilcNetAPI/silc_net_close_server
*
* SYNOPSIS
*
- * SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
- * const char *remote_ip_addr,
- * int remote_port,
- * SilcSchedule schedule,
- * SilcNetCallback callback,
- * void *context);
+ * void silc_net_close_server(int sock);
*
* DESCRIPTION
*
- * Creates TCP/IP connection to the remote host indicated by `remote_host'
- * which may be hostname or IP address, on the port indicated by
- * `remote_port'. If the `local_ip_addr' is provided the local host is
- * bound to that address before creating the connection. This is
- * asynchronous call, and this function returns before the connection is
- * actually established. The `callback' will be called after the
- * connection is created to deliver the SilcStream for the created
- * connection. This function supports IPv6 if the platform supports it.
- *
- * The returned SilcAsyncOperation context can be used to control the
- * asynchronous connecting, such as to abort it. If it is aborted
- * using silc_async_abort the `callback' will not be called. If NULL
- * is returned the operation cannot be aborted.
+ * Closes the server by closing the socket connection.
*
***/
-SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
- const char *remote_ip_addr,
- int remote_port,
- SilcSchedule schedule,
- SilcNetCallback callback,
- void *context);
+void silc_net_close_server(int sock);
-/****f* silcutil/SilcNetAPI/silc_net_udp_connect
+/****f* silcutil/SilcNetAPI/silc_net_create_connection
*
* SYNOPSIS
*
- * SilcStream
- * silc_net_udp_connect(const char *local_ip_addr, int local_port,
- * const char *remote_ip_addr, int remote_port,
- * SilcSchedule schedule);
+ * int silc_net_create_connection(const char *local_ip, int port,
+ * const char *host);
*
* DESCRIPTION
*
- * This function creates UDP stream. The UDP stream is bound to the
- * `local_ip_addr' if it is specified. If `local_port' is non-zero the
- * stream is bound to that port. If the `remote_ip_addr' and `remote_port'
- * is also provided, packets may be sent to that address using
- * silc_stream_write function and packets may be received using
- * silc_stream_read function.
- *
- * If the remote address is not provided the stream is in connectionless
- * state. This means that packets can be received only by using
- * silc_net_udp_receive and sent only by using the function
- * silc_net_udp_send.
- *
- * To receive packets the silc_stream_set_notifier must be called for the
- * returned SilcStream. The packets are always received in the notifier
- * callback when the SILC_STREAM_CAN_READ is returned to the callback
- * To read the packet use silc_stream_read if the remote address was
- * provided, and silc_net_udp_receive if it was not.
- *
- * Supports IPv6 if the platform supports it.
- *
- * EXAMPLE
- *
- * SilcStream udpstream;
- *
- * // Create UDP stream and prepare to receive packets
- * udpstream = silc_net_udp_connect("10.2.1.7", 5000,
- * "10.2.1.100, 5000, schedule);
- * silc_stream_set_notifier(udpstream, schedule, receive_callback, context);
- *
- * // Send packet to remote host
- * silc_stream_write(udpstream, data, data_len);
- *
- * Create UDP listener:
- *
- * udpstream = silc_net_udp_connect("0.0.0.0", 500, NULL, 0, schedule);
- * silc_stream_set_notifier(udpstream, schedule, receive_callback, context);
+ * Creates a connection (TCP/IP) to a remote host. Returns the connection
+ * socket or -1 on error. This blocks the process while trying to create
+ * the connection. If the `local_ip' is not NULL then this will bind
+ * the `local_ip' address to a port before creating the connection. If
+ * it is NULL then this will directly create the connection.
*
***/
-SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port,
- const char *remote_ip_addr, int remote_port,
- SilcSchedule schedule);
+int silc_net_create_connection(const char *localhost, int port,
+ const char *host);
-/****f* silcutil/SilcNetAPI/silc_net_udp_receive
+/****f* silcutil/SilcNetAPI/silc_net_create_connection_async
*
* SYNOPSIS
*
- * int
- * silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
- * SilcUInt32 remote_ip_addr_size, int *remote_port,
- * unsigned char *ret_data, SilcUInt32 data_size)
+ * int silc_net_create_connection_async(const char *local_ip, int port,
+ * const char *host);
*
* DESCRIPTION
*
- * Receive a UDP packet from the `stream'. The IP address and port of
- * the sender is returned into `remote_ip_addr' buffer and `remote_port'
- * pointer. The packet data is returned into the `ret_data' buffer.
- *
- * Returns the length of the packet, or -1 on error or 0 in case of EOF.
+ * Creates a connection (TCP/IP) to a remote host. Returns the connection
+ * socket or -1 on error. This creates non-blocking socket hence the
+ * connection returns directly. To get the result of the connect() one
+ * must select() the socket and read the result after it's ready. If the
+ * `local_ip' is not NULL then this will bind the `local_ip' address to
+ * a port before creating the connection. If it is NULL then this will
+ * directly create the connection.
*
***/
-int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
- SilcUInt32 remote_ip_addr_size, int *remote_port,
- unsigned char *ret_data, SilcUInt32 data_size);
+int silc_net_create_connection_async(const char *local_ip, int port,
+ const char *host);
-/****f* silcutil/SilcNetAPI/silc_net_udp_send
+/****f* silcutil/SilcNetAPI/silc_net_close_connection
*
* SYNOPSIS
*
- * int silc_net_udp_send(SilcStream stream,
- * const char *remote_ip_addr, int remote_port,
- * const unsigned char *data, SilcUInt32 data_len);
+ * void silc_net_close_connection(int sock);
*
* DESCRIPTION
*
- * Sends an UDP packet to remote host `remote_ip_addr' on `remote_port'.
- * This may be used with UDP streams that are not connected to any
- * specific remote host. With those stream silc_stream_write cannot be
- * used. In those cases, this function must be used. This may also be
- * used even if the stream is connected.
- *
- * Returns the amount of data written, -1 if data could not be written
- * at this moment, or -2 if error occurred. If -1 is returned the
- * notifier callback will later be called with SILC_STREAM_CAN_WRITE
- * status when stream is again ready for writing.
+ * Closes the connection by closing the socket connection.
*
***/
-int silc_net_udp_send(SilcStream stream,
- const char *remote_ip_addr, int remote_port,
- const unsigned char *data, SilcUInt32 data_len);
+void silc_net_close_connection(int sock);
-/****f* silcutil/SilcNetAPI/silc_net_close_connection
+/****f* silcutil/SilcNetAPI/silc_net_accept_connection
*
* SYNOPSIS
*
- * void silc_net_close_connection(int sock);
+ * int silc_net_accept_connection(int sock);
*
* DESCRIPTION
*
- * Closes the connection by closing the socket connection. This routine
- * can only be used with POSIX compliant systems.
+ * Accepts a connection from a particular socket.
*
***/
-void silc_net_close_connection(int sock);
+int silc_net_accept_connection(int sock);
-/****f* silcutil/SilcNetAPI/silc_net_accept_connection
+/****f* silcutil/SilcNetAPI/silc_net_set_socket_nonblock
*
* SYNOPSIS
*
- * int silc_net_accept_connection(int sock);
+ * int silc_net_set_socket_nonblock(int sock);
*
* DESCRIPTION
*
- * Accepts a connection from a particular socket. This routine can only
- * be used with POSIX compliant systems. This call is equivalent to
- * accept(2).
+ * Sets the socket to non-blocking mode.
*
***/
-int silc_net_accept_connection(int sock);
+int silc_net_set_socket_nonblock(int sock);
/****f* silcutil/SilcNetAPI/silc_net_set_socket_opt
*
*
* Sets a option for a socket. This function can be used to set
* various options for the socket. Some of the options might be
- * system specific. This routine can only be used with POSIX compliant
- * systems. This call is equivalent to setsockopt(2);
+ * system specific.
*
***/
int silc_net_set_socket_opt(int sock, int level, int option, int on);
*
* SYNOPSIS
*
- * int silc_net_get_socket_opt(int sock, int level, int option,
+ * int silc_net_get_socket_opt(int sock, int level, int option,
* void *optval, int *opt_len);
*
* DESCRIPTION
*
- * Return socket options to the `optval' and `opt_len'. This routine
- * can only be used with POSIX compliant systems. This call is
- * equivalent to getsockopt(2).
+ * Return socket options to the `optval' and `opt_len'.
*
***/
-int silc_net_get_socket_opt(int sock, int level, int option,
+int silc_net_get_socket_opt(int sock, int level, int option,
void *optval, int *opt_len);
-/****f* silcutil/SilcNetAPI/silc_net_set_socket_nonblock
- *
- * SYNOPSIS
- *
- * int silc_net_set_socket_nonblock(SilcSocket sock);
- *
- * DESCRIPTION
- *
- * Sets the socket `sock' to non-blocking mode.
- *
- ***/
-int silc_net_set_socket_nonblock(SilcSocket sock);
-
/****f* silcutil/SilcNetAPI/silc_net_is_ip4
*
* SYNOPSIS
*
- * SilcBool silc_net_is_ip4(const char *addr);
+ * bool silc_net_is_ip4(const char *addr);
*
* DESCRIPTION
*
* Checks whether IP address sent as argument is valid IPv4 address.
*
***/
-SilcBool silc_net_is_ip4(const char *addr);
+bool silc_net_is_ip4(const char *addr);
/****f* silcutil/SilcNetAPI/silc_net_is_ip6
*
* SYNOPSIS
*
- * SilcBool silc_net_is_ip6(const char *addr);
+ * bool silc_net_is_ip6(const char *addr);
*
* DESCRIPTION
*
* Checks whether IP address sent as argument is valid IPv6 address.
*
***/
-SilcBool silc_net_is_ip6(const char *addr);
+bool silc_net_is_ip6(const char *addr);
/****f* silcutil/SilcNetAPI/silc_net_is_ip
*
* SYNOPSIS
*
- * SilcBool silc_net_is_ip(const char *addr);
+ * bool silc_net_is_ip(const char *addr);
*
* DESCRIPTION
*
* This supports both IPv4 and IPv6 addresses.
*
***/
-SilcBool silc_net_is_ip(const char *addr);
+bool silc_net_is_ip(const char *addr);
/****f* silcutil/SilcNetAPI/silc_net_addr2bin
*
* SYNOPSIS
*
- * SilcBool silc_net_addr2bin(const char *addr, void *bin,
- * SilcUInt32 bin_len);
+ * bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len);
*
* DESCRIPTION
*
* IPv4 or IPv6 address.
*
***/
-SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len);
+bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len);
/****f* silcutil/SilcNetAPI/SilcNetResolveCallback
*
* SYNOPSIS
*
- * typedef void (*SilcNetResolveCallback)(const char *result,
+ * typedef void (*SilcNetResolveCallback)(const char *result,
* void *context);
*
* DESCRIPTION
*
* SYNOPSIS
*
- * SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6,
+ * bool silc_net_gethostbyname(const char *name, bool prefer_ipv6,
* char *address, SilcUInt32 address_len);
*
* DESCRIPTION
* address also.
*
***/
-SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6,
- char *address, SilcUInt32 address_len);
+bool silc_net_gethostbyname(const char *name, bool prefer_ipv6, char *address,
+ SilcUInt32 address_len);
/****f* silcutil/SilcNetAPI/silc_net_gethostbyname_async
*
* SYNOPSIS
*
- * void silc_net_gethostbyname_async(const char *name,
- * SilcBool prefer_ipv6,
+ * void silc_net_gethostbyname_async(const char *name,
+ * bool prefer_ipv6,
* SilcSchedule schedule,
* SilcNetResolveCallback completion,
* void *context)
* address also.
*
***/
-void silc_net_gethostbyname_async(const char *name,
- SilcBool prefer_ipv6,
+void silc_net_gethostbyname_async(const char *name,
+ bool prefer_ipv6,
SilcSchedule schedule,
SilcNetResolveCallback completion,
void *context);
*
* SYNOPSIS
*
- * SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
+ * bool silc_net_gethostbyaddr(const char *addr, char *name,
* SilcUInt32 name_len);
*
* DESCRIPTION
*
* Resolves the hostname for the IP address indicated by the `addr'
- * This returns TRUE and the resolved hostname to the `name' buffer,
+ * This returns TRUE and the resolved hostname to the `name' buffer,
* or FALSE on error. The `addr' may be either IPv4 or IPv6 address.
* This is synchronous function and will block the calling process.
*
***/
-SilcBool silc_net_gethostbyaddr(const char *addr, char *name,
- SilcUInt32 name_len);
+bool silc_net_gethostbyaddr(const char *addr, char *name, SilcUInt32 name_len);
/****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr_async
*
* SYNOPSIS
*
- * void silc_net_gethostbyaddr_async(const char *addr,
+ * void silc_net_gethostbyaddr_async(const char *addr,
* SilcSchedule schedule,
* SilcNetResolveCallback completion,
* void *context)
* completed.
*
***/
-void silc_net_gethostbyaddr_async(const char *addr,
+void silc_net_gethostbyaddr_async(const char *addr,
SilcSchedule schedule,
SilcNetResolveCallback completion,
void *context);
*
* SYNOPSIS
*
- * SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
- * char **ip);
+ * bool silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
*
* DESCRIPTION
*
* lookup as well to verify that the IP has FQDN.
*
***/
-SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
- char **ip);
+bool silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
/****f* silcutil/SilcNetAPI/silc_net_check_local_by_sock
*
* SYNOPSIS
*
- * SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
- * char **ip);
+ * bool silc_net_check_local_by_sock(int sock, char **hostname, char **ip);
*
* DESCRIPTION
*
* lookup as well to verify that the IP has FQDN.
*
***/
-SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
- char **ip);
+bool silc_net_check_local_by_sock(int sock, char **hostname, char **ip);
/****f* silcutil/SilcNetAPI/silc_net_get_remote_port
*
* SYNOPSIS
*
- * SilcUInt16 silc_net_get_remote_port(SilcSocket sock);
+ * SilcUInt16 silc_net_get_remote_port(int sock);
*
* DESCRIPTION
*
* Return remote port by socket.
*
***/
-SilcUInt16 silc_net_get_remote_port(SilcSocket sock);
+SilcUInt16 silc_net_get_remote_port(int sock);
/****f* silcutil/SilcNetAPI/silc_net_get_local_port
*
* SYNOPSIS
*
- * SilcUInt16 silc_net_get_local_port(SilcSocket sock);
+ * SilcUInt16 silc_net_get_local_port(int sock);
*
* DESCRIPTION
*
* Return local port by socket.
*
***/
-SilcUInt16 silc_net_get_local_port(SilcSocket sock);
+SilcUInt16 silc_net_get_local_port(int sock);
/****f* silcutil/SilcNetAPI/silc_net_localhost
*
*
* SYNOPSIS
*
- * SilcBool silc_net_win32_init(void);
+ * bool silc_net_win32_init(void);
*
* DESCRIPTION
*
* This routines is available only on Win32 platform.
*
***/
-SilcBool silc_net_win32_init(void);
+bool silc_net_win32_init(void);
/****f* silcutil/SilcNetAPI/silc_net_win32_uninit
*
***/
void silc_net_win32_uninit(void);
-#include "silcnet_i.h"
-
-#endif /* SILCNET_H */
+#endif
+++ /dev/null
-/*
-
- silcnet_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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 SILCNET_I_H
-#define SILCNET_I_H
-
-#ifndef SILCNET_H
-#error "Do not include this header directly"
-#endif
-
-/* Net listener context */
-struct SilcNetListenerStruct {
- SilcSchedule schedule;
- SilcNetCallback callback;
- void *context;
- SilcSocket *socks;
- unsigned int socks_count : 30;
- unsigned int require_fqdn : 1;
- unsigned int lookup : 1;
-};
-
-#endif /* SILCNET_I_H */
--- /dev/null
+/*
+
+ silcprotocol.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.
+
+*/
+/*
+ * Created: Tue Nov 25 19:25:33 GMT+0200 1997
+ */
+/* $Id$ */
+
+#include "silcincludes.h"
+
+/* Dynamically registered protocols */
+SilcProtocolObject *silc_protocol_list = NULL;
+
+/* Dynamically registers new protocol. The protocol is added into protocol
+ list and can be unregistered with silc_protocol_unregister. */
+
+void silc_protocol_register(SilcProtocolType type,
+ SilcProtocolCallback callback)
+{
+ SilcProtocolObject *proto_new;
+
+ proto_new = silc_calloc(1, sizeof(*proto_new));
+ proto_new->type = type;
+ proto_new->callback = callback;
+
+ if (!silc_protocol_list)
+ silc_protocol_list = proto_new;
+ else {
+ proto_new->next = silc_protocol_list;
+ silc_protocol_list = proto_new;
+ }
+}
+
+/* Unregisters protocol. The unregistering is done by both protocol type
+ and the protocol callback. */
+
+void silc_protocol_unregister(SilcProtocolType type,
+ SilcProtocolCallback callback)
+{
+ SilcProtocolObject *protocol, *prev;
+
+ protocol = silc_protocol_list;
+ prev = NULL;
+ while (protocol && (protocol->type != type &&
+ protocol->callback != callback)) {
+ prev = protocol;
+ protocol = protocol->next;
+ }
+
+ if (protocol) {
+ if (prev)
+ prev->next = protocol->next;
+ else
+ silc_protocol_list = protocol->next;
+
+ silc_free(protocol);
+ }
+}
+
+/* Allocates a new protocol object. The new allocated and initialized
+ protocol is returned to the new_protocol argument. The argument context
+ is the context to be sent as argument for the protocol. The callback
+ argument is the function to be called _after_ the protocol has finished. */
+
+void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
+ void *context, SilcProtocolFinalCallback callback)
+{
+ SilcProtocolObject *protocol;
+
+ SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
+
+ protocol = silc_protocol_list;
+ while (protocol && protocol->type != type)
+ protocol = protocol->next;
+
+ if (!protocol) {
+ SILC_LOG_ERROR(("Requested protocol does not exists"));
+ *new_protocol = NULL;
+ return;
+ }
+
+ *new_protocol = silc_calloc(1, sizeof(**new_protocol));
+ (*new_protocol)->protocol = protocol;
+ (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
+ (*new_protocol)->context = context;
+ (*new_protocol)->final_callback = callback;
+}
+
+/* Frees a protocol object. */
+
+void silc_protocol_free(SilcProtocol protocol)
+{
+ if (protocol)
+ silc_free(protocol);
+}
+
+/* Executes next state of the protocol. The state must be set before
+ calling this function. */
+
+void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
+ long secs, long usecs)
+{
+ if (secs + usecs)
+ silc_schedule_task_add(schedule, 0,
+ protocol->protocol->callback, (void *)protocol,
+ secs, usecs,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ else
+ protocol->protocol->callback(schedule, silc_schedule_get_context(schedule),
+ 0, 0, (void *)protocol);
+}
+
+/* Executes the final callback of the protocol. */
+
+void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule)
+{
+ protocol->final_callback(schedule, silc_schedule_get_context(schedule),
+ 0, 0, (void *)protocol);
+}
+
+/* Cancels the execution of the next state of the protocol. */
+
+void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule)
+{
+ silc_schedule_task_del_by_context(schedule, protocol);
+}
--- /dev/null
+/*
+
+ silcprotocol.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* silccore/SILC Protocol Interface
+ *
+ * DESCRIPTION
+ *
+ * Implementation of the protocol handling routines for SILC applications.
+ * These routines allow execution of arbitrary protocols in the application.
+ * New protocols may be registered by type and allocated later by that
+ * type for the execution. The protocols implements a state machine style
+ * execution where each state is executed one after the other. The
+ * application controls these states and their order of execution.
+ *
+ * After the protocol has been executed, an final callback is called
+ * which the application may use to do post-protocol work or to start
+ * perhaps other protocols. These routines are generic and the actual
+ * protocols, their types, callback and final callbacks functions must
+ * be implemented in the application.
+ *
+ ***/
+
+#ifndef SILCPROTOCOL_H
+#define SILCPROTOCOL_H
+
+/****d* silccore/SilcProtocolAPI/SilcProtocolType
+ *
+ * NAME
+ *
+ * typedef unsigned char SilcProtocolType;
+ *
+ * DESCRIPTION
+ *
+ * Protocol type definition. The protocol types are application
+ * specific and this is just a generic type for them.
+ *
+ ***/
+typedef unsigned char SilcProtocolType;
+
+/****d* silccore/SilcProtocolAPI/SilcProtocolState
+ *
+ * NAME
+ *
+ * typedef unsigned char SilcProtocolState;
+ *
+ * DESCRIPTION
+ *
+ * Protocol state definition and the defined protocol states. These
+ * states are the generic states. However, each protocol actually
+ * implements the states. The state after SILC_PROTOCOL_STATE_START
+ * would be state 2 in the application. These states can be easily
+ * used for example inside switch() statement.
+ *
+ * EXAMPLE
+ *
+ * switch (protocol->state) {
+ * case SILC_PROTOCOL_STATE_START:
+ * protocol_starts_here();
+ * case 2:
+ * ...
+ * case 3:
+ * ...
+ * case SILC_PROTOCOL_STATE_END:
+ * protocol_ends_here();
+ * case SILC_PROTOCOL_STATE_FAILURE:
+ * remote_end_sent_failure();
+ * case SILC_PROTOCOL_STATE_ERROR:
+ * local_error_during_protocol();
+ * }
+ *
+ * SOURCE
+ */
+typedef unsigned char SilcProtocolState;
+
+/* Protocol states. Do NOT change the values of these states, especially
+ the START state or you break every protocol. */
+#define SILC_PROTOCOL_STATE_UNKNOWN 0
+#define SILC_PROTOCOL_STATE_START 1
+#define SILC_PROTOCOL_STATE_END 252
+#define SILC_PROTOCOL_STATE_FAILURE 253 /* Received failure from remote */
+#define SILC_PROTOCOL_STATE_ERROR 254 /* Local error at our end */
+/***/
+
+/* Type definition for authentication protocol's auth methods. */
+/* XXX strictly speaking this belongs to application */
+typedef unsigned char SilcProtocolAuthMeth;
+
+/****f* silccore/SilcProtocolAPI/SilcProtocolCallback
+ *
+ * SYNOPSIS
+ *
+ * typedef SilcTaskCallback SilcProtocolCallback;
+ *
+ * DESCRIPTION
+ *
+ * Protocol callback. This callback is set when registering new
+ * protocol. The callback is called everytime the protocol is executed.
+ * The `context' delivered to this callback function is the SilcProtocol
+ * context and needs to be explicitly type casted to SilcProtocol in
+ * the callback function.
+ *
+ ***/
+typedef SilcTaskCallback SilcProtocolCallback;
+
+/****f* silccore/SilcProtocolAPI/SilcProtocolFinalCallback
+ *
+ * SYNOPSIS
+ *
+ * typedef SilcTaskCallback SilcProtocolFinalCallback;
+ *
+ * DESCRIPTION
+ *
+ * Final protocol callback. This callback is set when allocating
+ * protocol for execution. This is called when the protocol has ended.
+ * The `context' delivered to this callback function is the SilcProtocol
+ * context and needs to be explicitly type casted to SilcProtocol in
+ * the callback function.
+ *
+ ***/
+typedef SilcTaskCallback SilcProtocolFinalCallback;
+
+/****s* silccore/SilcProtocolAPI/SilcProtocolObject
+ *
+ * NAME
+ *
+ * typedef struct SilcProtocolObjectStruct { ... } SilcProtocolObject;
+ *
+ * DESCRIPTION
+ *
+ * The object for one protocol. This hold the information of one
+ * registered protocol. Application must not allocate this type
+ * directly. It is used by the protocol routines.
+ *
+ * Short description of the field following:
+ *
+ * SilcProtocolType type
+ *
+ * Protocol type.
+ *
+ * SilcProtocolCallback callback;
+ *
+ * Callback function for the protocol. This is SilcTaskCallback function
+ * pointer as the protocols in SILC are executed as timeout tasks.
+ *
+ * struct SilcProtocolObjectStruct *next;
+ *
+ * Pointer to the next protocol.
+ *
+ ***/
+typedef struct SilcProtocolObjectStruct {
+ SilcProtocolType type;
+ SilcProtocolCallback callback;
+ struct SilcProtocolObjectStruct *next;
+} SilcProtocolObject;
+
+/****s* silccore/SilcProtocolAPI/SilcProtocol
+ *
+ * NAME
+ *
+ * typedef struct SilcProtocolStruct { ... } *SilcProtocol;
+ *
+ * DESCRIPTION
+ *
+ * The actual protocol object. This is allocated by the silc_protocol_alloc
+ * and holds the information about the current protocol. Information
+ * such as the current state, execution callback and final callback.
+ * The context is freed by silc_protocol_free function.
+ *
+ * Short description of the field following:
+ *
+ * SilcProtocolObject *protocol
+ *
+ * This is the pointer to the SilcProtocolObject and holds the
+ * protocol specific information.
+ *
+ * SilcProtocolState state
+ *
+ * Protocol state. The state of the protocol can be changed in the
+ * callback function.
+ *
+ * void *context
+ *
+ * Context to be sent for the callback function. This is usually
+ * object for either SILC client or server. However, this abstraction
+ * makes it possible that this pointer could be some other object as
+ * well. Note that the context is not delivered in any callback
+ * function. Application can access it through this context.
+ *
+ * SilcProtocolFinalCallback final_callback;
+ *
+ * This is a callback function that is called with timeout _after_ the
+ * protocol has finished or error occurs. If this is NULL, naturally
+ * nothing will be executed. Protocol should call this function only at
+ * SILC_PROTOCOL_STATE_END and SILC_PROTOCOL_STATE_ERROR states.
+ *
+ ***/
+typedef struct SilcProtocolStruct {
+ SilcProtocolObject *protocol;
+ SilcProtocolState state;
+ void *context;
+ SilcProtocolFinalCallback final_callback;
+} *SilcProtocol;
+
+/* Prototypes */
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_register
+ *
+ * SYNOPSIS
+ *
+ * void silc_protocol_register(SilcProtocolType type,
+ * SilcProtocolCallback callback);
+ *
+ * DESCRIPTION
+ *
+ * Dynamically registers new protocol. The protocol is added into protocol
+ * list and can be unregistered with silc_protocol_unregister. The
+ * `type' is the type of the protocol and is used to identify the
+ * protocol when allocating it with silc_protocol_alloc. The `callback'
+ * is the actual protocol function that is called when protocol is
+ * executed (and it performes the actual protocol). The protocol
+ * is unregistered by silc_protocol_unregister function.
+ *
+ ***/
+void silc_protocol_register(SilcProtocolType type,
+ SilcProtocolCallback callback);
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_unregister
+ *
+ * SYNOPSIS
+ *
+ * void silc_protocol_unregister(SilcProtocolType type,
+ * SilcProtocolCallback callback);
+ *
+ * DESCRIPTION
+ *
+ * Unregisters protocol. The unregistering is done by both protocol type
+ * and the protocol callback. Every registered protocol must be
+ * unregistered using this function.
+ *
+ ***/
+void silc_protocol_unregister(SilcProtocolType type,
+ SilcProtocolCallback callback);
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_alloc
+ *
+ * SYNOPSIS
+ *
+ * void silc_protocol_alloc(SilcProtocolType type,
+ * SilcProtocol *new_protocol,
+ * void *context,
+ * SilcProtocolFinalCallback callback);
+ *
+ * DESCRIPTION
+ *
+ * Allocates a new protocol. The new allocated and initialized
+ * protocol is returned to the `new_protocol' argument. The argument
+ * context `context' is the context to be sent as argument for the
+ * protocol callback function. The `callback' argument is the function
+ * to be called after the protocol has finished.
+ *
+ ***/
+void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
+ void *context, SilcProtocolFinalCallback callback);
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_protocol_free(SilcProtocol protocol);
+ *
+ * DESCRIPTION
+ *
+ * Frees the protocol context. This must be called for all allocated
+ * protocols.
+ *
+ ***/
+void silc_protocol_free(SilcProtocol protocol);
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_execute
+ *
+ * SYNOPSIS
+ *
+ * void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
+ * long secs, long usecs);
+ *
+ * DESCRIPTION
+ *
+ * Executes the protocol. This calls the state that has been set.
+ * The state must be set before calling this function. This is then
+ * also used to call always the next state after changing the state
+ * of the protocol. The `schedule' is the application's scheduler.
+ * It is passed to the protocol callback functions. The `secs' and
+ * `usecs' are the timeout before the protocol is executed. If both
+ * zero the protocol is executed immediately.
+ *
+ ***/
+void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
+ long secs, long usecs);
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_execute_final
+ *
+ * SYNOPSIS
+ *
+ * void
+ * silc_protocol_execute_final(SilcProtocol protocol,
+ * SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ * Executes the final callback for the protocol. The `schedule' is
+ * the application's scheduler.. It is passed to the protocol callback
+ * functions. The final callback is executed immediately.
+ *
+ ***/
+void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule);
+
+/****f* silccore/SilcProtocolAPI/silc_protocol_cancel
+ *
+ * SYNOPSIS
+ *
+ * void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ * Cancels the execution of the next state of the protocol. This has
+ * effect only if the silc_protocol_execute was called with timeout.
+ * It is guaranteed that if the protocol is cancelled before the timeout
+ * has elapsed the protocol callback won't be called.
+ *
+ ***/
+void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule);
+
+#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1998 - 2007 Pekka Riikonen
+ Copyright (C) 1998 - 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
+#include "silcschedule_i.h"
-/************************** Types and definitions ***************************/
+/* Forward declarations */
+typedef struct SilcTaskQueueStruct *SilcTaskQueue;
-/* Platform specific implementation */
-extern const SilcScheduleOps schedule_ops;
+/* System specific routines. Implemented under unix/, win32/ and such. */
-static void silc_schedule_task_remove(SilcSchedule schedule, SilcTask task);
-static void silc_schedule_dispatch_fd(SilcSchedule schedule);
-static void silc_schedule_dispatch_timeout(SilcSchedule schedule,
- SilcBool dispatch_all);
+/* System specific select(). Returns same values as normal select(). */
+int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count,
+ struct timeval *timeout);
+/* Initializes the platform specific scheduler. This for example initializes
+ the wakeup mechanism of the scheduler. In multi-threaded environment
+ the scheduler needs to be wakenup when tasks are added or removed from
+ the task queues. Returns context to the platform specific scheduler. */
+void *silc_schedule_internal_init(SilcSchedule schedule, void *context);
-/************************ Static utility functions **************************/
+/* Uninitializes the platform specific scheduler context. */
+void silc_schedule_internal_uninit(void *context);
-/* Fd task hash table destructor */
+/* Wakes up the scheduler. This is platform specific routine */
+void silc_schedule_internal_wakeup(void *context);
-static void silc_schedule_fd_destructor(void *key, void *context,
- void *user_context)
-{
- silc_free(context);
-}
+/* Register signal */
+void silc_schedule_internal_signal_register(void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context);
-/* Executes file descriptor tasks. Invalid tasks are removed here. */
+/* Unregister signal */
+void silc_schedule_internal_signal_unregister(void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context);
-static void silc_schedule_dispatch_fd(SilcSchedule schedule)
-{
- SilcTaskFd task;
- SilcTask t;
+/* Mark signal to be called later. */
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal);
- /* The dispatch list includes only valid tasks, and tasks that have
- something to dispatch. Dispatching is atomic; no matter if another
- thread invalidates a task when we unlock, we dispatch to completion. */
- SILC_SCHEDULE_UNLOCK(schedule);
- silc_list_start(schedule->fd_dispatch);
- while ((task = silc_list_get(schedule->fd_dispatch))) {
- t = (SilcTask)task;
-
- /* Is the task ready for reading */
- if (task->revents & SILC_TASK_READ)
- t->callback(schedule, schedule->app_context, SILC_TASK_READ,
- task->fd, t->context);
-
- /* Is the task ready for writing */
- if (t->valid && task->revents & SILC_TASK_WRITE)
- t->callback(schedule, schedule->app_context, SILC_TASK_WRITE,
- task->fd, t->context);
- }
- SILC_SCHEDULE_LOCK(schedule);
+/* Call all signals */
+void silc_schedule_internal_signals_call(void *context,
+ SilcSchedule schedule);
- /* Remove invalidated tasks */
- silc_list_start(schedule->fd_dispatch);
- while ((task = silc_list_get(schedule->fd_dispatch)))
- if (silc_unlikely(!task->header.valid))
- silc_schedule_task_remove(schedule, (SilcTask)task);
-}
+/* Block registered signals in scheduler. */
+void silc_schedule_internal_signals_block(void *context);
-/* Executes all tasks whose timeout has expired. The task is removed from
- the task queue after the callback function has returned. Also, invalid
- tasks are removed here. */
+/* Unblock registered signals in schedule. */
+void silc_schedule_internal_signals_unblock(void *context);
-static void silc_schedule_dispatch_timeout(SilcSchedule schedule,
- SilcBool dispatch_all)
-{
- SilcTask t;
- SilcTaskTimeout task;
- struct timeval curtime;
- int count = 0;
+/* Internal task management routines. */
- SILC_LOG_DEBUG(("Running timeout tasks"));
-
- silc_gettimeofday(&curtime);
-
- /* First task in the task queue has always the earliest timeout. */
- silc_list_start(schedule->timeout_queue);
- task = silc_list_get(schedule->timeout_queue);
- if (silc_unlikely(!task))
- return;
- do {
- t = (SilcTask)task;
-
- /* Remove invalid task */
- if (silc_unlikely(!t->valid)) {
- silc_schedule_task_remove(schedule, t);
- continue;
- }
-
- /* Execute the task if the timeout has expired */
- if (!silc_compare_timeval(&task->timeout, &curtime) && !dispatch_all)
- break;
-
- t->valid = FALSE;
- SILC_SCHEDULE_UNLOCK(schedule);
- t->callback(schedule, schedule->app_context, SILC_TASK_EXPIRE, 0,
- t->context);
- SILC_SCHEDULE_LOCK(schedule);
-
- /* Remove the expired task */
- silc_schedule_task_remove(schedule, t);
-
- /* Balance when we have lots of small timeouts */
- if (silc_unlikely((++count) > 40))
- break;
- } while (silc_likely((task = silc_list_get(schedule->timeout_queue))));
-}
-
-/* Calculates next timeout. This is the timeout value when at earliest some
- of the timeout tasks expire. If this is in the past, they will be
- dispatched now. */
-
-static void silc_schedule_select_timeout(SilcSchedule schedule)
-{
- SilcTask t;
- SilcTaskTimeout task;
- struct timeval curtime;
- SilcBool dispatch = TRUE;
+static void silc_schedule_dispatch_timeout(SilcSchedule schedule,
+ bool dispatch_all);
+static void silc_task_queue_alloc(SilcTaskQueue *queue);
+static void silc_task_queue_free(SilcTaskQueue queue);
+static SilcTask silc_task_find(SilcTaskQueue queue, SilcUInt32 fd);
+static SilcTask silc_task_add(SilcTaskQueue queue, SilcTask newtask,
+ SilcTaskPriority priority);
+static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first);
+static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask,
+ SilcTaskPriority priority);
+static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task);
+static void silc_task_del_by_context(SilcTaskQueue queue, void *context);
+static void silc_task_del_by_callback(SilcTaskQueue queue,
+ SilcTaskCallback callback);
+static void silc_task_del_by_fd(SilcTaskQueue queue, SilcUInt32 fd);
+
+/* Returns the task queue by task type */
+#define SILC_SCHEDULE_GET_QUEUE(type) \
+ (type == SILC_TASK_FD ? schedule->fd_queue : \
+ type == SILC_TASK_TIMEOUT ? schedule->timeout_queue : \
+ schedule->generic_queue)
+
+/* Locks. These also blocks signals that we care about and thus guarantee
+ that while we are in scheduler no signals can happen. This way we can
+ synchronise signals with SILC Scheduler. */
+#define SILC_SCHEDULE_LOCK(schedule) \
+do { \
+ silc_schedule_internal_signals_block(schedule->internal); \
+ silc_mutex_lock(schedule->lock); \
+} while (0)
+#define SILC_SCHEDULE_UNLOCK(schedule) \
+do { \
+ silc_mutex_unlock(schedule->lock); \
+ silc_schedule_internal_signals_unblock(schedule->internal); \
+} while (0)
+
+/* SILC Task object. Represents one task in the scheduler. */
+struct SilcTaskStruct {
+ SilcUInt32 fd;
+ SilcTaskCallback callback; /* Task callback */
+ void *context; /* Task callback context */
+ struct timeval timeout; /* Set for timeout tasks */
+ unsigned int valid : 1; /* Set when task is valid */
+ unsigned int priority : 2; /* Priority of the task */
+ unsigned int type : 5; /* Type of the task */
+
+ /* Pointers forming doubly linked circular list */
+ struct SilcTaskStruct *next;
+ struct SilcTaskStruct *prev;
+};
+
+/* SILC Task Queue object. The queue holds all the tasks in the scheduler.
+ There are always three task queues in the scheduler. One for non-timeout
+ tasks (fd tasks performing tasks over specified file descriptor),
+ one for timeout tasks and one for generic tasks. */
+struct SilcTaskQueueStruct {
+ SilcTask task; /* Pointer to all tasks */
+ struct timeval timeout; /* Current timeout */
+ SILC_MUTEX_DEFINE(lock); /* Queue's lock */
+};
- /* Get the current time */
- silc_gettimeofday(&curtime);
- schedule->has_timeout = FALSE;
+/*
+ SILC Scheduler structure.
- /* First task in the task queue has always the earliest timeout. */
- silc_list_start(schedule->timeout_queue);
- task = silc_list_get(schedule->timeout_queue);
- if (silc_unlikely(!task))
- return;
- do {
- t = (SilcTask)task;
+ This is the actual schedule object in SILC. Both SILC client and server
+ uses this same scheduler. Actually, this scheduler could be used by any
+ program needing scheduling.
- /* Remove invalid task */
- if (silc_unlikely(!t->valid)) {
- silc_schedule_task_remove(schedule, t);
- continue;
- }
+ Following short description of the fields:
- /* If the timeout is in past, we will run the task and all other
- timeout tasks from the past. */
- if (silc_compare_timeval(&task->timeout, &curtime) && dispatch) {
- silc_schedule_dispatch_timeout(schedule, FALSE);
- if (silc_unlikely(!schedule->valid))
- return;
+ SilcTaskQueue fd_queue
- /* Start selecting new timeout again after dispatch */
- silc_list_start(schedule->timeout_queue);
- dispatch = FALSE;
- continue;
- }
+ Task queue hook for non-timeout tasks. Usually this means that these
+ tasks perform different kind of I/O on file descriptors. File
+ descriptors are usually network sockets but they actually can be
+ any file descriptors. This hook is initialized in silc_schedule_init
+ function. Timeout tasks should not be added to this queue because
+ they will never expire.
- /* Calculate the next timeout */
- curtime.tv_sec = task->timeout.tv_sec - curtime.tv_sec;
- curtime.tv_usec = task->timeout.tv_usec - curtime.tv_usec;
- if (curtime.tv_sec < 0)
- curtime.tv_sec = 0;
-
- /* We wouldn't want to go under zero, check for it. */
- if (curtime.tv_usec < 0) {
- curtime.tv_sec -= 1;
- if (curtime.tv_sec < 0)
- curtime.tv_sec = 0;
- curtime.tv_usec += 1000000L;
- }
- break;
- } while ((task = silc_list_get(schedule->timeout_queue)));
+ SilcTaskQueue timeout_queue
- /* Save the timeout */
- if (task) {
- schedule->timeout = curtime;
- schedule->has_timeout = TRUE;
- SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule->timeout.tv_sec,
- schedule->timeout.tv_usec));
- }
-}
+ Task queue hook for timeout tasks. This hook is reserved specificly
+ for tasks with timeout. Non-timeout tasks should not be added to this
+ queue because they will never get scheduled. This hook is also
+ initialized in silc_schedule_init function.
-/* Removes task from the scheduler. This must be called with scheduler
- locked. */
+ SilcTaskQueue generic_queue
-static void silc_schedule_task_remove(SilcSchedule schedule, SilcTask task)
-{
- SilcTaskFd ftask;
-
- if (silc_unlikely(task == SILC_ALL_TASKS)) {
- SilcTask task;
- SilcHashTableList htl;
- SilcUInt32 fd;
-
- /* Delete from fd queue */
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, (void *)&fd, (void *)&task))
- silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(fd));
- silc_hash_table_list_reset(&htl);
-
- /* Delete from timeout queue */
- silc_list_start(schedule->timeout_queue);
- while ((task = silc_list_get(schedule->timeout_queue))) {
- silc_list_del(schedule->timeout_queue, task);
- silc_free(task);
- }
+ Task queue hook for generic tasks. This hook is reserved specificly
+ for generic tasks, tasks that apply to all file descriptors, except
+ to those that have specificly registered a non-timeout task. This hook
+ is also initialized in silc_schedule_init function.
- return;
- }
+ SilcScheduleFd fd_list
- if (silc_likely(task->type == 1)) {
- /* Delete from timeout queue */
- silc_list_del(schedule->timeout_queue, task);
+ List of file descriptors the scheduler is supposed to be listenning.
+ This is updated internally.
- /* Put to free list */
- silc_list_add(schedule->free_tasks, task);
- } else {
- /* Delete from fd queue */
- ftask = (SilcTaskFd)task;
- silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(ftask->fd));
- }
-}
+ SilcUInt32 max_fd
+ SilcUInt32 last_fd
-/* Timeout freelist garbage collection */
+ Size of the fd_list list. There can be `max_fd' many tasks in
+ the scheduler at once. The `last_fd' is the last valid entry
+ in the fd_list.
-SILC_TASK_CALLBACK(silc_schedule_timeout_gc)
-{
- SilcTaskTimeout t;
- int c;
+ struct timeval *timeout;
- if (!schedule->valid)
- return;
+ Pointer to the schedules next timeout. Value of this timeout is
+ automatically updated in the silc_schedule function.
- SILC_LOG_DEBUG(("Timeout freelist garbage collection"));
+ bool valid
- SILC_SCHEDULE_LOCK(schedule);
+ Marks validity of the scheduler. This is a boolean value. When this
+ is false the scheduler is terminated and the program will end. This
+ set to true when the scheduler is initialized with silc_schedule_init
+ function.
- if (silc_list_count(schedule->free_tasks) <= 10) {
- SILC_SCHEDULE_UNLOCK(schedule);
- silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
- schedule, 3600, 0);
- return;
- }
- if (silc_list_count(schedule->timeout_queue) >
- silc_list_count(schedule->free_tasks)) {
- SILC_SCHEDULE_UNLOCK(schedule);
- silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
- schedule, 3600, 0);
- return;
- }
+ fd_set in
+ fd_set out
- c = silc_list_count(schedule->free_tasks) / 2;
- if (c > silc_list_count(schedule->timeout_queue))
- c = (silc_list_count(schedule->free_tasks) -
- silc_list_count(schedule->timeout_queue));
- if (silc_list_count(schedule->free_tasks) - c < 10)
- c -= (10 - (silc_list_count(schedule->free_tasks) - c));
+ File descriptor sets for select(). These are automatically managed
+ by the scheduler and should not be touched otherwise.
- SILC_LOG_DEBUG(("Freeing %d unused tasks, leaving %d", c,
- silc_list_count(schedule->free_tasks) - c));
+ void *internal
- silc_list_start(schedule->free_tasks);
- while ((t = silc_list_get(schedule->free_tasks)) && c-- > 0) {
- silc_list_del(schedule->free_tasks, t);
- silc_free(t);
- }
- silc_list_start(schedule->free_tasks);
+ System specific scheduler context.
- SILC_SCHEDULE_UNLOCK(schedule);
+ SILC_MUTEX_DEFINE(lock)
- silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
- schedule, 3600, 0);
-}
+ Scheduler lock.
-#ifdef SILC_DIST_INPLACE
-/* Print schedule statistics to stdout */
+ bool signal_tasks
-void silc_schedule_stats(SilcSchedule schedule)
-{
- SilcTaskFd ftask;
- fprintf(stdout, "Schedule %p statistics:\n\n", schedule);
- fprintf(stdout, "Num FD tasks : %lu (%lu bytes allocated)\n",
- silc_hash_table_count(schedule->fd_queue),
- sizeof(*ftask) * silc_hash_table_count(schedule->fd_queue));
- fprintf(stdout, "Num Timeout tasks : %d (%d bytes allocated)\n",
- silc_list_count(schedule->timeout_queue),
- sizeof(struct SilcTaskTimeoutStruct) *
- silc_list_count(schedule->timeout_queue));
- fprintf(stdout, "Num Timeout freelist : %d (%d bytes allocated)\n",
- silc_list_count(schedule->free_tasks),
- sizeof(struct SilcTaskTimeoutStruct) *
- silc_list_count(schedule->free_tasks));
-}
-#endif /* SILC_DIST_INPLACE */
+ TRUE when tasks has been registered from signals. Next round in
+ scheduler will call the callbacks when this is TRUE.
-/****************************** Public API **********************************/
+*/
+struct SilcScheduleStruct {
+ void *app_context; /* Application specific context */
+ SilcTaskQueue fd_queue;
+ SilcTaskQueue timeout_queue;
+ SilcTaskQueue generic_queue;
+ SilcScheduleFd fd_list;
+ SilcUInt32 max_fd;
+ SilcUInt32 last_fd;
+ struct timeval *timeout;
+ bool valid;
+ void *internal;
+ SILC_MUTEX_DEFINE(lock);
+ bool is_locked;
+ bool signal_tasks;
+};
/* Initializes the scheduler. This returns the scheduler context that
is given as arugment usually to all silc_schedule_* functions.
SILC_LOG_DEBUG(("Initializing scheduler"));
schedule = silc_calloc(1, sizeof(*schedule));
- if (!schedule)
- return NULL;
- schedule->fd_queue =
- silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
- silc_schedule_fd_destructor, NULL, TRUE);
- if (!schedule->fd_queue) {
- silc_free(schedule);
- return NULL;
- }
+ /* Allocate three task queues, one for file descriptor based tasks,
+ one for timeout tasks and one for generic tasks. */
+ silc_task_queue_alloc(&schedule->fd_queue);
+ silc_task_queue_alloc(&schedule->timeout_queue);
+ silc_task_queue_alloc(&schedule->generic_queue);
- silc_list_init(schedule->timeout_queue, struct SilcTaskStruct, next);
- silc_list_init(schedule->free_tasks, struct SilcTaskStruct, next);
+ if (!max_tasks)
+ max_tasks = 200;
- schedule->app_context = app_context;
+ /* Initialize the scheduler */
+ schedule->fd_list = silc_calloc(max_tasks, sizeof(*schedule->fd_list));
+ schedule->max_fd = max_tasks;
+ schedule->timeout = NULL;
schedule->valid = TRUE;
- schedule->max_tasks = max_tasks;
+ schedule->app_context = app_context;
/* Allocate scheduler lock */
silc_mutex_alloc(&schedule->lock);
/* Initialize the platform specific scheduler. */
- schedule->internal = schedule_ops.init(schedule, app_context);
- if (!schedule->internal) {
- silc_hash_table_free(schedule->fd_queue);
- silc_mutex_free(schedule->lock);
- silc_free(schedule);
- return NULL;
- }
-
- /* Timeout freelist garbage collection */
- silc_schedule_task_add_timeout(schedule, silc_schedule_timeout_gc,
- schedule, 3600, 0);
+ schedule->internal = silc_schedule_internal_init(schedule, app_context);
return schedule;
}
scheduler could not be uninitialized. This happens when the scheduler
is still valid and silc_schedule_stop has not been called. */
-SilcBool silc_schedule_uninit(SilcSchedule schedule)
+bool silc_schedule_uninit(SilcSchedule schedule)
{
- SilcTask task;
-
SILC_LOG_DEBUG(("Uninitializing scheduler"));
if (schedule->valid == TRUE)
/* Dispatch all timeouts before going away */
SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(schedule->timeout_queue->lock);
silc_schedule_dispatch_timeout(schedule, TRUE);
+ silc_mutex_unlock(schedule->timeout_queue->lock);
SILC_SCHEDULE_UNLOCK(schedule);
/* Deliver signals before going away */
if (schedule->signal_tasks) {
- schedule_ops.signals_call(schedule, schedule->internal);
+ silc_schedule_internal_signals_call(schedule->internal, schedule);
schedule->signal_tasks = FALSE;
}
/* Unregister all tasks */
- silc_schedule_task_del(schedule, SILC_ALL_TASKS);
- silc_schedule_task_remove(schedule, SILC_ALL_TASKS);
-
- /* Delete timeout task freelist */
- silc_list_start(schedule->free_tasks);
- while ((task = silc_list_get(schedule->free_tasks)))
- silc_free(task);
+ silc_schedule_task_remove(schedule->fd_queue, SILC_ALL_TASKS);
+ silc_schedule_task_remove(schedule->timeout_queue, SILC_ALL_TASKS);
+ silc_schedule_task_remove(schedule->generic_queue, SILC_ALL_TASKS);
/* Unregister all task queues */
- silc_hash_table_free(schedule->fd_queue);
+ silc_task_queue_free(schedule->fd_queue);
+ silc_task_queue_free(schedule->timeout_queue);
+ silc_task_queue_free(schedule->generic_queue);
+
+ silc_free(schedule->fd_list);
/* Uninit the platform specific scheduler. */
- schedule_ops.uninit(schedule, schedule->internal);
+ silc_schedule_internal_uninit(schedule->internal);
silc_mutex_free(schedule->lock);
silc_free(schedule);
return TRUE;
}
+/* Enlarge the capabilities of the scheduler to handle tasks to `max_tasks'. */
+
+bool silc_schedule_reinit(SilcSchedule schedule, int max_tasks)
+{
+ SILC_SCHEDULE_LOCK(schedule);
+ if (schedule->max_fd <= max_tasks)
+ return FALSE;
+ schedule->fd_list = silc_realloc(schedule->fd_list,
+ (sizeof(*schedule->fd_list) * max_tasks));
+ schedule->max_fd = max_tasks;
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return TRUE;
+}
+
/* Stops the schedule even if it is not supposed to be stopped yet.
After calling this, one should call silc_schedule_uninit (after the
silc_schedule has returned). */
SILC_SCHEDULE_UNLOCK(schedule);
}
-/* Runs the scheduler once and then returns. Must be called locked. */
+/* Executes nontimeout tasks. It then checks whether any of ther fd tasks
+ was signaled by the silc_select. If some task was not signaled then
+ all generic tasks are executed for that task. The generic tasks are
+ never executed for task that has explicit fd task set. */
+/* This holds the schedule->lock and the queue locks. */
-static SilcBool silc_schedule_iterate(SilcSchedule schedule, int timeout_usecs)
+static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
{
- struct timeval timeout;
- int ret;
+ SilcTask task;
+ int i;
+ SilcUInt32 fd, last_fd = schedule->last_fd;
+ SilcUInt16 revents;
- do {
- SILC_LOG_DEBUG(("In scheduler loop"));
+ for (i = 0; i <= last_fd; i++) {
+ if (schedule->fd_list[i].events == 0)
+ continue;
- /* Deliver signals if any has been set to be called */
- if (silc_unlikely(schedule->signal_tasks)) {
- SILC_SCHEDULE_UNLOCK(schedule);
- schedule_ops.signals_call(schedule, schedule->internal);
- schedule->signal_tasks = FALSE;
- SILC_SCHEDULE_LOCK(schedule);
- }
+ /* First check whether this fd has task in the fd queue */
+ silc_mutex_lock(schedule->fd_queue->lock);
+ fd = schedule->fd_list[i].fd;
+ task = silc_task_find(schedule->fd_queue, fd);
+ revents = schedule->fd_list[i].revents;
+
+ /* If the task was found then execute its callbacks. If not then
+ execute all generic tasks for that fd. */
+ if (task) {
+ /* Validity of the task is checked always before and after
+ execution beacuse the task might have been unregistered
+ in the callback function, ie. it is not valid anymore. */
+
+ /* Is the task ready for reading */
+ if (task->valid && revents & SILC_TASK_READ) {
+ silc_mutex_unlock(schedule->fd_queue->lock);
+ SILC_SCHEDULE_UNLOCK(schedule);
+ task->callback(schedule, schedule->app_context,
+ SILC_TASK_READ, task->fd, task->context);
+ SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(schedule->fd_queue->lock);
+ }
- /* Check if scheduler is valid */
- if (silc_unlikely(schedule->valid == FALSE)) {
- SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
- return FALSE;
- }
+ /* Is the task ready for writing */
+ if (task->valid && revents & SILC_TASK_WRITE) {
+ silc_mutex_unlock(schedule->fd_queue->lock);
+ SILC_SCHEDULE_UNLOCK(schedule);
+ task->callback(schedule, schedule->app_context,
+ SILC_TASK_WRITE, task->fd, task->context);
+ SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(schedule->fd_queue->lock);
+ }
- /* Calculate next timeout for silc_select(). This is the timeout value
- when at earliest some of the timeout tasks expire. This may dispatch
- already expired timeouts. */
- silc_schedule_select_timeout(schedule);
+ if (!task->valid)
+ silc_schedule_task_remove(schedule->fd_queue, task);
- /* Check if scheduler is valid */
- if (silc_unlikely(schedule->valid == FALSE)) {
- SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
- return FALSE;
+ silc_mutex_unlock(schedule->fd_queue->lock);
+ } else {
+ /* Run generic tasks for this fd. */
+
+ silc_mutex_unlock(schedule->fd_queue->lock);
+
+ silc_mutex_lock(schedule->generic_queue->lock);
+ if (!schedule->generic_queue->task) {
+ silc_mutex_unlock(schedule->generic_queue->lock);
+ continue;
+ }
+
+ task = schedule->generic_queue->task;
+ while(1) {
+ /* Validity of the task and fd is checked always before and after
+ execution beacuse the task might have been unregistered
+ in the callback function, ie. it is not valid anymore. */
+
+ /* Is the task ready for reading */
+ if (task->valid && revents & SILC_TASK_READ &&
+ fd == schedule->fd_list[i].fd) {
+ silc_mutex_unlock(schedule->generic_queue->lock);
+ SILC_SCHEDULE_UNLOCK(schedule);
+ task->callback(schedule, schedule->app_context,
+ SILC_TASK_READ, fd, task->context);
+ SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(schedule->generic_queue->lock);
+ }
+
+ /* Is the task ready for writing */
+ if (task->valid && revents & SILC_TASK_WRITE &&
+ fd == schedule->fd_list[i].fd) {
+ silc_mutex_unlock(schedule->generic_queue->lock);
+ SILC_SCHEDULE_UNLOCK(schedule);
+ task->callback(schedule, schedule->app_context,
+ SILC_TASK_WRITE, fd, task->context);
+ SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(schedule->generic_queue->lock);
+ }
+
+ if (!task->valid) {
+ /* Invalid (unregistered) tasks are removed from the
+ task queue. */
+ if (schedule->generic_queue->task == task->next) {
+ silc_schedule_task_remove(schedule->generic_queue, task);
+ silc_mutex_unlock(schedule->generic_queue->lock);
+ break;
+ }
+
+ task = task->next;
+ silc_schedule_task_remove(schedule->generic_queue, task);
+ continue;
+ }
+
+ /* Break if there isn't more tasks in the queue */
+ if (schedule->generic_queue->task == task->next)
+ break;
+
+ task = task->next;
+ }
+
+ silc_mutex_unlock(schedule->generic_queue->lock);
}
+ }
+}
+
+/* Executes all tasks whose timeout has expired. The task is removed from
+ the task queue after the callback function has returned. Also, invalid
+ tasks are removed here. We don't have to care about priorities because
+ tasks are already sorted in their priority order at the registration
+ phase. */
+/* This holds the schedule->lock and the schedule->timeout_queue->lock */
+
+static void silc_schedule_dispatch_timeout(SilcSchedule schedule,
+ bool dispatch_all)
+{
+ SilcTaskQueue queue = schedule->timeout_queue;
+ SilcTask task;
+ struct timeval curtime;
+
+ SILC_LOG_DEBUG(("Running timeout tasks"));
- if (timeout_usecs >= 0) {
- timeout.tv_sec = 0;
- timeout.tv_usec = timeout_usecs;
- schedule->timeout = timeout;
- schedule->has_timeout = TRUE;
+ silc_gettimeofday(&curtime);
+
+ queue = schedule->timeout_queue;
+ if (queue && queue->task) {
+ task = queue->task;
+
+ /* Walk thorugh all tasks in the particular task queue and run all
+ the expired tasks. */
+ while(1) {
+ /* Execute the task if the timeout has expired */
+ if (dispatch_all ||
+ silc_compare_timeval(&task->timeout, &curtime)) {
+ if (task->valid) {
+ silc_mutex_unlock(queue->lock);
+ SILC_SCHEDULE_UNLOCK(schedule);
+ task->callback(schedule, schedule->app_context,
+ SILC_TASK_EXPIRE, task->fd, task->context);
+ SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(queue->lock);
+ }
+
+ /* Break if there isn't more tasks in the queue */
+ if (queue->task == task->next) {
+ silc_schedule_task_remove(queue, task);
+ break;
+ }
+
+ task = task->next;
+
+ /* Remove the task from queue */
+ silc_schedule_task_remove(queue, task->prev);
+ } else {
+ /* The timeout hasn't expired, check for next one */
+
+ /* Break if there isn't more tasks in the queue */
+ if (queue->task == task->next)
+ break;
+
+ task = task->next;
+ }
}
+ }
+}
+
+/* Calculates next timeout for select(). This is the timeout value
+ when at earliest some of the timeout tasks expire. If this is in the
+ past, they will be run now. */
+/* This holds the schedule->lock and the schedule->timeout_queue->lock */
- /* This is the main silc_select(). The program blocks here until some
- of the selected file descriptors change status or the selected
- timeout expires. */
- SILC_LOG_DEBUG(("Select"));
- ret = schedule_ops.schedule(schedule, schedule->internal);
+static void silc_schedule_select_timeout(SilcSchedule schedule)
+{
+ SilcTaskQueue queue = schedule->timeout_queue;
+ SilcTask task;
+ struct timeval curtime;
- if (silc_likely(ret == 0)) {
- /* Timeout */
- SILC_LOG_DEBUG(("Running timeout tasks"));
- if (silc_likely(silc_list_count(schedule->timeout_queue)))
+ /* Get the current time */
+ silc_gettimeofday(&curtime);
+ schedule->timeout = NULL;
+
+ /* First task in the task queue has always the smallest timeout. */
+ task = queue->task;
+ while(1) {
+ if (task && task->valid == TRUE) {
+ /* If the timeout is in past, we will run the task and all other
+ timeout tasks from the past. */
+ if (silc_compare_timeval(&task->timeout, &curtime)) {
silc_schedule_dispatch_timeout(schedule, FALSE);
- continue;
- } else if (silc_likely(ret > 0)) {
- /* There is some data available now */
- SILC_LOG_DEBUG(("Running fd tasks"));
- silc_schedule_dispatch_fd(schedule);
- continue;
+ /* The task(s) has expired and doesn't exist on the task queue
+ anymore. We continue with new timeout. */
+ queue = schedule->timeout_queue;
+ task = queue->task;
+ if (task == NULL || task->valid == FALSE)
+ break;
+ }
+ /* Calculate the next timeout for select() */
+ queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec;
+ queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec;
+ if (queue->timeout.tv_sec < 0)
+ queue->timeout.tv_sec = 0;
+
+ /* We wouldn't want to go under zero, check for it. */
+ if (queue->timeout.tv_usec < 0) {
+ queue->timeout.tv_sec -= 1;
+ if (queue->timeout.tv_sec < 0)
+ queue->timeout.tv_sec = 0;
+ queue->timeout.tv_usec += 1000000L;
+ }
+
+ /* We've got the timeout value */
+ break;
} else {
- /* Error */
- if (silc_likely(errno == EINTR))
- continue;
- SILC_LOG_ERROR(("Error in select()/poll(): %s", strerror(errno)));
- continue;
+ /* Task is not valid, remove it and try next one. */
+ silc_schedule_task_remove(queue, task);
+ task = queue->task;
+ if (queue->task == NULL)
+ break;
}
- } while (timeout_usecs == -1);
+ }
- return TRUE;
+ /* Save the timeout */
+ if (task) {
+ schedule->timeout = &queue->timeout;
+ SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule->timeout->tv_sec,
+ schedule->timeout->tv_usec));
+ }
}
/* Runs the scheduler once and then returns. */
-SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
+bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
{
- SilcBool ret;
- SILC_SCHEDULE_LOCK(schedule);
- ret = silc_schedule_iterate(schedule, timeout_usecs);
+ struct timeval timeout;
+ int ret;
+
+ SILC_LOG_DEBUG(("In scheduler loop"));
+
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_LOCK(schedule);
+
+ /* Deliver signals if any has been set to be called */
+ if (schedule->signal_tasks) {
+ SILC_SCHEDULE_UNLOCK(schedule);
+ silc_schedule_internal_signals_call(schedule->internal, schedule);
+ schedule->signal_tasks = FALSE;
+ SILC_SCHEDULE_LOCK(schedule);
+ }
+
+ /* If the task queues aren't initialized or we aren't valid anymore
+ we will return */
+ if ((!schedule->fd_queue && !schedule->timeout_queue
+ && !schedule->generic_queue) || schedule->valid == FALSE) {
+ SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return FALSE;
+ }
+
+ /* If the task queues aren't initialized or we aren't valid anymore
+ we will return */
+ if ((!schedule->fd_queue && !schedule->timeout_queue
+ && !schedule->generic_queue) || schedule->valid == FALSE) {
+ SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return FALSE;
+ }
+
+ /* Calculate next timeout for silc_select(). This is the timeout value
+ when at earliest some of the timeout tasks expire. */
+ silc_mutex_lock(schedule->timeout_queue->lock);
+ silc_schedule_select_timeout(schedule);
+ silc_mutex_unlock(schedule->timeout_queue->lock);
+
+ if (timeout_usecs >= 0) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = timeout_usecs;
+ schedule->timeout = &timeout;
+ }
+
SILC_SCHEDULE_UNLOCK(schedule);
- return ret;
+
+ /* This is the main select(). The program blocks here until some
+ of the selected file descriptors change status or the selected
+ timeout expires. */
+ SILC_LOG_DEBUG(("Select"));
+ ret = silc_select(schedule->fd_list, schedule->last_fd + 1,
+ schedule->timeout);
+
+ SILC_SCHEDULE_LOCK(schedule);
+
+ switch (ret) {
+ case -1:
+ /* Error */
+ if (errno == EINTR)
+ break;
+ SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
+ break;
+ case 0:
+ /* Timeout */
+ silc_mutex_lock(schedule->timeout_queue->lock);
+ silc_schedule_dispatch_timeout(schedule, FALSE);
+ silc_mutex_unlock(schedule->timeout_queue->lock);
+ break;
+ default:
+ /* There is some data available now */
+ SILC_LOG_DEBUG(("Running non-timeout tasks"));
+ silc_schedule_dispatch_nontimeout(schedule);
+ break;
+ }
+
+ if (!schedule->is_locked)
+ SILC_SCHEDULE_UNLOCK(schedule);
+
+ return TRUE;
}
-/* Runs the scheduler and blocks here. When this returns the scheduler
- has ended. */
+/* The SILC scheduler. This is actually the main routine in SILC programs.
+ When this returns the program is to be ended. Before this function can
+ be called, one must call silc_schedule_init function. */
void silc_schedule(SilcSchedule schedule)
{
SILC_LOG_DEBUG(("Running scheduler"));
- /* Start the scheduler loop */
+ if (schedule->valid == FALSE) {
+ SILC_LOG_ERROR(("Scheduler is not valid, stopping"));
+ return;
+ }
+
SILC_SCHEDULE_LOCK(schedule);
- silc_schedule_iterate(schedule, -1);
+ schedule->is_locked = TRUE;
+
+ /* Start the scheduler loop */
+ while (silc_schedule_one(schedule, -1))
+ ;
+
SILC_SCHEDULE_UNLOCK(schedule);
}
#ifdef SILC_THREADS
SILC_LOG_DEBUG(("Wakeup scheduler"));
SILC_SCHEDULE_LOCK(schedule);
- schedule_ops.wakeup(schedule, schedule->internal);
+ silc_schedule_internal_wakeup(schedule->internal);
SILC_SCHEDULE_UNLOCK(schedule);
#endif
}
SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
SilcTaskCallback callback, void *context,
long seconds, long useconds,
- SilcTaskType type)
+ SilcTaskType type,
+ SilcTaskPriority priority)
{
- SilcTask task = NULL;
+ SilcTask newtask;
+ SilcTaskQueue queue;
+ int timeout = FALSE;
- if (silc_unlikely(!schedule->valid))
+ if (!schedule->valid)
return NULL;
- SILC_SCHEDULE_LOCK(schedule);
+ queue = SILC_SCHEDULE_GET_QUEUE(type);
- if (silc_likely(type == SILC_TASK_TIMEOUT)) {
- SilcTaskTimeout tmp, prev, ttask;
- SilcList list;
+ /* If the task is generic task, we check whether this task has already
+ been registered. Generic tasks are registered only once and after that
+ the same task applies to all file descriptors to be registered. */
+ if (type == SILC_TASK_GENERIC) {
+ silc_mutex_lock(queue->lock);
- silc_list_start(schedule->free_tasks);
- ttask = silc_list_get(schedule->free_tasks);
- if (silc_unlikely(!ttask)) {
- ttask = silc_calloc(1, sizeof(*ttask));
- if (silc_unlikely(!ttask))
- goto out;
- }
- silc_list_del(schedule->free_tasks, ttask);
-
- ttask->header.type = 1;
- ttask->header.callback = callback;
- ttask->header.context = context;
- ttask->header.valid = TRUE;
-
- /* Add timeout */
- silc_gettimeofday(&ttask->timeout);
- if ((seconds + useconds) > 0) {
- ttask->timeout.tv_sec += seconds + (useconds / 1000000L);
- ttask->timeout.tv_usec += (useconds % 1000000L);
- if (ttask->timeout.tv_usec >= 1000000L) {
- ttask->timeout.tv_sec += 1;
- ttask->timeout.tv_usec -= 1000000L;
- }
- }
+ SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d", fd,
+ type, priority));
- 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. */
- list = schedule->timeout_queue;
- silc_list_start(list);
- prev = NULL;
- while ((tmp = silc_list_get(list)) != SILC_LIST_END) {
- /* If we have shorter timeout, we have found our spot */
- if (silc_compare_timeval(&ttask->timeout, &tmp->timeout)) {
- silc_list_insert(schedule->timeout_queue, prev, ttask);
- break;
- }
- prev = tmp;
- }
- if (!tmp)
- silc_list_add(schedule->timeout_queue, ttask);
+ if (queue->task) {
+ SilcTask task = queue->task;
+ while(1) {
+ if ((task->callback == callback) && (task->context == context)) {
+ SILC_LOG_DEBUG(("Found matching generic task, using the match"));
- task = (SilcTask)ttask;
+ silc_mutex_unlock(queue->lock);
- } else if (silc_likely(type == SILC_TASK_FD)) {
- SilcTaskFd ftask;
+ /* Add the fd to be listened, the task found now applies to this
+ fd as well. */
+ silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ, FALSE);
+ return task;
+ }
- /* Check if fd is already added */
- if (silc_unlikely(silc_hash_table_find(schedule->fd_queue,
- SILC_32_TO_PTR(fd),
- NULL, (void *)&task))) {
- if (task->valid)
- goto out;
+ if (queue->task == task->next)
+ break;
- /* Remove invalid task. We must have unique fd key to hash table. */
- silc_schedule_task_remove(schedule, task);
+ task = task->next;
+ }
}
- /* Check max tasks */
- if (silc_unlikely(schedule->max_tasks > 0 &&
- silc_hash_table_count(schedule->fd_queue) >=
- schedule->max_tasks)) {
- SILC_LOG_WARNING(("Scheduler task limit reached: cannot add new task"));
- task = NULL;
- goto out;
- }
+ silc_mutex_unlock(queue->lock);
+ }
+
+ newtask = silc_calloc(1, sizeof(*newtask));
+ if (!newtask)
+ return NULL;
- ftask = silc_calloc(1, sizeof(*ftask));
- if (silc_unlikely(!ftask)) {
- task = NULL;
- goto out;
+ SILC_LOG_DEBUG(("Registering new task %p, fd=%d type=%d priority=%d",
+ newtask, fd, type, priority));
+
+ newtask->fd = fd;
+ newtask->context = context;
+ newtask->callback = callback;
+ newtask->valid = TRUE;
+ newtask->priority = priority;
+ newtask->type = type;
+ newtask->next = newtask;
+ newtask->prev = newtask;
+
+ /* Create timeout if marked to be timeout task */
+ if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
+ silc_gettimeofday(&newtask->timeout);
+ newtask->timeout.tv_sec += seconds + (useconds / 1000000L);
+ newtask->timeout.tv_usec += (useconds % 1000000L);
+ if (newtask->timeout.tv_usec > 999999L) {
+ newtask->timeout.tv_sec += 1;
+ newtask->timeout.tv_usec -= 1000000L;
}
+ timeout = TRUE;
+ }
- SILC_LOG_DEBUG(("New fd task %p fd=%d", ftask, fd));
+ /* If the task is non-timeout task we have to tell the scheduler that we
+ would like to have these tasks scheduled at some odd distant future. */
+ if (type != SILC_TASK_TIMEOUT)
+ silc_schedule_set_listen_fd(schedule, fd, SILC_TASK_READ, FALSE);
- ftask->header.type = 0;
- ftask->header.callback = callback;
- ftask->header.context = context;
- ftask->header.valid = TRUE;
- ftask->events = SILC_TASK_READ;
- ftask->fd = fd;
+ silc_mutex_lock(queue->lock);
- /* Add task and schedule it */
- if (!silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask)) {
- silc_free(ftask);
- task = NULL;
- goto out;
- }
- if (!schedule_ops.schedule_fd(schedule, schedule->internal,
- ftask, ftask->events)) {
- silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(fd));
- task = NULL;
- goto out;
- }
+ /* Is this first task of the queue? */
+ if (queue->task == NULL) {
+ queue->task = newtask;
+ silc_mutex_unlock(queue->lock);
+ return newtask;
+ }
- task = (SilcTask)ftask;
+ if (timeout)
+ newtask = silc_task_add_timeout(queue, newtask, priority);
+ else
+ newtask = silc_task_add(queue, newtask, priority);
- } else if (silc_unlikely(type == SILC_TASK_SIGNAL)) {
- SILC_SCHEDULE_UNLOCK(schedule);
- schedule_ops.signal_register(schedule, schedule->internal, fd,
- callback, context);
- return NULL;
- }
+ silc_mutex_unlock(queue->lock);
- out:
- SILC_SCHEDULE_UNLOCK(schedule);
- return task;
+ return newtask;
}
-/* Invalidates task */
+/* Removes a task from the scheduler */
-SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task)
+void silc_schedule_task_del(SilcSchedule schedule, SilcTask task)
{
- if (silc_unlikely(task == SILC_ALL_TASKS)) {
- SilcHashTableList htl;
+ SilcTaskQueue queue = SILC_SCHEDULE_GET_QUEUE(task->type);
- SILC_LOG_DEBUG(("Unregister all tasks"));
+ /* Unregister all tasks */
+ if (task == SILC_ALL_TASKS) {
+ SilcTask next;
+ SILC_LOG_DEBUG(("Unregistering all tasks at once"));
- SILC_SCHEDULE_LOCK(schedule);
+ silc_mutex_lock(queue->lock);
- /* Delete from fd queue */
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&task))
- task->valid = FALSE;
- silc_hash_table_list_reset(&htl);
+ if (!queue->task) {
+ silc_mutex_unlock(queue->lock);
+ return;
+ }
- /* Delete from timeout queue */
- silc_list_start(schedule->timeout_queue);
- while ((task = (SilcTask)silc_list_get(schedule->timeout_queue))
- != SILC_LIST_END)
- task->valid = FALSE;
+ next = queue->task;
- SILC_SCHEDULE_UNLOCK(schedule);
- return TRUE;
+ while(1) {
+ if (next->valid)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+
+ silc_mutex_unlock(queue->lock);
+ return;
}
- SILC_LOG_DEBUG(("Unregistering task %p", task));
- SILC_SCHEDULE_LOCK(schedule);
- task->valid = FALSE;
- SILC_SCHEDULE_UNLOCK(schedule);
+ SILC_LOG_DEBUG(("Unregistering task"));
- return TRUE;
+ silc_mutex_lock(queue->lock);
+
+ /* Unregister the specific task */
+ if (task->valid)
+ task->valid = FALSE;
+
+ silc_mutex_unlock(queue->lock);
}
-/* Invalidate task by fd */
+/* Remove task by fd */
-SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd)
+void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd)
{
- SilcTask task = NULL;
- SilcBool ret = FALSE;
-
SILC_LOG_DEBUG(("Unregister task by fd %d", fd));
- SILC_SCHEDULE_LOCK(schedule);
+ silc_task_del_by_fd(schedule->timeout_queue, fd);
+ silc_task_del_by_fd(schedule->fd_queue, fd);
+}
- /* fd is unique, so there is only one task with this fd in the table */
- if (silc_likely(silc_hash_table_find(schedule->fd_queue,
- SILC_32_TO_PTR(fd), NULL,
- (void *)&task))) {
- SILC_LOG_DEBUG(("Deleting task %p", task));
- task->valid = FALSE;
- ret = TRUE;
- }
+/* Remove task by task callback. */
- SILC_SCHEDULE_UNLOCK(schedule);
+void silc_schedule_task_del_by_callback(SilcSchedule schedule,
+ SilcTaskCallback callback)
+{
+ SILC_LOG_DEBUG(("Unregister task by callback"));
- /* If it is signal, remove it */
- if (silc_unlikely(!task)) {
- schedule_ops.signal_unregister(schedule, schedule->internal, fd);
- ret = TRUE;
- }
+ silc_task_del_by_callback(schedule->timeout_queue, callback);
+ silc_task_del_by_callback(schedule->fd_queue, callback);
+ silc_task_del_by_callback(schedule->generic_queue, callback);
+}
+
+/* Remove task by context. */
+
+void silc_schedule_task_del_by_context(SilcSchedule schedule, void *context)
+{
+ SILC_LOG_DEBUG(("Unregister task by context"));
- return ret;
+ silc_task_del_by_context(schedule->timeout_queue, context);
+ silc_task_del_by_context(schedule->fd_queue, context);
+ silc_task_del_by_context(schedule->generic_queue, context);
}
-/* Invalidate task by task callback. */
+/* Sets a file descriptor to be listened by select() in scheduler. One can
+ call this directly if wanted. This can be called multiple times for
+ one file descriptor to set different iomasks. */
-SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
- SilcTaskCallback callback)
+void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
+ SilcTaskEvent mask, bool send_events)
{
- SilcTask task;
- SilcHashTableList htl;
- SilcList list;
- SilcBool ret = FALSE;
+ int i;
+ bool found = FALSE;
- SILC_LOG_DEBUG(("Unregister task by callback"));
+ if (!schedule->valid)
+ return;
SILC_SCHEDULE_LOCK(schedule);
- /* Delete from fd queue */
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&task)) {
- if (task->callback == callback) {
- task->valid = FALSE;
- ret = TRUE;
+ for (i = 0; i < schedule->max_fd; i++)
+ if (schedule->fd_list[i].fd == fd) {
+ schedule->fd_list[i].fd = fd;
+ schedule->fd_list[i].events = mask;
+ schedule->fd_list[i].revents = 0;
+ if (i > schedule->last_fd)
+ schedule->last_fd = i;
+ found = TRUE;
+ if (send_events) {
+ schedule->fd_list[i].revents = mask;
+ silc_schedule_dispatch_nontimeout(schedule);
+ }
+ break;
}
- }
- silc_hash_table_list_reset(&htl);
-
- /* Delete from timeout queue */
- list = schedule->timeout_queue;
- silc_list_start(list);
- while ((task = (SilcTask)silc_list_get(list))) {
- if (task->callback == callback) {
- task->valid = FALSE;
- ret = TRUE;
+
+ if (!found)
+ for (i = 0; i < schedule->max_fd; i++)
+ if (schedule->fd_list[i].events == 0) {
+ schedule->fd_list[i].fd = fd;
+ schedule->fd_list[i].events = mask;
+ schedule->fd_list[i].revents = 0;
+ if (i > schedule->last_fd)
+ schedule->last_fd = i;
+ if (send_events) {
+ schedule->fd_list[i].revents = mask;
+ silc_schedule_dispatch_nontimeout(schedule);
+ }
+ break;
+ }
+
+ SILC_SCHEDULE_UNLOCK(schedule);
+}
+
+/* Removes a file descriptor from listen list. */
+
+void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd)
+{
+ int i;
+
+ SILC_SCHEDULE_LOCK(schedule);
+
+ SILC_LOG_DEBUG(("Unset listen fd %d", fd));
+
+ for (i = 0; i < schedule->max_fd; i++)
+ if (schedule->fd_list[i].fd == fd) {
+ schedule->fd_list[i].fd = 0;
+ schedule->fd_list[i].events = 0;
+ schedule->fd_list[i].revents = 0;
+ if (schedule->last_fd == i && i > 0)
+ schedule->last_fd = i - 1;
+ break;
}
- }
SILC_SCHEDULE_UNLOCK(schedule);
+}
+
+/* Register a new signal */
- return ret;
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context)
+{
+ silc_schedule_internal_signal_register(schedule->internal, signal,
+ callback, context);
}
-/* Invalidate task by context. */
+/* Unregister a new signal */
-SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule,
- void *context)
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context)
{
- SilcTask task;
- SilcHashTableList htl;
- SilcList list;
- SilcBool ret = FALSE;
+ silc_schedule_internal_signal_unregister(schedule->internal, signal,
+ callback, context);
+}
- SILC_LOG_DEBUG(("Unregister task by context"));
+/* Call signal indicated by `signal'. */
- SILC_SCHEDULE_LOCK(schedule);
+void silc_schedule_signal_call(SilcSchedule schedule, SilcUInt32 signal)
+{
+ /* Mark that signals needs to be delivered later. */
+ silc_schedule_internal_signal_call(schedule->internal, signal);
+ schedule->signal_tasks = TRUE;
+}
- /* Delete from fd queue */
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&task)) {
- if (task->context == context) {
- task->valid = FALSE;
- ret = TRUE;
- }
+/* Allocates a newtask task queue into the scheduler */
+
+static void silc_task_queue_alloc(SilcTaskQueue *queue)
+{
+ *queue = silc_calloc(1, sizeof(**queue));
+ silc_mutex_alloc(&(*queue)->lock);
+}
+
+/* Free's a task queue. */
+
+static void silc_task_queue_free(SilcTaskQueue queue)
+{
+ silc_mutex_free(queue->lock);
+ memset(queue, 'F', sizeof(*queue));
+ silc_free(queue);
+}
+
+/* Return task by its fd. */
+
+static SilcTask silc_task_find(SilcTaskQueue queue, SilcUInt32 fd)
+{
+ SilcTask next;
+
+ if (!queue->task)
+ return NULL;
+
+ next = queue->task;
+
+ while (1) {
+ if (next->fd == fd)
+ return next;
+ if (queue->task == next->next)
+ return NULL;
+ next = next->next;
}
- silc_hash_table_list_reset(&htl);
-
- /* Delete from timeout queue */
- list = schedule->timeout_queue;
- silc_list_start(list);
- while ((task = (SilcTask)silc_list_get(list))) {
- if (task->context == context) {
- ret = TRUE;
- task->valid = FALSE;
+
+ return NULL;
+}
+
+/* Adds a non-timeout task into the task queue. This function is used
+ by silc_task_register function. Returns a pointer to the registered
+ task. */
+
+static SilcTask silc_task_add(SilcTaskQueue queue, SilcTask newtask,
+ SilcTaskPriority priority)
+{
+ SilcTask task, next, prev;
+
+ /* Take the first task in the queue */
+ task = queue->task;
+
+ switch(priority) {
+ case SILC_TASK_PRI_LOW:
+ /* Lowest priority. The task is added at the end of the list. */
+ prev = task->prev;
+ newtask->prev = prev;
+ newtask->next = task;
+ prev->next = newtask;
+ task->prev = newtask;
+ break;
+ case SILC_TASK_PRI_NORMAL:
+ /* Normal priority. The task is added before lower priority tasks
+ but after tasks with higher priority. */
+ prev = task->prev;
+ while(prev != task) {
+ if (prev->priority > SILC_TASK_PRI_LOW)
+ break;
+ prev = prev->prev;
+ }
+ if (prev == task) {
+ /* There are only lower priorities in the list, we will
+ sit before them and become the first task in the queue. */
+ prev = task->prev;
+ newtask->prev = prev;
+ newtask->next = task;
+ task->prev = newtask;
+ prev->next = newtask;
+
+ /* We are now the first task in queue */
+ queue->task = newtask;
+ } else {
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ newtask->prev = prev;
+ newtask->next = next;
+ prev->next = newtask;
+ next->prev = newtask;
}
+ break;
+ default:
+ silc_free(newtask);
+ return NULL;
}
- SILC_SCHEDULE_UNLOCK(schedule);
+ return newtask;
+}
+
+/* Return the timeout task with smallest timeout. */
- return ret;
+static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first)
+{
+ SilcTask prev, task;
+
+ prev = first->prev;
+
+ if (first == prev)
+ return first;
+
+ task = first;
+ while (1) {
+ if (first == prev)
+ break;
+
+ if (silc_compare_timeval(&prev->timeout, &task->timeout))
+ task = prev;
+
+ prev = prev->prev;
+ }
+
+ return task;
}
-/* Invalidate task by all */
+/* Adds a timeout task into the task queue. This function is used by
+ silc_task_register function. Returns a pointer to the registered
+ task. Timeout tasks are sorted by their timeout value in ascending
+ order. The priority matters if there are more than one task with
+ same timeout. */
-SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
- SilcTaskCallback callback,
- void *context)
+static SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask newtask,
+ SilcTaskPriority priority)
{
- SilcTask task;
- SilcList list;
- SilcBool ret = FALSE;
+ SilcTask task, prev, next;
- SILC_LOG_DEBUG(("Unregister task by fd, callback and context"));
+ /* Take the first task in the queue */
+ task = queue->task;
- /* For fd task, callback and context is irrelevant as fd is unique */
- if (fd)
- return silc_schedule_task_del_by_fd(schedule, fd);
+ /* Take last task from the list */
+ prev = task->prev;
- SILC_SCHEDULE_LOCK(schedule);
+ switch(priority) {
+ case SILC_TASK_PRI_LOW:
+ /* Lowest priority. The task is added at the end of the list. */
+ while(prev != task) {
- /* Delete from timeout queue */
- list = schedule->timeout_queue;
- silc_list_start(list);
- while ((task = (SilcTask)silc_list_get(list))) {
- if (task->callback == callback && task->context == context) {
- task->valid = FALSE;
- ret = TRUE;
+ /* If we have longer timeout than with the task head of us
+ we have found our spot. */
+ if (silc_compare_timeval(&prev->timeout, &newtask->timeout))
+ break;
+
+ /* If we are equal size of timeout we will be after it. */
+ if (!silc_compare_timeval(&newtask->timeout, &prev->timeout))
+ break;
+
+ /* We have shorter timeout, compare to next one. */
+ prev = prev->prev;
}
- }
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ newtask->prev = prev;
+ newtask->next = next;
+ prev->next = newtask;
+ next->prev = newtask;
+
+ if (prev == task) {
+ /* Check if we are going to be the first task in the queue */
+ if (silc_compare_timeval(&prev->timeout, &newtask->timeout))
+ break;
+ if (!silc_compare_timeval(&newtask->timeout, &prev->timeout))
+ break;
- SILC_SCHEDULE_UNLOCK(schedule);
+ /* We are now the first task in queue */
+ queue->task = newtask;
+ }
+ break;
+ case SILC_TASK_PRI_NORMAL:
+ /* Normal priority. The task is added before lower priority tasks
+ but after tasks with higher priority. */
+ while(prev != task) {
+
+ /* If we have longer timeout than with the task head of us
+ we have found our spot. */
+ if (silc_compare_timeval(&prev->timeout, &newtask->timeout))
+ break;
- return TRUE;
+ /* If we are equal size of timeout, priority kicks in place. */
+ if (!silc_compare_timeval(&newtask->timeout, &prev->timeout))
+ if (prev->priority >= SILC_TASK_PRI_NORMAL)
+ break;
+
+ /* We have shorter timeout or higher priority, compare to next one. */
+ prev = prev->prev;
+ }
+ /* Found a spot from the list, add the task to the list. */
+ next = prev->next;
+ newtask->prev = prev;
+ newtask->next = next;
+ prev->next = newtask;
+ next->prev = newtask;
+
+ if (prev == task) {
+ /* Check if we are going to be the first task in the queue */
+ if (silc_compare_timeval(&prev->timeout, &newtask->timeout))
+ break;
+ if (!silc_compare_timeval(&newtask->timeout, &prev->timeout))
+ if (prev->priority >= SILC_TASK_PRI_NORMAL)
+ break;
+
+ /* We are now the first task in queue */
+ queue->task = newtask;
+ }
+ break;
+ default:
+ silc_free(newtask);
+ return NULL;
+ }
+
+ return newtask;
}
-/* Sets a file descriptor to be listened by scheduler. One can call this
- directly if wanted. This can be called multiple times for one file
- descriptor to set different iomasks. */
+/* Removes (unregisters) a task from particular task queue. This function
+ is used internally by scheduler. This must be called holding the
+ queue->lock. */
-SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
- SilcTaskEvent mask, SilcBool send_events)
+static int silc_schedule_task_remove(SilcTaskQueue queue, SilcTask task)
{
- SilcTaskFd task;
+ SilcTask first, old, next;
- if (silc_unlikely(!schedule->valid))
+ if (!queue || !task)
return FALSE;
- SILC_SCHEDULE_LOCK(schedule);
+ if (!queue->task) {
+ return FALSE;
+ }
- if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
- NULL, (void *)&task)) {
- if (!schedule_ops.schedule_fd(schedule, schedule->internal, task, mask)) {
- SILC_SCHEDULE_UNLOCK(schedule);
- return FALSE;
- }
- task->events = mask;
- if (silc_unlikely(send_events) && mask) {
- task->revents = mask;
- silc_schedule_dispatch_fd(schedule);
+ first = queue->task;
+
+ /* Unregister all tasks in queue */
+ if (task == SILC_ALL_TASKS) {
+ SILC_LOG_DEBUG(("Removing all tasks at once"));
+ next = first;
+
+ while(1) {
+ old = next->next;
+ silc_free(next);
+ if (old == first)
+ break;
+ next = old;
}
+
+ queue->task = NULL;
+ return TRUE;
}
- SILC_SCHEDULE_UNLOCK(schedule);
+ SILC_LOG_DEBUG(("Removing task %p", task));
- return TRUE;
-}
+ /* Unregister the task */
+ old = first;
+ while(1) {
+ if (old == task) {
+ SilcTask prev, next;
+
+ prev = old->prev;
+ next = old->next;
+ prev->next = next;
+ next->prev = prev;
+
+ if (prev == old && next == old)
+ queue->task = NULL;
+ if (queue->task == old)
+ queue->task = silc_task_get_first(queue, next);
-/* Returns the file descriptor's current requested event mask. */
+ silc_free(old);
+ return TRUE;
+ }
+ old = old->prev;
+
+ if (old == first) {
+ return FALSE;
+ }
+ }
+}
-SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
- SilcUInt32 fd)
+static void silc_task_del_by_fd(SilcTaskQueue queue, SilcUInt32 fd)
{
- SilcTaskFd task;
- SilcTaskEvent event = 0;
+ SilcTask next;
- if (silc_unlikely(!schedule->valid))
- return 0;
+ silc_mutex_lock(queue->lock);
- SILC_SCHEDULE_LOCK(schedule);
- if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
- NULL, (void *)&task))
- event = task->events;
- SILC_SCHEDULE_UNLOCK(schedule);
+ if (!queue->task) {
+ silc_mutex_unlock(queue->lock);
+ return;
+ }
+
+ next = queue->task;
+
+ while(1) {
+ if (next->fd == fd)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
- return event;
+ silc_mutex_unlock(queue->lock);
}
-/* Removes a file descriptor from listen list. */
+static void silc_task_del_by_callback(SilcTaskQueue queue,
+ SilcTaskCallback callback)
+{
+ SilcTask next;
-void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd)
+ silc_mutex_lock(queue->lock);
+
+ if (!queue->task) {
+ silc_mutex_unlock(queue->lock);
+ return;
+ }
+
+ next = queue->task;
+
+ while(1) {
+ if (next->callback == callback)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+
+ silc_mutex_unlock(queue->lock);
+}
+
+static void silc_task_del_by_context(SilcTaskQueue queue, void *context)
{
- silc_schedule_set_listen_fd(schedule, fd, 0, FALSE);
+ SilcTask next;
+
+ silc_mutex_lock(queue->lock);
+
+ if (!queue->task) {
+ silc_mutex_unlock(queue->lock);
+ return;
+ }
+
+ next = queue->task;
+
+ while(1) {
+ if (next->context == context)
+ next->valid = FALSE;
+ if (queue->task == next->next)
+ break;
+ next = next->next;
+ }
+
+ silc_mutex_unlock(queue->lock);
}
/*
-
+
silcschedule.h
-
+
Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1998 - 2007 Pekka Riikonen
-
+
+ Copyright (C) 1998 - 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* silcutil/SILC Schedule Interface
*
* DESCRIPTION
* the application's main loop that can handle incoming data, outgoing data,
* timeouts and dispatch different kind of tasks.
*
- * The SILC Scheduler supports file descriptor based tasks and timeout tasks.
- * File descriptor tasks are tasks that perform some operation over the
- * specified file descriptor. These include network connections, for example.
- * The timeout tasks are timeouts that are executed after the specified
- * timeout has elapsed.
+ * The SILC Scheduler supports file descriptor based tasks, timeout tasks
+ * and generic tasks. File descriptor tasks are tasks that perform some
+ * operation over the specified file descriptor. These include network
+ * connections, for example. The timeout tasks are timeouts that are executed
+ * after the specified timeout has elapsed. The generic tasks are tasks that
+ * apply to all registered file descriptors thus providing one task that
+ * applies to many independent connections.
*
* The SILC Scheduler is designed to be the sole main loop of the application
* so that the application does not need any other main loop. However,
* SILC Scheduler does support running the scheduler only once, so that the
* scheduler does not block, and thus providing a possiblity that some
- * external main loop is run over the SILC Scheduler.
+ * external main loop is run over the SILC Scheduler. However, these
+ * applications are considered to be special cases.
*
* Typical application first initializes the scheduler and then registers
* the very first tasks to the scheduler and then run the scheduler. After
- * the scheduler's run function returns the application is considered to be
+ * the scheduler's run function returns the application is considered to be
* ended.
*
* On WIN32 systems the SILC Scheduler is too designed to work as the main
* it dispatches them from the scheduler, and thus makes it possible to
* create GUI applications. The scheduler can also handle all kinds of
* WIN32 handles, this includes sockets created by the SILC Net API routines,
- * WSAEVENT handle objects created by Winsock2 routines and arbitrary
+ * WSAEVENT handle objects created by Winsock2 routines and arbitrary
* WIN32 HANDLE objects.
*
* The SILC Scheduler supports multi-threads as well. The actual scheduler
/****s* silcutil/SilcScheduleAPI/SilcSchedule
*
* NAME
- *
+ *
* typedef struct SilcScheduleStruct *SilcSchedule;
*
* DESCRIPTION
*
* This context is the actual Scheduler and is allocated by
* the silc_schedule_init funtion. The context is given as argument
- * to all silc_schedule_* functions. It must be freed by the
+ * to all silc_schedule_* functions. It must be freed by the
* silc_schedule_uninit function.
*
***/
/****s* silcutil/SilcScheduleAPI/SilcTask
*
* NAME
- *
+ *
* typedef struct SilcTaskStruct *SilcTask;
*
* DESCRIPTION
/****d* silcutil/SilcScheduleAPI/SilcTaskType
*
* NAME
- *
+ *
* typedef enum { ... } SilcTaskType;
*
* DESCRIPTION
*
- * SILC has two types of tasks, non-timeout tasks (tasks that perform
- * over file descriptors), and timeout tasks. This type is sent as
- * argument for the task registering function, silc_schedule_task_add.
+ * SILC has three types of tasks, non-timeout tasks (tasks that perform
+ * over file descriptors), timeout tasks and generic tasks (tasks that
+ * apply to every file descriptor). This type is sent as argument for the
+ * task registering function, silc_schedule_task_add.
*
* SOURCE
*/
These tasks are for example network connections. */
SILC_TASK_FD = 0,
- /* Timeout tasks are tasks that are executed after the specified
+ /* Timeout tasks are tasks that are executed after the specified
time has elapsed. After the task is executed the task is removed
automatically from the scheduler. It is safe to re-register the
task in task callback. It is also safe to unregister a task in
the task callback. */
SILC_TASK_TIMEOUT,
- /* Platform specific process signal task. On Unix systems this is one of
- the signals described in signal(7). On other platforms this may not
- be available at all. Only one callback per signal may be added. */
- SILC_TASK_SIGNAL
+ /* Generic tasks are non-timeout tasks and they apply to all file
+ descriptors, except to those that have explicitly registered a
+ non-timeout task. These tasks are there to make it simpler and faster
+ to execute common code that applies to all connections. These are,
+ for example, receiving packets from network and sending packets to
+ network. It doesn't make much sense to register a task that receives
+ a packet from network to every connection when you can have one task
+ that applies to all connections. This is what generic tasks are for.
+ Generic tasks are not bound to any specific file descriptor, however,
+ the correct file descriptor must be passed as argument to task
+ registering function. */
+ SILC_TASK_GENERIC,
} SilcTaskType;
/***/
/****d* silcutil/SilcScheduleAPI/SilcTaskEvent
*
* NAME
- *
+ *
* typedef enum { ... } SilcTaskEvent;
*
* DESCRIPTION
} SilcTaskEvent;
/***/
+/****d* silcutil/SilcScheduleAPI/SilcTaskPriority
+ *
+ * NAME
+ *
+ * typedef enum { ... } SilcTaskPriority;
+ *
+ * DESCRIPTION
+ *
+ * Task priorities. Tasks may be registered with different priorities.
+ * This type defines the different task priorities. The priorities
+ * behaves same for all type of tasks, fd tasks, timeout tasks and
+ * generic tasks.
+ *
+ * SOURCE
+ */
+typedef enum {
+ /* Lowest priority. The task is scheduled to run after its timeout
+ has expired only and only when every other task with higher priority
+ has already been run. For non-timeout tasks this priority behaves
+ same way. Life is not fair for tasks with this priority. */
+ SILC_TASK_PRI_LOW = 0,
+
+ /* Normal priority that is used mostly in SILC. This is priority that
+ should always be used unless you specificly need some other priority.
+ The scheduler will run this task as soon as its timeout has expired.
+ For non-timeout tasks this priority behaves same way. Tasks are run
+ in FIFO (First-In-First-Out) order. */
+ SILC_TASK_PRI_NORMAL,
+} SilcTaskPriority;
+/***/
+
/****f* silcutil/SilcScheduleAPI/SilcTaskCallback
*
* SYNOPSIS
* is a caller specified context. If multiple events occurred this
* callback is called separately for all events. The `app_context'
* is application specific context that was given as argument to the
- * silc_schedule_init function. If the task is timeout task then `fd'
- * is zero (0).
+ * silc_schedule_init function.
*
* To specify task callback function in the application using the
- * SILC_TASK_CALLBACK macro is recommended.
+ * SILC_TASK_CALLBACK and SILC_TASK_CALLBACK_GLOBAL macros is
+ * recommended.
*
***/
typedef void (*SilcTaskCallback)(SilcSchedule schedule, void *app_context,
/****d* silcutil/SilcScheduleAPI/SILC_ALL_TASKS
*
* NAME
- *
+ *
* #define SILC_ALL_TASKS ...
*
* DESCRIPTION
*
- * Marks for all tasks in the scheduler. This can be passed to
+ * Marks for all tasks in the scheduler. This can be passed to
* silc_schedule_task_del function to delete all tasks at once.
*
* SOURCE
/****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK
*
* NAME
- *
+ *
* #define SILC_TASK_CALLBACK ...
*
* DESCRIPTION
*
* SOURCE
*/
-#define SILC_TASK_CALLBACK(func) \
+#define SILC_TASK_CALLBACK(func) \
+static void func(SilcSchedule schedule, void *app_context, \
+ SilcTaskEvent type, \
+ SilcUInt32 fd, void *context)
+/***/
+
+/****d* silcutil/SilcScheduleAPI/SILC_TASK_CALLBACK_GLOBAL
+ *
+ * NAME
+ *
+ * #define SILC_TASK_CALLBACK_GLOBAL ...
+ *
+ * DESCRIPTION
+ *
+ * Generic macro to define task callback functions. This defines a
+ * function with name `func' as a task callback function. This
+ * differs from SILC_TASK_CALLBACK in that the defined function is
+ * not static.
+ *
+ * SOURCE
+ */
+#define SILC_TASK_CALLBACK_GLOBAL(func) \
void func(SilcSchedule schedule, void *app_context, SilcTaskEvent type, \
SilcUInt32 fd, void *context)
/***/
*
* Initializes the scheduler. This returns the scheduler context that
* is given as argument usually to all silc_schedule_* functions.
- * The `app_context' is application specific context that is delivered
- * to all task callbacks. The caller must free that context. The
- * 'app_context' can be for example the application itself.
- *
- * The `max_tasks' is the maximum number of SILC_TASK_FD tasks in the
- * scheduler. Set value to 0 to use default. Operating system will
- * enforce the final limit. On some operating systems the limit can
- * be significantly increased when this function is called in priviliged
- * mode (as super user).
+ * The `max_tasks' indicates the number of maximum tasks that the
+ * scheduler can handle. The `app_context' is application specific
+ * context that is delivered to all task callbacks. The caller must
+ * free that context. The 'app_context' can be for example the
+ * application itself.
*
***/
SilcSchedule silc_schedule_init(int max_tasks, void *app_context);
*
* SYNOPSIS
*
- * SilcBool silc_schedule_uninit(SilcSchedule schedule);
+ * bool silc_schedule_uninit(SilcSchedule schedule);
*
* DESCRIPTION
*
* is still valid and silc_schedule_stop has not been called.
*
***/
-SilcBool silc_schedule_uninit(SilcSchedule schedule);
+bool silc_schedule_uninit(SilcSchedule schedule);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_reinit
+ *
+ * SYNOPSIS
+ *
+ * SilcSchedule silc_schedule_reinit(int max_tasks);
+ *
+ * DESCRIPTION
+ *
+ * This function can be called to enlarge the task handling capabilities
+ * of the scheduler indicated by `schedule'. The `max_tasks' must be
+ * larger than what was set in silc_schedule_init function. This function
+ * returns FALSE if it cannot reinit the scheduler. This function does
+ * not do anything else except ready the scheduler to handle `max_tasks'
+ * number of tasks after this function returns. It is safe to call this
+ * function at any time, and it is guaranteed that existing tasks remain
+ * as they are in the scheduler.
+ *
+ ***/
+bool silc_schedule_reinit(SilcSchedule schedule, int max_tasks);
/****f* silcutil/SilcScheduleAPI/silc_schedule_stop
*
*
* DESCRIPTION
*
- * Stops the scheduler even if it is not supposed to be stopped yet.
- * After calling this, one must call silc_schedule_uninit (after the
+ * Stops the scheduler even if it is not supposed to be stopped yet.
+ * After calling this, one must call silc_schedule_uninit (after the
* silc_schedule has returned). After this is called it is guaranteed
* that next time the scheduler enters the main loop it will be stopped.
* However, untill it enters the main loop it will not detect that
*
* DESCRIPTION
*
- * The SILC scheduler. The program will run inside this function.
+ * The SILC scheduler. This is actually the main routine in SILC programs.
* When this returns the program is to be ended. Before this function can
* be called, one must call silc_schedule_init function.
*
- * NOTES
- *
- * On Windows this will block the program, but will continue dispatching
- * window messages, and thus can be used as the main loop of the program.
- *
- * On Symbian this will return immediately. On Symbian calling
- * silc_schedule is same as calling silc_schedule_one.
- *
***/
void silc_schedule(SilcSchedule schedule);
*
* SYNOPSIS
*
- * SilcBool silc_schedule_one(SilcSchedule schedule, int block);
+ * bool silc_schedule_one(SilcSchedule schedule, int block);
*
* DESCRIPTION
*
* scheduler. The function will not return in this timeout unless
* some other event occurs.
*
- * Typically this would be called from a timeout or idle task
- * periodically (typically from 5-50 ms) to schedule SILC tasks. In
- * this case the `timeout_usecs' is usually 0.
- *
***/
-SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs);
+bool silc_schedule_one(SilcSchedule schedule, int timeout_usecs);
/****f* silcutil/SilcScheduleAPI/silc_schedule_wakeup
*
***/
void *silc_schedule_get_context(SilcSchedule schedule);
-/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_fd
- *
- * SYNOPSIS
- *
- * SilcTask
- * silc_schedule_task_add_fd(SilcSchedule schedule, SilcUInt32 fd,
- * SilcTaskCallback callback, void *context);
- *
- * DESCRIPTION
- *
- * Add file descriptor task to scheduler. The `fd' may be either real
- * file descriptor, socket or on some platforms an opaque file descriptor
- * handle. To receive events for the file descriptor set the correct
- * request events with silc_schedule_set_listen_fd function.
- *
- * The task will be initially set for SILC_TASK_READ events. Setting that
- * event immediately after this call returns is not necessary.
- *
- * This returns the new task or NULL on error. If a task with `fd' has
- * already been added this will return the existing task pointer.
- *
- ***/
-#define silc_schedule_task_add_fd(schedule, fd, callback, context) \
- silc_schedule_task_add(schedule, fd, callback, context, 0, 0, SILC_TASK_FD)
-
-/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_timeout
+/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add
*
* SYNOPSIS
*
- * SilcTask
- * silc_schedule_task_add_timeout(SilcSchedule schedule,
- * SilcTaskCallback callback, void *context,
- * long seconds, long useconds);
+ * SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
+ * SilcTaskCallback callback,
+ * void *context,
+ * long seconds, long useconds,
+ * SilcTaskType type,
+ * SilcTaskPriority priority);
*
* DESCRIPTION
*
- * Add timeout task to scheduler. The `callback' will be called once
- * the specified timeout has elapsed. The task will be removed from the
- * scheduler automatically once the task expires. The event returned
- * to the `callback' is SILC_TASK_EXPIRE. The task added with zero (0)
- * timeout will be executed immediately next time tasks are scheduled.
- *
- ***/
-#define silc_schedule_task_add_timeout(schedule, callback, context, s, u) \
- silc_schedule_task_add(schedule, 0, callback, context, s, u, \
- SILC_TASK_TIMEOUT)
-
-/****f* silcutil/SilcScheduleAPI/silc_schedule_task_add_signal
- *
- * SYNOPSIS
- *
- * SilcTask
- * silc_schedule_task_add_signal(SilcSchedule schedule, int signal,
- * SilcTaskCallback callback, void *context);
- *
- * DESCRIPTION
- *
- * Add platform specific process signal handler to scheduler. On Unix
- * systems the `signal' is one of the signal specified in signal(7). On
- * other platforms this function may not be available at all, and has no
- * effect when called. The event delivered to the `callback' is
- * SILC_TASK_INTERRUPT.
- *
- * NOTES
- *
- * One signal may be registered only one callback. Adding second callback
- * for signal that already has one will fail.
- *
- * This function always returns NULL. To remove signal from scheduler by
- * the signal call silc_schedule_task_del_by_fd.
- *
+ * Registers a new task to the scheduler. This same function is used
+ * to register all types of tasks. The `type' argument tells what type
+ * of the task is. Note that when registering non-timeout tasks one
+ * should also pass 0 as timeout, as the timeout will be ignored anyway.
+ * Also, note, that one cannot register timeout task with 0 timeout.
+ * There cannot be zero timeouts, passing zero means no timeout is used
+ * for the task and SILC_TASK_FD is used as default task type in
+ * this case.
+ *
+ * The `schedule' is the scheduler context. The `fd' is the file
+ * descriptor of the task. On WIN32 systems the `fd' is not actual
+ * file descriptor but some WIN32 event handle. On WIN32 system the `fd'
+ * may be a socket created by the SILC Net API routines, WSAEVENT object
+ * created by Winsock2 network routines or arbitrary WIN32 HANDLE object.
+ * On Unix systems the `fd' is always the real file descriptor.
+ *
+ * The `callback' is the task callback that will be called when some
+ * event occurs for this task. The `context' is sent as argument to
+ * the task `callback' function. For timeout tasks the callback is
+ * called after the specified timeout has elapsed.
+ *
+ * If the `type' is SILC_TASK_TIMEOUT then `seconds' and `useconds'
+ * may be non-zero. Otherwise they should be zero. The `priority'
+ * indicates the priority of the task.
+ *
+ * It is always safe to call this function in any place. New tasks
+ * may be added also in task callbacks, and in multi-threaded environment
+ * in other threads as well.
+ *
***/
-#define silc_schedule_task_add_signal(schedule, sig, callback, context) \
- silc_schedule_task_add(schedule, sig, callback, context, 0, 0, \
- SILC_TASK_SIGNAL)
+SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
+ SilcTaskCallback callback, void *context,
+ long seconds, long useconds,
+ SilcTaskType type,
+ SilcTaskPriority priority);
/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del
*
* SYNOPSIS
*
- * SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
+ * void silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
*
* DESCRIPTION
*
* Deletes the `task' from the scheduler indicated by the `schedule'.
* After deleting the task it is guaranteed that the task callback
* will not be called. If the `task' is SILC_ALL_TASKS then all
- * tasks is removed from the scheduler. Returns always TRUE.
+ * tasks is removed from the scheduler.
*
* It is safe to call this function in any place. Tasks may be removed
* in task callbacks (including in the task's own task callback) and
* in multi-threaded environment in other threads as well.
*
***/
-SilcBool silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
+void silc_schedule_task_del(SilcSchedule schedule, SilcTask task);
/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_fd
*
* SYNOPSIS
*
- * SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule,
- * SilcUInt32 fd);
+ * void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd);
*
* DESCRIPTION
*
- * Deletes a task from the scheduler by the specified `fd'. Returns
- * FALSE if such fd task does not exist.
+ * Deletes a task from the scheduler by the specified `fd'.
*
* It is safe to call this function in any place. Tasks may be removed
* in task callbacks (including in the task's own task callback) and
* in multi-threaded environment in other threads as well.
*
+ * Note that generic tasks cannot be deleted using this function
+ * since generic tasks does not match any specific fd.
+ *
***/
-SilcBool silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd);
+void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd);
/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_callback
*
* SYNOPSIS
*
- * SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
- * SilcTaskCallback callback);
+ * void silc_schedule_task_del_by_callback(SilcSchedule schedule,
+ * SilcTaskCallback callback);
*
* DESCRIPTION
*
* Deletes a task from the scheduler by the specified `callback' task
- * callback function. Returns FALSE if such task with such callback
- * does not exist.
+ * callback function.
*
* It is safe to call this function in any place. Tasks may be removed
* in task callbacks (including in the task's own task callback) and
* in multi-threaded environment in other threads as well.
*
***/
-SilcBool silc_schedule_task_del_by_callback(SilcSchedule schedule,
- SilcTaskCallback callback);
+void silc_schedule_task_del_by_callback(SilcSchedule schedule,
+ SilcTaskCallback callback);
/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_context
*
* SYNOPSIS
*
- * SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule,
- * void *context);
- *
- * DESCRIPTION
- *
- * Deletes a task from the scheduler by the specified `context'. Returns
- * FALSE if such task with such context does not exist.
- *
- * It is safe to call this function in any place. Tasks may be removed
- * in task callbacks (including in the task's own task callback) and
- * in multi-threaded environment in other threads as well.
- *
- ***/
-SilcBool silc_schedule_task_del_by_context(SilcSchedule schedule,
- void *context);
-
-/****f* silcutil/SilcScheduleAPI/silc_schedule_task_del_by_all
- *
- * SYNOPSIS
- *
- * SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
- * SilcTaskCallback callback,
+ * void silc_schedule_task_del_by_context(SilcSchedule schedule,
* void *context);
*
* DESCRIPTION
*
- * Deletes a task from the scheduler by the specified `fd', `callback'
- * and `context'. Returns FALSE if such task does not exist.
+ * Deletes a task from the scheduler by the specified `context'.
*
* It is safe to call this function in any place. Tasks may be removed
* in task callbacks (including in the task's own task callback) and
* in multi-threaded environment in other threads as well.
*
***/
-SilcBool silc_schedule_task_del_by_all(SilcSchedule schedule, int fd,
- SilcTaskCallback callback,
- void *context);
+void silc_schedule_task_del_by_context(SilcSchedule schedule, void *context);
/****f* silcutil/SilcScheduleAPI/silc_schedule_set_listen_fd
*
* SYNOPSIS
*
- * SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule,
- * SilcUInt32 fd,
- * SilcTaskEvent mask,
- * SilcBool send_events);
+ * void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
+ * SilcTaskEvent mask, bool send_events);
*
* DESCRIPTION
*
* after the event occurs in reality. In normal cases the `send_events'
* is set to FALSE.
*
- * Returns FALSE if the operation could not performed and TRUE if it
- * was a success.
+ ***/
+void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
+ SilcTaskEvent mask, bool send_events);
+
+/****f* silcutil/SilcScheduleAPI/silc_schedule_unset_listen_fd
+ *
+ * SYNOPSIS
+ *
+ * void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
+ *
+ * DESCRIPTION
+ *
+ * Tells the scheduler not to listen anymore for the specified
+ * file descriptor `fd'. No events will be detected for the `fd'
+ * after calling this function.
*
***/
-SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
- SilcTaskEvent mask, SilcBool send_events);
+void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
-/****f* silcutil/SilcScheduleAPI/silc_schedule_get_fd_events
+/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_register
*
* SYNOPSIS
*
- * SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
- * SilcUInt32 fd);
+ * void silc_schedule_signal_register(SilcSchedule schedule,
+ * SilcUInt32 signal,
+ * SilcTaskCallback callback,
+ * void *context);
*
* DESCRIPTION
*
- * Returns the file descriptor `fd' current requested events mask,
- * or 0 on error.
+ * Register signal indicated by `signal' to the scheduler. Application
+ * should register all signals it is going to use to the scheduler.
+ * The `callback' with `context' will be called after the application
+ * has called silc_schedule_signal_call function in the real signal
+ * callback. Application is responsible of calling that, and the
+ * signal system will not work without calling silc_schedule_signal_call
+ * function. The specified `signal' value will be also delivered to
+ * the `callback' as the fd-argument. The event type in the callback
+ * will be SILC_TASK_INTERRUPT. It is safe to use any SILC routines
+ * in the `callback' since it is actually called after the signal really
+ * happened.
+ *
+ * On platform that does not support signals calling this function has
+ * no effect.
+ *
+ * EXAMPLE
+ *
+ * Typical signal usage case on Unix systems:
+ *
+ * struct sigaction sa;
+ * sa.sa_handler = signal_handler;
+ * sigaction(SIGHUP, &sa, NULL);
+ * sigaction(SIGINT, &sa, NULL);
+ * silc_schedule_signal_register(schedule, SIGHUP, hup_signal, context);
+ * silc_schedule_signal_register(schedule, SIGINT, int_signal, context);
+ *
+ * static void signal_handler(int sig)
+ * {
+ * silc_schedule_signal_call(schedule, sig);
+ * }
+ *
+ * The `signal_handler' can be used as generic signal callback in the
+ * application that merely calls silc_schedule_signal_call, which then
+ * eventually will deliver for example the `hup_signal' callback. The
+ * same `signal_handler' can be used with all signals.
*
***/
-SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
- SilcUInt32 fd);
+void silc_schedule_signal_register(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context);
-/****f* silcutil/SilcScheduleAPI/silc_schedule_unset_listen_fd
+/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_unregister
*
* SYNOPSIS
*
- * void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
+ * void silc_schedule_signal_unregister(SilcSchedule schedule,
+ * SilcUInt32 signal,
+ * SilcTaskCallback callback,
+ * void *context);
*
* DESCRIPTION
*
- * Tells the scheduler not to listen anymore for the specified
- * file descriptor `fd'. No events will be detected for the `fd'
- * after calling this function.
+ * Unregister a signal indicated by `signal' from the scheduler. On
+ * platform that does not support signals calling this function has no
+ * effect.
*
***/
-void silc_schedule_unset_listen_fd(SilcSchedule schedule, SilcUInt32 fd);
+void silc_schedule_signal_unregister(SilcSchedule schedule, SilcUInt32 signal,
+ SilcTaskCallback callback, void *context);
-#include "silcschedule_i.h"
+/****f* silcutil/SilcScheduleAPI/silc_schedule_signal_call
+ *
+ * SYNOPSIS
+ *
+ * void silc_schedule_signal_call(SilcSchedule schedule,
+ * SilcUInt32 signal);
+ *
+ * DESCRIPTION
+ *
+ * Mark the `signal' to be called later. Every signal that has been
+ * registered by silc_schedule_signal_register is delivered by calling
+ * this function. When signal really occurs, the application is
+ * responsible of calling this function in the signal handler. After
+ * signal is over the scheduler will then safely deliver the callback
+ * that was given to silc_schedule_signal_register function.
+ *
+ ***/
+void silc_schedule_signal_call(SilcSchedule schedule, SilcUInt32 signal);
#endif
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 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
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
#ifndef SILCSCHEDULE_I_H
#define SILCSCHEDULE_I_H
-#ifndef SILCSCHEDULE_H
-#error "Do not include this header directly"
-#endif
-
-#include "silchashtable.h"
-#include "silclist.h"
-
-/* Task header */
-struct SilcTaskStruct {
- struct SilcTaskStruct *next;
- SilcTaskCallback callback;
- void *context;
- unsigned int type : 1; /* 0 = fd, 1 = timeout */
- unsigned int valid : 1; /* Set if task is valid */
-};
-
-/* Timeout task */
-typedef struct SilcTaskTimeoutStruct {
- struct SilcTaskStruct header;
- struct timeval timeout;
-} *SilcTaskTimeout;
+#include "silcincludes.h"
-/* Fd task */
-typedef struct SilcTaskFdStruct {
- struct SilcTaskStruct header;
- unsigned int scheduled : 1;
- unsigned int events : 14;
- unsigned int revents : 15;
- SilcUInt32 fd;
-} *SilcTaskFd;
-
-/* Scheduler context */
-struct SilcScheduleStruct {
- void *internal;
- void *app_context; /* Application specific context */
- SilcHashTable fd_queue; /* FD task queue */
- SilcList fd_dispatch; /* Dispatched FDs */
- SilcList timeout_queue; /* Timeout queue */
- SilcList free_tasks; /* Timeout task freelist */
- SilcMutex lock; /* Scheduler lock */
- struct timeval timeout; /* Current timeout */
- unsigned int max_tasks : 29; /* Max FD tasks */
- unsigned int has_timeout : 1; /* Set if timeout is set */
- unsigned int valid : 1; /* Set if scheduler is valid */
- unsigned int signal_tasks : 1; /* Set if to dispatch signals */
-};
-
-/* Locks. These also blocks signals that we care about and thus guarantee
- that while we are in scheduler no signals can happen. This way we can
- synchronise signals with SILC Scheduler. */
-#define SILC_SCHEDULE_LOCK(schedule) \
-do { \
- silc_mutex_lock(schedule->lock); \
- schedule_ops.signals_block(schedule, schedule->internal); \
-} while (0)
-#define SILC_SCHEDULE_UNLOCK(schedule) \
-do { \
- schedule_ops.signals_unblock(schedule, schedule->internal); \
- silc_mutex_unlock(schedule->lock); \
-} while (0)
-
-/* Platform specific scheduler operations */
+/* Schedule FD structure. Includes the file descriptors that the scheduler
+ will listen. This is given as argument to the silc_select function. */
typedef struct {
- /* Initializes the platform specific scheduler. This for example initializes
- the wakeup mechanism of the scheduler. In multi-threaded environment
- the scheduler needs to be wakenup when tasks are added or removed from
- the task queues. Returns context to the platform specific scheduler.
- If this returns NULL the scheduler initialization will fail. */
- void *(*init)(SilcSchedule schedule, void *app_context);
-
- /* Uninitializes the platform specific scheduler context. */
- void (*uninit)(SilcSchedule schedule, void *context);
-
- /* System specific waiter. This must fill the schedule->fd_dispatch queue
- with valid tasks that has something to dispatch, when this returns. */
- int (*schedule)(SilcSchedule schedule, void *context);
+ SilcUInt32 fd; /* The file descriptor (or handle on WIN32) */
+ SilcUInt16 events; /* Mask of task events, if events is 0 then
+ the fd must be omitted. */
+ SilcUInt16 revents; /* Returned events mask */
+} *SilcScheduleFd;
- /* Schedule `task' with events `event_mask'. Zero `event_mask'
- unschedules the task. */
- SilcBool (*schedule_fd)(SilcSchedule schedule, void *context,
- SilcTaskFd task, SilcTaskEvent event_mask);
-
- /* Wakes up the scheduler. This is platform specific routine */
- void (*wakeup)(SilcSchedule schedule, void *context);
-
- /* Register signal */
- void (*signal_register)(SilcSchedule schedule, void *context,
- SilcUInt32 signal, SilcTaskCallback callback,
- void *callback_context);
-
- /* Unregister signal */
- void (*signal_unregister)(SilcSchedule schedule, void *context,
- SilcUInt32 signal);
-
- /* Call all signals */
- void (*signals_call)(SilcSchedule schedule, void *context);
-
- /* Block registered signals in scheduler. */
- void (*signals_block)(SilcSchedule schedule, void *context);
-
- /* Unblock registered signals in schedule. */
- void (*signals_unblock)(SilcSchedule schedule, void *context);
-} SilcScheduleOps;
-
-/* The generic function to add any type of task to the scheduler. This
- used to be exported as is to application, but now they should use the
- macro wrappers defined in silcschedule.h. For Fd task the timeout must
- be zero, for timeout task the timeout must not be zero, for signal task
- the fd argument is the signal. */
-SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
- SilcTaskCallback callback, void *context,
- long seconds, long useconds,
- SilcTaskType type);
-
-#ifdef SILC_DIST_INPLACE
-/* Print scheduler statistics to stdout. */
-void silc_schedule_stats(SilcSchedule schedule);
-#endif /* SILC_DIST_INPLACE */
-
-#endif /* SILCSCHEDULE_I_H */
+#endif
+++ /dev/null
-/*
- * Copyright Patrick Powell 1995
- * This code is based on code written by Patrick Powell (papowell@astart.com)
- * It may be used for any purpose as long as this notice remains intact
- * on all source code distributions
- */
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (dopr) included.
- * Sigh. This sort of thing is always nasty do deal with. Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length. This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- *
- * More Recently:
- * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
- * This was ugly. It is still ugly. I opted out of floating point
- * numbers, but the formatter understands just about everything
- * from the normal C string format, at least as far as I can tell from
- * the Solaris 2.5 printf(3S) man page.
- *
- * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
- * Ok, added some minimal floating point support, which means this
- * probably requires libm on most operating systems. Don't yet
- * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
- * was pretty badly broken, it just wasn't being exercised in ways
- * which showed it, so that's been fixed. Also, formated the code
- * to mutt conventions, and removed dead code left over from the
- * original. Also, there is now a builtin-test, just compile with:
- * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
- * and run snprintf for results.
- *
- * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
- * The PGP code was using unsigned hexadecimal formats.
- * Unfortunately, unsigned formats simply didn't work.
- *
- * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
- * The original code assumed that both snprintf() and vsnprintf() were
- * missing. Some systems only have snprintf() but not vsnprintf(), so
- * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
- *
- * Andrew Tridgell (tridge@samba.org) Oct 1998
- * fixed handling of %.0f
- * added test for HAVE_LONG_DOUBLE
- *
- * tridge@samba.org, idra@samba.org, April 2001
- * got rid of fcvt code (twas buggy and made testing harder)
- * added C99 semantics
- *
- **************************************************************/
-
-#include "silc.h"
-
-#ifdef HAVE_LONG_DOUBLE
-#define LDOUBLE long double
-#else
-#define LDOUBLE double
-#endif
-
-#ifdef HAVE_LONG_LONG
-#define LLONG long long
-#else
-#define LLONG long
-#endif
-
-/*
- * dopr(): poor man's version of doprintf
- */
-
-/* format read states */
-#define DP_S_DEFAULT 0
-#define DP_S_FLAGS 1
-#define DP_S_MIN 2
-#define DP_S_DOT 3
-#define DP_S_MAX 4
-#define DP_S_MOD 5
-#define DP_S_CONV 6
-#define DP_S_DONE 7
-
-/* format flags - Bits */
-#define DP_F_MINUS (1 << 0)
-#define DP_F_PLUS (1 << 1)
-#define DP_F_SPACE (1 << 2)
-#define DP_F_NUM (1 << 3)
-#define DP_F_ZERO (1 << 4)
-#define DP_F_UP (1 << 5)
-#define DP_F_UNSIGNED (1 << 6)
-#define DP_F_HEXPREFIX (1 << 7)
-
-/* Conversion Flags */
-#define DP_C_SHORT 1
-#define DP_C_LONG 2
-#define DP_C_LDOUBLE 3
-#define DP_C_LLONG 4
-
-#define char_to_int(p) ((p)- '0')
-#ifndef MAX
-#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
-#endif
-
-static size_t dopr(char *buffer, size_t maxlen, const char *format,
- va_list args_in);
-static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
- char *value, int flags, int min, int max);
-static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
- long value, int base, int min, int max, int flags);
-static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags);
-static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
-
-static size_t dopr(char *buffer, size_t maxlen, const char *format,
- va_list args_in)
-{
- char ch;
- LLONG value;
- LDOUBLE fvalue;
- char *strvalue;
- int min;
- int max;
- int state;
- int flags;
- int cflags;
- size_t currlen;
- va_list args;
-
- silc_va_copy(args, args_in);
-
- state = DP_S_DEFAULT;
- currlen = flags = cflags = min = 0;
- max = -1;
- ch = *format++;
-
- while (state != DP_S_DONE) {
- if (ch == '\0')
- state = DP_S_DONE;
-
- switch(state) {
- case DP_S_DEFAULT:
- if (ch == '%')
- state = DP_S_FLAGS;
- else
- dopr_outch (buffer, &currlen, maxlen, ch);
- ch = *format++;
- break;
- case DP_S_FLAGS:
- switch (ch) {
- case '-':
- flags |= DP_F_MINUS;
- ch = *format++;
- break;
- case '+':
- flags |= DP_F_PLUS;
- ch = *format++;
- break;
- case ' ':
- flags |= DP_F_SPACE;
- ch = *format++;
- break;
- case '#':
- flags |= DP_F_NUM;
- ch = *format++;
- break;
- case '0':
- flags |= DP_F_ZERO;
- ch = *format++;
- break;
- default:
- state = DP_S_MIN;
- break;
- }
- break;
- case DP_S_MIN:
- if (isdigit((unsigned char)ch)) {
- min = 10*min + char_to_int (ch);
- ch = *format++;
- } else if (ch == '*') {
- min = va_arg (args, int);
- ch = *format++;
- state = DP_S_DOT;
- } else {
- state = DP_S_DOT;
- }
- break;
- case DP_S_DOT:
- if (ch == '.') {
- state = DP_S_MAX;
- ch = *format++;
- } else {
- state = DP_S_MOD;
- }
- break;
- case DP_S_MAX:
- if (isdigit((unsigned char)ch)) {
- if (max < 0)
- max = 0;
- max = 10*max + char_to_int (ch);
- ch = *format++;
- } else if (ch == '*') {
- max = va_arg (args, int);
- ch = *format++;
- state = DP_S_MOD;
- } else {
- state = DP_S_MOD;
- }
- break;
- case DP_S_MOD:
- switch (ch) {
- case 'h':
- cflags = DP_C_SHORT;
- ch = *format++;
- break;
- case 'l':
- cflags = DP_C_LONG;
- ch = *format++;
- if (ch == 'l') { /* It's a long long */
- cflags = DP_C_LLONG;
- ch = *format++;
- }
- break;
- case 'L':
- cflags = DP_C_LDOUBLE;
- ch = *format++;
- break;
- default:
- break;
- }
- state = DP_S_CONV;
- break;
- case DP_S_CONV:
- switch (ch) {
- case 'd':
- case 'i':
- if (cflags == DP_C_SHORT)
- value = va_arg (args, int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, LLONG);
- else
- value = va_arg (args, int);
- fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'o':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int);
- else if (cflags == DP_C_LONG)
- value = (long)va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = (long)va_arg (args, unsigned LLONG);
- else
- value = (long)va_arg (args, unsigned int);
- fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
- break;
- case 'u':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int);
- else if (cflags == DP_C_LONG)
- value = (long)va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = (LLONG)va_arg (args, unsigned LLONG);
- else
- value = (long)va_arg (args, unsigned int);
- fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'X':
- flags |= DP_F_UP;
- case 'x':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = va_arg (args, unsigned int);
- else if (cflags == DP_C_LONG)
- value = (long)va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = (LLONG)va_arg (args, unsigned LLONG);
- else
- value = (long)va_arg (args, unsigned int);
- fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
- break;
- case 'f':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'E':
- flags |= DP_F_UP;
- case 'e':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'G':
- flags |= DP_F_UP;
- case 'g':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'c':
- dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
- break;
- case 's':
- strvalue = va_arg (args, char *);
- if (!strvalue) strvalue = "(NULL)";
- if (max == -1) {
- max = strlen(strvalue);
- }
- if (min > 0 && max >= 0 && min > max) max = min;
- fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
- break;
- case 'p':
- flags |= (DP_F_UNSIGNED | DP_F_HEXPREFIX);
- strvalue = va_arg (args, void *);
- fmtint (buffer, &currlen, maxlen, (long )strvalue, 16, min, max,
- flags);
- break;
- case 'n':
- if (cflags == DP_C_SHORT) {
- short int *num;
- num = va_arg (args, short int *);
- *num = currlen;
- } else if (cflags == DP_C_LONG) {
- long int *num;
- num = va_arg (args, long int *);
- *num = (long int)currlen;
- } else if (cflags == DP_C_LLONG) {
- LLONG *num;
- num = va_arg (args, LLONG *);
- *num = (LLONG)currlen;
- } else {
- int *num;
- num = va_arg (args, int *);
- *num = currlen;
- }
- break;
- case '%':
- dopr_outch (buffer, &currlen, maxlen, ch);
- break;
- case 'w':
- /* not supported yet, treat as next char */
- ch = *format++;
- break;
- default:
- /* Unknown, skip */
- break;
- }
- ch = *format++;
- state = DP_S_DEFAULT;
- flags = cflags = min = 0;
- max = -1;
- break;
- case DP_S_DONE:
- break;
- default:
- /* hmm? */
- break; /* some picky compilers need this */
- }
- }
- if (maxlen != 0) {
- if (currlen < maxlen - 1)
- buffer[currlen] = '\0';
- else if (maxlen > 0)
- buffer[maxlen - 1] = '\0';
- }
-
- return currlen;
-}
-
-static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
- char *value, int flags, int min, int max)
-{
- int padlen, strln; /* amount to pad */
- int cnt = 0;
-
- if (value == 0) {
- value = "<NULL>";
- }
-
- for (strln = 0; value[strln]; ++strln); /* strlen */
- padlen = min - strln;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justify */
-
- while ((padlen > 0) && (cnt < max)) {
- dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- ++cnt;
- }
- while (*value && (cnt < max)) {
- dopr_outch (buffer, currlen, maxlen, *value++);
- ++cnt;
- }
- while ((padlen < 0) && (cnt < max)) {
- dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- ++cnt;
- }
-}
-
-/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
-
-static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
- long value, int base, int min, int max, int flags)
-{
- int signvalue = 0;
- unsigned long uvalue;
- char convert[20];
- int place = 0;
- int spadlen = 0; /* amount to space pad */
- int zpadlen = 0; /* amount to zero pad */
- int caps = 0;
-
- if (max < 0)
- max = 0;
-
- uvalue = value;
-
- if(!(flags & DP_F_UNSIGNED)) {
- if( value < 0 ) {
- signvalue = '-';
- uvalue = -value;
- } else {
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else if (flags & DP_F_SPACE)
- signvalue = ' ';
- }
- }
-
- if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
-
- do {
- convert[place++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")
- [uvalue % (unsigned)base ];
- uvalue = (uvalue / (unsigned)base );
- } while(uvalue && (place < 20));
- if (place == 20) place--;
- convert[place] = 0;
-
- zpadlen = max - place;
- spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
- if (zpadlen < 0) zpadlen = 0;
- if (spadlen < 0) spadlen = 0;
- if (flags & DP_F_ZERO) {
- zpadlen = MAX(zpadlen, spadlen);
- spadlen = 0;
- }
- if (flags & DP_F_MINUS)
- spadlen = -spadlen; /* Left Justifty */
-
- /* Spaces */
- while (spadlen > 0) {
- dopr_outch (buffer, currlen, maxlen, ' ');
- --spadlen;
- }
-
- /* 0x prefix */
- if (flags & DP_F_HEXPREFIX) {
- dopr_outch (buffer, currlen, maxlen, '0');
- dopr_outch (buffer, currlen, maxlen, 'x');
- }
-
- /* Sign */
- if (signvalue)
- dopr_outch (buffer, currlen, maxlen, signvalue);
-
- /* Zeros */
- if (zpadlen > 0) {
- while (zpadlen > 0) {
- dopr_outch (buffer, currlen, maxlen, '0');
- --zpadlen;
- }
- }
-
- /* Digits */
- while (place > 0)
- dopr_outch (buffer, currlen, maxlen, convert[--place]);
-
- /* Left Justified spaces */
- while (spadlen < 0) {
- dopr_outch (buffer, currlen, maxlen, ' ');
- ++spadlen;
- }
-}
-
-static LDOUBLE abs_val(LDOUBLE value)
-{
- LDOUBLE result = value;
-
- if (value < 0)
- result = -value;
-
- return result;
-}
-
-static LDOUBLE POW10(int exp)
-{
- LDOUBLE result = 1;
-
- while (exp) {
- result *= 10;
- exp--;
- }
-
- return result;
-}
-
-static LLONG ROUND(LDOUBLE value)
-{
- LLONG intpart;
-
- intpart = (LLONG)value;
- value = value - intpart;
- if (value >= 0.5) intpart++;
-
- return intpart;
-}
-
-/* a replacement for modf that doesn't need the math library. Should
- be portable, but slow */
-static double my_modf(double x0, double *iptr)
-{
- int i;
- long l;
- double x = x0;
- double f = 1.0;
-
- for (i=0;i<100;i++) {
- l = (long)x;
- if (l <= (x+1) && l >= (x-1)) break;
- x *= 0.1;
- f *= 10.0;
- }
-
- if (i == 100) {
- /* yikes! the number is beyond what we can handle.
- What do we do? */
- (*iptr) = 0;
- return 0;
- }
-
- if (i != 0) {
- double i2;
- double ret;
-
- ret = my_modf(x0-l*f, &i2);
- (*iptr) = l*f + i2;
- return ret;
- }
-
- (*iptr) = l;
- return x - (*iptr);
-}
-
-
-static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags)
-{
- int signvalue = 0;
- double ufvalue;
- char iconvert[311];
- char fconvert[311];
- int iplace = 0;
- int fplace = 0;
- int padlen = 0; /* amount to pad */
- int zpadlen = 0;
- int caps = 0;
- int idx;
- double intpart;
- double fracpart;
- double temp;
-
- /*
- * AIX manpage says the default is 0, but Solaris says the default
- * is 6, and sprintf on AIX defaults to 6
- */
- if (max < 0)
- max = 6;
-
- ufvalue = abs_val (fvalue);
-
- if (fvalue < 0) {
- signvalue = '-';
- } else {
- if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
- signvalue = '+';
- } else {
- if (flags & DP_F_SPACE)
- signvalue = ' ';
- }
- }
-
-#if 0
- if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
-#endif
-
-#if 0
- if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
-#endif
-
- /*
- * Sorry, we only support 16 digits past the decimal because of our
- * conversion method
- */
- if (max > 16)
- max = 16;
-
- /* We "cheat" by converting the fractional part to integer by
- * multiplying by a factor of 10
- */
-
- temp = ufvalue;
- my_modf(temp, &intpart);
-
- fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
-
- if (fracpart >= POW10(max)) {
- intpart++;
- fracpart -= POW10(max);
- }
-
-
- /* Convert integer part */
- do {
- temp = intpart*0.1;
- my_modf(temp, &intpart);
- idx = (int) ((temp -intpart +0.05)* 10.0);
- /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
- /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
- iconvert[iplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
- } while (intpart && (iplace < 311));
- if (iplace == 311) iplace--;
- iconvert[iplace] = 0;
-
- /* Convert fractional part */
- if (fracpart)
- {
- do {
- temp = fracpart*0.1;
- my_modf(temp, &fracpart);
- idx = (int) ((temp -fracpart +0.05)* 10.0);
- /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
- /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
- fconvert[fplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
- } while(fracpart && (fplace < 311));
- if (fplace == 311) fplace--;
- }
- fconvert[fplace] = 0;
-
- /* -1 for decimal point, another -1 if we are printing a sign */
- padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
- zpadlen = max - fplace;
- if (zpadlen < 0) zpadlen = 0;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justifty */
-
- if ((flags & DP_F_ZERO) && (padlen > 0)) {
- if (signvalue) {
- dopr_outch (buffer, currlen, maxlen, signvalue);
- --padlen;
- signvalue = 0;
- }
- while (padlen > 0) {
- dopr_outch (buffer, currlen, maxlen, '0');
- --padlen;
- }
- }
- while (padlen > 0) {
- dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- if (signvalue)
- dopr_outch (buffer, currlen, maxlen, signvalue);
-
- while (iplace > 0)
- dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
-
- /*
- * Decimal point. This should probably use locale to find the correct
- * char to print out.
- */
- if (max > 0) {
- dopr_outch (buffer, currlen, maxlen, '.');
-
- while (zpadlen > 0) {
- dopr_outch (buffer, currlen, maxlen, '0');
- --zpadlen;
- }
-
- while (fplace > 0)
- dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
- }
-
- while (padlen < 0) {
- dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
-}
-
-static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
-{
- if (*currlen < maxlen) {
- buffer[(*currlen)] = c;
- }
- (*currlen)++;
-}
-
-int silc_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
-{
- if (str != NULL)
- str[0] = 0;
- return dopr(str, count, fmt, args);
-}
-
-int silc_snprintf(char *str, size_t count, const char *fmt, ...)
-{
- size_t ret;
- va_list ap;
-
- va_start(ap, fmt);
- ret = silc_vsnprintf(str, count, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-int silc_vasprintf(char **ptr, const char *format, va_list ap)
-{
- int ret;
- va_list ap2;
-
- silc_va_copy(ap2, ap);
-
- ret = silc_vsnprintf(NULL, 0, format, ap2);
- if (ret <= 0) return ret;
-
- (*ptr) = (char *)silc_malloc(ret+1);
- if (!*ptr) return -1;
-
- silc_va_copy(ap2, ap);
-
- ret = silc_vsnprintf(*ptr, ret+1, format, ap2);
-
- return ret;
-}
-
-int silc_asprintf(char **ptr, const char *format, ...)
-{
- va_list ap;
- int ret;
-
- *ptr = NULL;
- va_start(ap, format);
- ret = silc_vasprintf(ptr, format, ap);
- va_end(ap);
-
- return ret;
-}
+++ /dev/null
-/*
-
- silcsnprintf.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2007 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* silcutil/Snprintf
- *
- * DESCRIPTION
- *
- * Platform independent version of snprintf and other similar string
- * formatting routines.
- *
- ***/
-
-#ifndef SILCSNPRINTF_H
-#define SILCSNPRINTF_H
-
-/****f* silcutil/SilcSnprintf/silc_snprintf
- *
- * SYNOPSIS
- *
- * int silc_snprintf(char *str, size_t count, const char *fmt, ...);
- *
- * DESCRIPTION
- *
- * Outputs string into `str' of maximum of size `count' including the
- * trailing '\0' according to the `fmt'. The `fmt' is equivalent to
- * snprintf(3) and printf(3) formatting. Returns the number of character
- * in `str' or negative value on error.
- *
- ***/
-int silc_snprintf(char *str, size_t count, const char *fmt, ...);
-
-/****f* silcutil/SilcSnprintf/silc_vsnprintf
- *
- * SYNOPSIS
- *
- * int silc_vsnprintf(char *str, size_t count, const char *fmt,
- * va_list args)
- *
- * DESCRIPTION
- *
- * Same as silc_snprintf but takes the argument for the formatting from
- * the `args' variable argument list.
- *
- ***/
-int silc_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
-
-/****f* silcutil/SilcSnprintf/silc_asprintf
- *
- * SYNOPSIS
- *
- * int silc_asprintf(char **ptr, const char *format, ...)
- *
- * DESCRIPTION
- *
- * Same as silc_snprintf but allocates a string large enough to hold the
- * output including the trailing '\0'. The caller must free the `ptr'.
- *
- ***/
-int silc_asprintf(char **ptr, const char *format, ...);
-
-/****f* silcutil/SilcSnprintf/silc_vasprintf
- *
- * SYNOPSIS
- *
- * int silc_vasprintf(char **ptr, const char *format, va_list ap)
- *
- * DESCRIPTION
- *
- * Same as silc_asprintf but takes the argument from the `ap' variable
- * argument list.
- *
- ***/
-int silc_vasprintf(char **ptr, const char *format, va_list ap);
-
-#endif /* SILCSNPRINTF_H */
--- /dev/null
+/*
+
+ silcsockconn.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2003 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 "silcincludes.h"
+
+/* Heartbeat context */
+struct SilcSocketConnectionHBStruct {
+ SilcUInt32 heartbeat;
+ SilcSocketConnectionHBCb hb_callback;
+ void *hb_context;
+ SilcSchedule schedule;
+ SilcTask hb_task;
+ SilcSocketConnection sock;
+};
+
+/* Internal async host lookup context. */
+typedef struct {
+ SilcSocketHostLookupCb callback;
+ void *context;
+ SilcSchedule schedule;
+ SilcSocketConnection sock;
+ bool port;
+} *SilcSocketHostLookup;
+
+/* Allocates a new socket connection object. The allocated object is
+ returned to the new_socket argument. */
+
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
+ SilcSocketConnection *new_socket)
+{
+ SILC_LOG_DEBUG(("Allocating new socket connection object"));
+
+ /* Set the pointers. Incoming and outgoing data buffers
+ are allocated by the application when they are first used. */
+ *new_socket = silc_calloc(1, sizeof(**new_socket));
+ (*new_socket)->sock = sock;
+ (*new_socket)->type = type;
+ (*new_socket)->user_data = user_data;
+ (*new_socket)->protocol = NULL;
+ (*new_socket)->flags = 0;
+ (*new_socket)->inbuf = NULL;
+ (*new_socket)->outbuf = NULL;
+ (*new_socket)->users++;
+}
+
+/* Free's the Socket connection object. */
+
+void silc_socket_free(SilcSocketConnection sock)
+{
+ sock->users--;
+ SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users + 1,
+ sock->users));
+ if (sock->users < 1) {
+ silc_buffer_free(sock->inbuf);
+ silc_buffer_free(sock->outbuf);
+ if (sock->hb) {
+ silc_schedule_task_del(sock->hb->schedule, sock->hb->hb_task);
+ silc_free(sock->hb);
+ }
+ if (sock->qos) {
+ silc_schedule_task_del_by_context(sock->qos->schedule, sock->qos);
+ silc_free(sock->qos);
+ }
+ silc_free(sock->ip);
+ silc_free(sock->hostname);
+
+ memset(sock, 'F', sizeof(*sock));
+ silc_free(sock);
+ }
+}
+
+/* Increase the reference counter. */
+
+SilcSocketConnection silc_socket_dup(SilcSocketConnection sock)
+{
+ sock->users++;
+ SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users - 1,
+ sock->users));
+ return sock;
+}
+
+/* Internal timeout callback to perform heartbeat */
+
+SILC_TASK_CALLBACK(silc_socket_heartbeat)
+{
+ SilcSocketConnectionHB hb = (SilcSocketConnectionHB)context;
+
+ if (!hb->heartbeat)
+ return;
+
+ if (SILC_IS_DISCONNECTING(hb->sock) ||
+ SILC_IS_DISCONNECTED(hb->sock))
+ return;
+
+ if (hb->hb_callback)
+ hb->hb_callback(hb->sock, hb->hb_context);
+
+ hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock,
+ silc_socket_heartbeat,
+ context, hb->heartbeat, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+}
+
+/* Sets the heartbeat timeout and prepares the socket for performing
+ heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
+ allocated by the application and will be sent as argument to the
+ `hb_callback' function that is called when the `heartbeat' timeout
+ expires. The callback `hb_context' won't be touched by the library
+ but will be freed automatically when calling silc_socket_free. The
+ `schedule' is the application's scheduler. */
+
+void silc_socket_set_heartbeat(SilcSocketConnection sock,
+ SilcUInt32 heartbeat,
+ void *hb_context,
+ SilcSocketConnectionHBCb hb_callback,
+ SilcSchedule schedule)
+{
+ if (sock->hb) {
+ silc_schedule_task_del(schedule, sock->hb->hb_task);
+ silc_free(sock->hb);
+ }
+
+ sock->hb = silc_calloc(1, sizeof(*sock->hb));
+ sock->hb->heartbeat = heartbeat;
+ sock->hb->hb_context = hb_context;
+ sock->hb->hb_callback = hb_callback;
+ sock->hb->schedule = schedule;
+ sock->hb->sock = sock;
+ sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
+ silc_socket_heartbeat,
+ (void *)sock->hb, heartbeat, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+}
+
+/* Sets a "Quality of Service" settings for socket connection `sock'.
+ The `read_rate' specifies the maximum read operations per second.
+ If more read operations are executed the limit will be applied for
+ the reading. The `read_limit_bytes' specifies the maximum data
+ that is read. It is guaranteed that silc_socket_read never returns
+ more that `read_limit_bytes' of data. If more is read the limit
+ will be applied for the reading. The `limit_sec' and `limit_usec'
+ specifies the limit that is applied if `read_rate' and/or
+ `read_limit_bytes' is reached. The `schedule' is the application's
+ scheduler. */
+
+void silc_socket_set_qos(SilcSocketConnection sock,
+ SilcUInt32 read_rate,
+ SilcUInt32 read_limit_bytes,
+ SilcUInt32 limit_sec,
+ SilcUInt32 limit_usec,
+ SilcSchedule schedule)
+{
+ if (!sock)
+ return;
+
+ if (sock->qos && !read_rate && !read_limit_bytes &&
+ !limit_sec && !limit_usec && !schedule) {
+ silc_schedule_task_del_by_context(sock->qos->schedule, sock->qos);
+ silc_free(sock->qos);
+ sock->qos = NULL;
+ return;
+ }
+ if (!schedule)
+ return;
+
+ if (!sock->qos) {
+ sock->qos = silc_calloc(1, sizeof(*sock->qos));
+ if (!sock->qos)
+ return;
+ }
+ sock->qos->read_rate = read_rate;
+ sock->qos->read_limit_bytes = read_limit_bytes;
+ sock->qos->limit_sec = limit_sec;
+ sock->qos->limit_usec = limit_usec;
+ sock->qos->schedule = schedule;
+ memset(&sock->qos->next_limit, 0, sizeof(sock->qos->next_limit));
+ sock->qos->cur_rate = 0;
+ sock->qos->sock = sock;
+}
+
+/* Finishing timeout callback that will actually call the user specified
+ host lookup callback. This is executed back in the calling thread and
+ not in the lookup thread. */
+
+SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
+{
+ SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
+
+ SILC_UNSET_HOST_LOOKUP(lookup->sock);
+
+ /* If the reference counter is 1 we know that we are the only one
+ holding the socket and it thus is considered freed. The lookup
+ is cancelled also and we will not call the final callback. */
+ if (lookup->sock->users == 1) {
+ SILC_LOG_DEBUG(("Async host lookup was cancelled"));
+ silc_socket_free(lookup->sock);
+ silc_free(lookup);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Async host lookup finished"));
+
+ silc_socket_free(lookup->sock);
+
+ /* Call the final callback. */
+ if (lookup->callback)
+ lookup->callback(lookup->sock, lookup->context);
+
+ silc_free(lookup);
+}
+
+/* The thread function that performs the actual lookup. */
+
+static void *silc_socket_host_lookup_start(void *context)
+{
+ SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
+ SilcSocketConnection sock = lookup->sock;
+ SilcSchedule schedule = lookup->schedule;
+
+ if (lookup->port)
+ sock->port = silc_net_get_remote_port(sock->sock);
+
+ silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);
+ if (!sock->hostname && sock->ip)
+ sock->hostname = strdup(sock->ip);
+
+ silc_schedule_task_add(schedule, sock->sock,
+ silc_socket_host_lookup_finish, lookup, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_schedule_wakeup(schedule);
+
+ return NULL;
+}
+
+/* Performs asynchronous host name and IP address lookups for the
+ specified socket connection. This may be called when the socket
+ connection is created and the full IP address and fully qualified
+ domain name information is desired. The `callback' with `context'
+ will be called after the lookup is performed. The `schedule'
+ is the application's scheduler which the lookup routine needs. If
+ the socket connection is freed during the lookup the library will
+ automatically cancel the lookup and the `callback' will not be called. */
+
+void silc_socket_host_lookup(SilcSocketConnection sock,
+ bool port_lookup,
+ SilcSocketHostLookupCb callback,
+ void *context,
+ SilcSchedule schedule)
+{
+ SilcSocketHostLookup lookup;
+
+ SILC_LOG_DEBUG(("Performing async host lookup"));
+
+ if (SILC_IS_DISCONNECTING(sock) ||
+ SILC_IS_DISCONNECTED(sock))
+ return;
+
+ lookup = silc_calloc(1, sizeof(*lookup));
+ lookup->sock = silc_socket_dup(sock); /* Increase reference counter */
+ lookup->callback = callback;
+ lookup->context = context;
+ lookup->schedule = schedule;
+ lookup->port = port_lookup;
+
+ SILC_SET_HOST_LOOKUP(sock);
+ silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);
+}
--- /dev/null
+/*
+
+ silcsockconn.h
+
+ Author: Pekka Riikonen <priikone@silnet.org>
+
+ Copyright (C) 1997 - 2001, 2003 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* silcutil/SILC Socket Interface
+ *
+ * DESCRIPTION
+ *
+ * Implementation of the Socket Connection object. The SilcSocketConnection
+ * is used by all applications to represent a socket based connection
+ * to the network. The Socket Connection object handles inbound and outbound
+ * data buffers, can perform keepalive actions for the connection and
+ * supports connection based protocols as well.
+ *
+ ***/
+
+#ifndef SILCSOCKCONN_H
+#define SILCSOCKCONN_H
+
+/****s* silcutil/SilcSocketConnectionAPI/SilcSocketConnection
+ *
+ * NAME
+ *
+ * typedef struct SilcSocketConnectionStruct *SilcSocketConnection;
+ *
+ * DESCRIPTION
+ *
+ * This context is forward declaration for the SilcSocketConnectionStruct.
+ * This is allocated by the silc_socket_alloc and freed by the
+ * silc_socket_free function. The silc_socket_dup can be used to
+ * increase the reference counter of the context. The data is freed
+ * by the silc_socket_free function only after the reference counter
+ * hits zero.
+ *
+ ***/
+typedef struct SilcSocketConnectionStruct *SilcSocketConnection;
+
+/****s* silcutil/SilcSocketConnectionAPI/SilcSocketConnectionHB
+ *
+ * NAME
+ *
+ * typedef struct SilcSocketConnectionHB *SilcSocketConnectionHB;
+ *
+ * DESCRIPTION
+ *
+ * This context is the heartbeat context for the SilcSockeConnection.
+ * It is meant to hold the keepalive information for the connection.
+ * This is allocated internally and freed internally by the
+ * interface routines.
+ *
+ ***/
+typedef struct SilcSocketConnectionHBStruct *SilcSocketConnectionHB;
+
+/****s* silcutil/SilcSocketConnectionAPI/SilcSocketConnectionQos
+ *
+ * NAME
+ *
+ * typedef struct SilcSocketConnectionQosStruct *SilcSocketConnectionQos;
+ *
+ * DESCRIPTION
+ *
+ * This structure is "Quality of Service" structure for the socket
+ * connection and is set with silc_socket_set_qos function for a
+ * socket context.
+ *
+ ***/
+typedef struct SilcSocketConnectionQosStruct {
+ SilcUInt16 read_limit_bytes; /* Max read bytes */
+ SilcUInt16 read_rate; /* Max read rate/second */
+ SilcUInt16 limit_sec; /* Limit seconds */
+ SilcUInt32 limit_usec; /* Limit microseconds */
+ SilcSchedule schedule;
+ struct timeval next_limit;
+ unsigned int cur_rate : 31;
+ unsigned int applied : 1;
+ SilcUInt32 data_len;
+ SilcSocketConnection sock;
+} *SilcSocketConnectionQos;
+
+/****d* silcutil/SilcSocketConnectionAPI/SilcSocketType
+ *
+ * NAME
+ *
+ * typedef enum { ... } SilcSocketType;
+ *
+ * DESCRIPTION
+ *
+ * Socket types. These identifies the socket connection. There
+ * are four different types; unknown, client, server and router.
+ * Unknown connections are connections that hasn't advanced long
+ * enough so that we might know which type of connection it is.
+ * It is the applications responsibility to update the type
+ * information when it becomes available.
+ *
+ * SOURCE
+ */
+typedef enum {
+ SILC_SOCKET_TYPE_UNKNOWN = 0,
+ SILC_SOCKET_TYPE_CLIENT = 1,
+ SILC_SOCKET_TYPE_SERVER = 2,
+ SILC_SOCKET_TYPE_ROUTER = 3
+} SilcSocketType;
+/***/
+
+/* Socket flags */
+#define SILC_SF_NONE 0
+#define SILC_SF_INBUF_PENDING 1 /* data in inbound buffer */
+#define SILC_SF_OUTBUF_PENDING 2 /* data in outbound buffer */
+#define SILC_SF_DISCONNECTING 3 /* socket disconnecting */
+#define SILC_SF_DISCONNECTED 4 /* socket disconnected */
+#define SILC_SF_HOST_LOOKUP 5 /* performing host lookup for socket */
+#define SILC_SF_DISABLED 6 /* socket connection is disabled,
+ no data is sent or received. */
+#define SILC_SF_LISTENER 7
+
+/****s* silcutil/SilcSocketConnectionAPI/SilcSocketConnectionStruct
+ *
+ * NAME
+ *
+ * struct SilcSocketConnectionStruct { ... };
+ *
+ * DESCRIPTION
+ *
+ * This object holds information about the connected sockets to the server.
+ * This is quite important object since this is referenced by the server all
+ * the time when figuring out what the connection is supposed to be doing
+ * and to whom we should send a message. This structure is the structure
+ * for the SilcSocketConnection forward declaration.
+ *
+ * Following short description of the fields:
+ *
+ * int sock
+ *
+ * The actual connected socket. This is usually saved when accepting
+ * new connection to the server.
+ *
+ * SilcSocketType type
+ *
+ * Type of the socket. This identifies the type of the connection. This
+ * is mainly used to identify whether the connection is a client or a
+ * server connection.
+ *
+ * void *user_data
+ *
+ * This is a pointer to a data that is is saved here at the same
+ * time a new connection object is allocated. Usually this is a
+ * back-pointer to some important data for fast referencing. For
+ * SILC server this is a pointer to the ID list and for SILC client
+ * to object holding active connections (windows).
+ *
+ * SilcProtocol protocol
+ *
+ * Protocol object for the socket. Currently only one protocol can be
+ * executing at a time for a particular socket.
+ *
+ * SilcUInt32 flags
+ *
+ * Socket flags that indicate the status of the socket. This can
+ * indicate several different status that can affect the use of the
+ * socket object.
+ *
+ * int users
+ *
+ * Reference counter. When allocated it is set to one (1) and it won't
+ * be freed until it hits zero (0).
+ *
+ * SilcSocketConnectionHB hb
+ *
+ * The heartbeat context. If NULL, heartbeat is not performed.
+ *
+ * SilcBuffer inbuf
+ * SilcBuffer outbuf
+ *
+ * Incoming and outgoing buffers for the particular socket connection.
+ * Incoming data from the socket is put after decryption in to the
+ * inbuf buffer and outgoing data after encryption is put to the outbuf
+ * buffer.
+ *
+ * char *hostname
+ * char *ip
+ * SilcUInt16 port
+ *
+ * Resolved hostname, IP address and port of the connection who owns
+ * this object.
+ *
+ ***/
+struct SilcSocketConnectionStruct {
+ int sock;
+ SilcSocketType type;
+ void *user_data;
+ SilcProtocol protocol;
+ SilcUInt32 flags;
+ int users;
+
+ SilcSocketConnectionHB hb;
+ SilcSocketConnectionQos qos;
+
+ SilcBuffer inbuf;
+ SilcBuffer outbuf;
+
+ char *hostname;
+ char *ip;
+ SilcUInt16 port;
+ SilcUInt8 sock_error;
+ SilcUInt8 version;
+};
+
+/* Macros */
+
+/* Check for specific protocol version */
+#define SILC_PROTOCOL_VERSION(s, maj, min) (s->version == maj##min)
+
+/* Amount of bytes to be read from the socket connection at once. */
+#define SILC_SOCKET_READ_SIZE 16384
+
+/* Default socket buffer size. */
+#define SILC_SOCKET_BUF_SIZE 1024
+
+/* Generic manipulation of flags */
+#define SF_SET(x, f) (x)->flags |= (1L << (f))
+#define SF_UNSET(x, f) (x)->flags &= ~(1L << (f))
+#define SF_IS(x, f) ((x)->flags & (1L << (f)))
+
+/* Setting/Unsetting flags */
+#define SILC_SET_OUTBUF_PENDING(x) SF_SET((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_SET_INBUF_PENDING(x) SF_SET((x), SILC_SF_INBUF_PENDING)
+#define SILC_SET_DISCONNECTING(x) SF_SET((x), SILC_SF_DISCONNECTING)
+#define SILC_SET_DISCONNECTED(x) SF_SET((x), SILC_SF_DISCONNECTED)
+#define SILC_SET_HOST_LOOKUP(x) SF_SET((x), SILC_SF_HOST_LOOKUP)
+#define SILC_SET_DISABLED(x) SF_SET((x), SILC_SF_DISABLED)
+#define SILC_SET_LISTENER(x) SF_SET((x), SILC_SF_LISTENER)
+#define SILC_UNSET_OUTBUF_PENDING(x) SF_UNSET((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_UNSET_INBUF_PENDING(x) SF_UNSET((x), SILC_SF_INBUF_PENDING)
+#define SILC_UNSET_DISCONNECTING(x) SF_UNSET((x), SILC_SF_DISCONNECTING)
+#define SILC_UNSET_DISCONNECTED(x) SF_UNSET((x), SILC_SF_DISCONNECTED)
+#define SILC_UNSET_HOST_LOOKUP(x) SF_UNSET((x), SILC_SF_HOST_LOOKUP)
+#define SILC_UNSET_DISABLED(x) SF_UNSET((x), SILC_SF_DISABLED)
+#define SILC_UNSET_LISTENER(x) SF_UNSET((x), SILC_SF_LISTENER)
+
+/* Checking for flags */
+#define SILC_IS_OUTBUF_PENDING(x) SF_IS((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_IS_INBUF_PENDING(x) SF_IS((x), SILC_SF_INBUF_PENDING)
+#define SILC_IS_DISCONNECTING(x) SF_IS((x), SILC_SF_DISCONNECTING)
+#define SILC_IS_DISCONNECTED(x) SF_IS((x), SILC_SF_DISCONNECTED)
+#define SILC_IS_HOST_LOOKUP(x) SF_IS((x), SILC_SF_HOST_LOOKUP)
+#define SILC_IS_DISABLED(x) SF_IS((x), SILC_SF_DISABLED)
+#define SILC_IS_LISTENER(x) SF_IS((x), SILC_SF_LISTENER)
+
+/* Prototypes */
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_alloc
+ *
+ * SYNOPSIS
+ *
+ * void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
+ * SilcSocketConnection *new_socket);
+ *
+ * DESCRIPTION
+ *
+ * Allocates a new socket connection object. The allocated object is
+ * returned to the new_socket argument. The `sock' is the socket
+ * for the connection, the `type' the initial type of the connection and
+ * the `user_data' a application specific pointer.
+ *
+ ***/
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
+ SilcSocketConnection *new_socket);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_socket_free(SilcSocketConnection sock);
+ *
+ * DESCRIPTION
+ *
+ * Frees the socket connection context. This frees it only if the
+ * reference counter of the socket is zero, otherwise it decreases the
+ * reference counter.
+ *
+ ***/
+void silc_socket_free(SilcSocketConnection sock);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_dup
+ *
+ * SYNOPSIS
+ *
+ * SilcSocketConnection silc_socket_dup(SilcSocketConnection sock);
+ *
+ * DESCRIPTION
+ *
+ * Duplicates the socket context. This actually does not duplicate
+ * any data, instead this increases the reference counter of the
+ * context. The reference counter is decreased by calling the
+ * silc_socket_free function and it frees the data when the counter
+ * hits zero.
+ *
+ ***/
+SilcSocketConnection silc_socket_dup(SilcSocketConnection sock);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_read
+ *
+ * SYNOPSIS
+ *
+ * int silc_socket_read(SilcSocketConnection sock);
+ *
+ * DESCRIPTION
+ *
+ * Reads data from the socket connection into the incoming data buffer.
+ * It reads as much as possible from the socket connection. This returns
+ * amount of bytes read or -1 on error or -2 on case where all of the
+ * data could not be read at once. Implementation of this function
+ * may be platform specific.
+ *
+ ***/
+int silc_socket_read(SilcSocketConnection sock);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_write
+ *
+ * SYNOPSIS
+ *
+ * int silc_socket_write(SilcSocketConnection sock);
+ *
+ * DESCRIPTION
+ *
+ * Writes data from the outgoing buffer to the socket connection. If the
+ * data cannot be written at once, it must be written at later time.
+ * The data is written from the data section of the buffer, not from head
+ * or tail section. This automatically pulls the data section towards end
+ * after writing the data. Implementation of this function may be
+ * platform specific.
+ *
+ ***/
+int silc_socket_write(SilcSocketConnection sock);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_get_error
+ *
+ * SYNOPSIS
+ *
+ * bool silc_socket_get_error(SilcSocketConnection sock, char *error,
+ * SilcUInt32 error_len);
+ *
+ * DESCRIPTION
+ *
+ * Returns human readable error message into the `error' buffer if
+ * the socket is in error status. Returns TRUE if error message was
+ * written into the buffer and FALSE if there is not socket error.
+ *
+ ***/
+bool silc_socket_get_error(SilcSocketConnection sock, char *error,
+ SilcUInt32 error_len);
+
+/****f* silcutil/SilcSocketConnectionAPI/SilcSocketConnectionHBCb
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcSocketConnectionHBCb)(SilcSocketConnection sock,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Heartbeat callback function. This is the function in the application
+ * that this library will call when it is time to send the keepalive
+ * packet SILC_PACKET_HEARTBEAT.
+ *
+ ***/
+typedef void (*SilcSocketConnectionHBCb)(SilcSocketConnection sock,
+ void *context);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_set_heartbeat
+ *
+ * SYNOPSIS
+ *
+ * void silc_socket_set_heartbeat(SilcSocketConnection sock,
+ * SilcUInt32 heartbeat,
+ * void *hb_context,
+ * SilcSocketConnectionHBCb hb_callback,
+ * SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ * Sets the heartbeat timeout and prepares the socket for performing
+ * heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
+ * allocated by the application and will be sent as argument to the
+ * `hb_callback' function that is called when the `heartbeat' timeout
+ * expires. The callback `hb_context' won't be touched by the library
+ * but and must be freed by the application. The `schedule' is the
+ * application's scheduler.
+ *
+ ***/
+void silc_socket_set_heartbeat(SilcSocketConnection sock,
+ SilcUInt32 heartbeat,
+ void *hb_context,
+ SilcSocketConnectionHBCb hb_callback,
+ SilcSchedule schedule);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_set_qos
+ *
+ * SYNOPSIS
+ *
+ * void silc_socket_set_qos(SilcSocketConnection sock,
+ * SilcUInt32 read_rate,
+ * SilcUInt32 read_limit_bytes,
+ * SilcUInt32 limit_sec,
+ * SilcUInt32 limit_usec,
+ * SilcSchedule schedule)
+ *
+ * DESCRIPTION
+ *
+ * Sets a "Quality of Service" settings for socket connection `sock'.
+ * The `read_rate' specifies the maximum read operations per second.
+ * If more read operations are executed the limit will be applied for
+ * the reading. The `read_limit_bytes' specifies the maximum data
+ * that is read. It is guaranteed that silc_socket_read never returns
+ * more that `read_limit_bytes' of data. If more is read the limit
+ * will be applied for the reading. The `limit_sec' and `limit_usec'
+ * specifies the limit that is applied if `read_rate' and/or
+ * `read_limit_bytes' is reached. The `schedule' is the application's
+ * scheduler. If all arguments except `sock' are NULL or zero this
+ * resets the QoS from the socket, all QoS for this socket that may
+ * be pending will be cancelled.
+ *
+ ***/
+void silc_socket_set_qos(SilcSocketConnection sock,
+ SilcUInt32 read_rate,
+ SilcUInt32 read_limit_bytes,
+ SilcUInt32 limit_sec,
+ SilcUInt32 limit_usec,
+ SilcSchedule schedule);
+
+/****f* silcutil/SilcSocketConnectionAPI/SilcSocketHostLookupCb
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcSocketHostLookupCb)(SilcSocketConnection sock,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Asynchronous host lookup callback function that will be called
+ * when the lookup is performed.
+ *
+ ***/
+typedef void (*SilcSocketHostLookupCb)(SilcSocketConnection sock,
+ void *context);
+
+/****f* silcutil/SilcSocketConnectionAPI/silc_socket_host_lookup
+ *
+ * SYNOPSIS
+ *
+ * void silc_socket_host_lookup(SilcSocketConnection sock,
+ * bool port_lookup,
+ * SilcSocketHostLookupCb callback,
+ * void *context,
+ * SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ * Performs asynchronous host name and IP address lookups for the
+ * specified socket connection. This may be called when the socket
+ * connection is created and the full IP address and fully qualified
+ * domain name information is desired. The `callback' with `context'
+ * will be called after the lookup is performed. The `schedule'
+ * is the application's scheduler which the lookup routine needs.
+ * If the socket connection is freed during the lookup the library
+ * will automatically cancel the lookup and the `callback' will not be
+ * called.
+ *
+ * If `port_lookup' is TRUE then the remote port of the socket
+ * connection is resolved. After the information is resolved they
+ * are accessible using sock->ip and sock->hostname pointers. Note
+ * that if the both IP and FQDN could not be resolved the sock->hostname
+ * includes the IP address of the remote host. The resolved port is
+ * available in sock->port.
+ *
+ ***/
+void silc_socket_host_lookup(SilcSocketConnection sock,
+ bool port_lookup,
+ SilcSocketHostLookupCb callback,
+ void *context,
+ SilcSchedule schedule);
+
+#endif
+++ /dev/null
-/*
-
- silcsocketstream.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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"
-
-/************************** Types and definitions ***************************/
-
-/* Stream operation functions (platform specific) */
-int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len);
-int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len);
-SilcBool silc_socket_stream_close(SilcStream stream);
-void silc_socket_stream_destroy(SilcStream stream);
-int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len);
-int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len);
-SilcBool silc_socket_stream_close(SilcStream stream);
-void silc_socket_stream_destroy(SilcStream stream);
-SilcBool silc_socket_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context);
-SilcSchedule silc_socket_stream_get_schedule(SilcStream stream);
-
-/* Internal async host lookup context. */
-typedef struct {
- SilcSocketStream stream;
- SilcSocketStreamStatus status;
- SilcSocketStreamCallback callback;
- SilcAsyncOperation op;
- void *context;
- unsigned int require_fqdn : 1;
- unsigned int aborted : 1;
-} *SilcSocketHostLookup;
-
-
-/************************ Static utility functions **************************/
-
-/* Finishing timeout callback that will actually call the user specified
- host lookup callback. This is executed back in the calling thread and
- not in the lookup thread. */
-
-SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
-{
- SilcSocketHostLookup lookup = context;
- SilcSocketStream stream = lookup->stream;
-
- if (lookup->aborted) {
- SILC_LOG_DEBUG(("Socket stream creation was aborted"));
- stream->schedule = NULL;
- silc_socket_stream_destroy(stream);
- silc_free(lookup);
- return;
- }
-
- if (lookup->status != SILC_SOCKET_OK) {
- SILC_LOG_DEBUG(("Socket stream failed"));
- stream->schedule = NULL;
- silc_socket_stream_destroy(stream);
- stream = lookup->stream = NULL;
- }
-
- /* Return the created socket stream to the caller */
- if (lookup->callback)
- lookup->callback(lookup->status, stream, lookup->context);
-
- if (lookup->op)
- silc_async_free(lookup->op);
- silc_free(lookup);
-}
-
-/* The thread function that performs the actual lookup. */
-
-static void *silc_socket_host_lookup_start(void *context)
-{
- SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
- SilcSocketStream stream = lookup->stream;
- SilcSchedule schedule = stream->schedule;
-
- stream->port = silc_net_get_remote_port(stream->sock);
-
- silc_net_check_host_by_sock(stream->sock, &stream->hostname, &stream->ip);
- if (!stream->ip) {
- lookup->status = SILC_SOCKET_UNKNOWN_IP;
- goto out;
- }
-
- if (!stream->hostname && lookup->require_fqdn) {
- lookup->status = SILC_SOCKET_UNKNOWN_HOST;
- goto out;
- }
-
- if (!stream->hostname) {
- stream->hostname = strdup(stream->ip);
- if (!stream->hostname) {
- lookup->status = SILC_SOCKET_NO_MEMORY;
- goto out;
- }
- }
-
- lookup->status = SILC_SOCKET_OK;
-
- out:
- silc_schedule_task_add_timeout(schedule, silc_socket_host_lookup_finish,
- lookup, 0, 0);
- silc_schedule_wakeup(schedule);
- return NULL;
-}
-
-/* Abort callback for stream creation. */
-
-static void silc_socket_host_lookup_abort(SilcAsyncOperation op,
- void *context)
-{
- SilcSocketHostLookup lookup = context;
-
- /* The host lookup is done in thread. We'll let it finish in its own
- good time and handle the abortion after it finishes. */
- lookup->aborted = TRUE;
-}
-
-
-/******************************* Public API *********************************/
-
-/* Creates TCP socket stream */
-
-SilcAsyncOperation
-silc_socket_tcp_stream_create(SilcSocket sock, SilcBool lookup,
- SilcBool require_fqdn,
- SilcSchedule schedule,
- SilcSocketStreamCallback callback,
- void *context)
-{
- SilcSocketStream stream;
- SilcSocketHostLookup l;
-
- if (!sock) {
- if (callback)
- callback(SILC_SOCKET_ERROR, NULL, context);
- return NULL;
- }
-
- stream = silc_calloc(1, sizeof(*stream));
- if (!stream) {
- if (callback)
- callback(SILC_SOCKET_NO_MEMORY, NULL, context);
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Creating TCP socket stream %p, sock %lu", stream, sock));
-
- stream->ops = &silc_socket_stream_ops;
- stream->sock = sock;
- stream->schedule = schedule;
-
- l = silc_calloc(1, sizeof(*l));
- if (!l) {
- silc_free(stream);
- if (callback)
- callback(SILC_SOCKET_NO_MEMORY, NULL, context);
- return NULL;
- }
-
- l->stream = stream;
- l->callback = callback;
- l->context = context;
- l->require_fqdn = require_fqdn;
-
- if (lookup) {
- /* Start asynchronous IP, hostname and port lookup process */
- l->op = silc_async_alloc(silc_socket_host_lookup_abort, NULL, l);
- if (!l->op) {
- silc_free(stream);
- silc_free(l);
- if (callback)
- callback(SILC_SOCKET_ERROR, NULL, context);
- return NULL;
- }
-
- /* Lookup in thread */
- SILC_LOG_DEBUG(("Starting async host lookup"));
- silc_thread_create(silc_socket_host_lookup_start, l, FALSE);
- return l->op;
- } else {
- /* No lookup */
- l->status = SILC_SOCKET_OK;
- silc_socket_host_lookup_finish(schedule,
- silc_schedule_get_context(schedule),
- 0, 0, l);
- return NULL;
- }
-}
-
-/* Creates UDP socket stream */
-
-SilcStream silc_socket_udp_stream_create(SilcSocket sock, SilcBool ipv6,
- SilcBool connected,
- SilcSchedule schedule)
-{
- SilcSocketStream stream;
-
- stream = silc_calloc(1, sizeof(*stream));
- if (!stream)
- return NULL;
-
- SILC_LOG_DEBUG(("Creating UDP socket stream %p", stream));
-
- stream->ops = &silc_socket_udp_stream_ops;
- stream->sock = sock;
- stream->schedule = schedule;
- stream->ipv6 = ipv6;
- stream->connected = connected;
-
- return (SilcStream)stream;
-}
-
-/* Returns TRUE if the stream is UDP stream */
-
-SilcBool silc_socket_stream_is_udp(SilcStream stream, SilcBool *connected)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM_UDP(socket_stream))
- return FALSE;
-
- if (connected)
- *connected = socket_stream->connected;
-
- return TRUE;
-}
-
-/* Returns socket stream information */
-
-SilcBool silc_socket_stream_get_info(SilcStream stream,
- SilcSocket *sock, const char **hostname,
- const char **ip, SilcUInt16 *port)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
- !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
- return FALSE;
-
- if (sock)
- *sock = socket_stream->sock;
- if (port) {
- if (!socket_stream->port)
- return FALSE;
- *port = socket_stream->port;
- }
- if (ip) {
- if (!socket_stream->ip)
- return FALSE;
- *ip = socket_stream->ip;
- }
- if (hostname) {
- if (!socket_stream->hostname)
- return FALSE;
- *hostname = socket_stream->hostname;
- }
-
- return TRUE;
-}
-
-/* Set socket information */
-
-SilcBool silc_socket_stream_set_info(SilcStream stream,
- const char *hostname,
- const char *ip, SilcUInt16 port)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
- !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
- return FALSE;
-
- if (hostname) {
- silc_free(socket_stream->hostname);
- socket_stream->hostname = strdup(hostname);
- if (!socket_stream->hostname)
- return FALSE;
- }
- if (ip) {
- silc_free(socket_stream->ip);
- socket_stream->ip = strdup(ip);
- if (!socket_stream->ip)
- return FALSE;
- if (!socket_stream->hostname) {
- socket_stream->hostname = strdup(ip);
- if (!socket_stream->hostname)
- return FALSE;
- }
- }
- if (port)
- socket_stream->port = port;
-
- return TRUE;
-}
-
-/* Return socket errno */
-
-int silc_socket_stream_get_error(SilcStream stream)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
- !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
- return 0;
-
- return socket_stream->sock_error;
-}
-
-/* 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)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
- !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
- return FALSE;
-
- SILC_LOG_DEBUG(("Setting QoS for socket stream"));
-
- if (socket_stream->qos && !read_rate && !read_limit_bytes &&
- !limit_sec && !limit_usec) {
- silc_schedule_task_del_by_context(socket_stream->schedule,
- socket_stream->qos);
- silc_free(socket_stream->qos);
- socket_stream->qos = NULL;
- return TRUE;
- }
-
- if (!socket_stream->qos) {
- socket_stream->qos = silc_calloc(1, sizeof(*socket_stream->qos));
- if (!socket_stream->qos)
- return FALSE;
- }
-
- socket_stream->qos->read_rate = read_rate;
- socket_stream->qos->read_limit_bytes = read_limit_bytes;
- socket_stream->qos->limit_sec = limit_sec;
- socket_stream->qos->limit_usec = limit_usec;
- memset(&socket_stream->qos->next_limit, 0,
- sizeof(socket_stream->qos->next_limit));
- socket_stream->qos->cur_rate = 0;
- socket_stream->qos->sock = socket_stream;
-
- socket_stream->qos->buffer = silc_malloc(read_limit_bytes);
- if (!socket_stream->qos->buffer)
- return FALSE;
-
- return TRUE;
-}
-
-/* Return associated scheduler */
-
-SilcSchedule silc_socket_stream_get_schedule(SilcStream stream)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
- !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
- return NULL;
-
- return socket_stream->schedule;
-}
-
-/* SILC Socket Stream ops. Functions are implemented under the
- platform specific subdirectories. */
-const SilcStreamOps silc_socket_stream_ops =
-{
- silc_socket_stream_read,
- silc_socket_stream_write,
- silc_socket_stream_close,
- silc_socket_stream_destroy,
- silc_socket_stream_notifier,
- silc_socket_stream_get_schedule,
-};
-const SilcStreamOps silc_socket_udp_stream_ops =
-{
- silc_socket_udp_stream_read,
- silc_socket_udp_stream_write,
- silc_socket_stream_close,
- silc_socket_stream_destroy,
- silc_socket_stream_notifier,
- silc_socket_stream_get_schedule,
-};
+++ /dev/null
-/*
-
- silcsocketstream.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 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* silcutil/SILC Socket Stream Interface
- *
- * DESCRIPTION
- *
- * Implementation of SILC Socket Stream. SILC Socket Stream can be used
- * read data from and write data to a socket connection. The SILC Socket
- * Stream provides also Quality of Service (QoS) support that can be used
- * to control the throughput of the stream. It also supports both TCP and
- * UDP, and IPv4 and IPv6.
- *
- * SILC Socket Stream is not thread-safe. If the same socket stream must be
- * used in multithreaded environment concurrency control must be employed.
- *
- ***/
-
-#ifndef SILCSOCKETSTREAM_H
-#define SILCSOCKETSTREAM_H
-
-/****d* silcutil/SilcSocketStreamAPI/SilcSocketStreamStatus
- *
- * NAME
- *
- * typedef enum { ... } SilcStreamStatus;
- *
- * DESCRIPTION
- *
- * Socket Stream status. This status is returned into the
- * SilcSocketStreamCallback function after the socket stream is
- * created.
- *
- * SOURCE
- */
-typedef enum {
- SILC_SOCKET_OK, /* Normal status */
- SILC_SOCKET_UNKNOWN_IP, /* Remote does not have IP address */
- SILC_SOCKET_UNKNOWN_HOST, /* Remote does not have host name */
- SILC_SOCKET_NO_MEMORY, /* System out of memory */
- SILC_SOCKET_ERROR, /* Unknown error */
-} SilcSocketStreamStatus;
-/***/
-
-/****f* silcutil/SilcSocketStreamAPI/SilcSocketStreamCallback
- *
- * SYNOPSIS
- *
- * typedef void (*SilcSocketStreamCallback)(SilcSocketStreamStatus status,
- * SilcStream stream,
- * void *context);
- *
- * DESCRIPTION
- *
- * Callback function of this type is called after the socket stream
- * creation is completed. If the `stream' is NULL the socket stream could
- * not be created or the socket connection is not otherwise allowed. The
- * `status' will indicate the error status. In case error ocurrs the
- * associated socket has already been destroyed. The `stream' is socket
- * stream representing the socket connection and silc_socket_stream_*
- * functions can be used to access the stream. All other silc_stream_*
- * functions can also be used to read data, send data, and otherwise
- * handle the stream.
- *
- ***/
-typedef void (*SilcSocketStreamCallback)(SilcSocketStreamStatus status,
- SilcStream stream, void *context);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_tcp_stream_create
- *
- * SYNOPSIS
- *
- * SilcAsyncOperation
- * silc_socket_tcp_stream_create(SilcSocket sock, SilcBool lookup,
- * SilcBool require_fqdn,
- * SilcSchedule schedule,
- * SilcSocketStreamCallback callback,
- * void *context);
- *
- * DESCRIPTION
- *
- * Creates TCP socket stream of the TCP connection indicated by `sock'.
- * The stream can be destroyed by calling the silc_stream_destroy. Data
- * can be sent and received from the stream by calling silc_stream_write
- * and silc_stream_read. The creation process is asynchronous since
- * socket connection information, such as hostname and IP address are
- * resolved, so SilcAsyncOperation is returned which can be used to cancel
- * the creation process. The `callback' will be called to return the
- * created socket stream. To destroy the stream call silc_stream_destroy.
- *
- * If the `lookup' is TRUE then this will perform IP and hostname lookup
- * for the socket. If the `require_fqdn' is TRUE then the socket must
- * have valid hostname and IP address, otherwise the stream creation will
- * fail. If it is FALSE then only valid IP address is required. Note that,
- * if the `lookup' is FALSE then the hostname, IP and port information
- * will not be available from the socket stream. In that case this will
- * also return NULL as the `callback' is called immediately.
- *
- ***/
-SilcAsyncOperation
-silc_socket_tcp_stream_create(SilcSocket sock, SilcBool lookup,
- SilcBool require_fqdn,
- SilcSchedule schedule,
- SilcSocketStreamCallback callback,
- void *context);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_udp_stream_create
- *
- * SYNOPSIS
- *
- * SilcStream silc_socket_udp_stream_create(SilcSocket sock,
- * SilcBool ipv6,
- * SilcBool connected,
- * SilcSchedule schedule);
- *
- * DESCRIPTION
- *
- * Creates UDP socket stream of the UDP connection indicated by `sock'.
- * The stream can be destroyed by calling the silc_stream_destroy.
- * The `connected' defines whether the socket is in connected or in
- * connectionless state.
- *
- * Note that, UDP packets may be read only through the notifier
- * callback (see silc_stream_set_notifier), when SILC_STREAM_CAN_READ
- * is returned to the callback. Because of this the notifier callback
- * must be set.
- *
- * Note that, UDP packet sending using silc_stream_write and receiving
- * with silc_stream_read works only if the `sock' is a UDP socket in a
- * connected state. In connectionless state sending packets with
- * silc_stream_write is possible only if the remote address and port
- * has been set with silc_socket_stream_set_info. If it is not set
- * in connectionless state packets may be sent only by using the
- * silc_net_udp_send function. In connectionless state packets may be
- * received only by using silc_net_udp_receive.
- *
- * This function returns the created SilcStream or NULL on error.
- *
- ***/
-SilcStream silc_socket_udp_stream_create(SilcSocket sock,
- SilcBool ipv6,
- SilcBool connected,
- SilcSchedule schedule);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_is_udp
- *
- * SYNOPSIS
- *
- * SilcBool silc_socket_stream_is_udp(SilcStream stream,
- * SilcBool *connected);
- *
- * DESCRIPTION
- *
- * Returns TRUE if the `stream' is UDP stream. If the `connected' pointer
- * is non-NULL indication whether the UDP stream is in connected state.
- * If it is then packets can be read and written using silc_stream_read
- * and silc_stream_write. If it is not then packets need to read and
- * written by using silc_net_udp_receive and silc_net_udp_send.
- *
- ***/
-SilcBool silc_socket_stream_is_udp(SilcStream stream, SilcBool *connected);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_get_info
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_socket_stream_get_info(SilcStream stream,
- * SilcSocket *sock, const char **hostname,
- * const char **ip, SilcUInt16 *port);
- *
- * DESCRIPTION
- *
- * Returns socket stream information such as the socket, remote hostname,
- * remote IP address and the remote port of the remote socket connection.
- * Return FALSE if these informations are not available.
- *
- ***/
-SilcBool silc_socket_stream_get_info(SilcStream stream,
- SilcSocket *sock, const char **hostname,
- const char **ip, SilcUInt16 *port);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_set_info
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_socket_stream_set_info(SilcStream stream,
- * const char *hostname,
- * const char *ip, SilcUInt16 port);
- *
- * DESCRIPTION
- *
- * Use this function to set the hostname, IP address and remote port
- * information to the socket stream indicated by `stream' if you did not
- * perform lookup in the silc_socket_tcp_stream_create. This is not
- * mandatory but if you would like to associate the information with the
- * stream use this function. If the lookup was performed when creating
- * the stream then calling this function is not necessary. Use the
- * function silc_socket_stream_get_info to get the information from the
- * stream.
- *
- ***/
-SilcBool silc_socket_stream_set_info(SilcStream stream,
- const char *hostname,
- const char *ip, SilcUInt16 port);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_get_error
- *
- * SYNOPSIS
- *
- * int silc_socket_stream_get_error(SilcStream stream);
- *
- * DESCRIPTION
- *
- * If error occurred during socket stream operations, this function
- * can be used to retrieve the error number that occurred.
- *
- ***/
-int silc_socket_stream_get_error(SilcStream stream);
-
-/****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_set_qos
- *
- * SYNOPSIS
- *
- * SilcBool silc_socket_stream_set_qos(SilcStream stream,
- * SilcUInt32 read_rate,
- * SilcUInt32 read_limit_bytes,
- * SilcUInt32 limit_sec,
- * SilcUInt32 limit_usec)
- *
- * DESCRIPTION
- *
- * Sets a "Quality of Service" settings for socket stream `stream'.
- * The `read_rate' specifies the maximum read operations per second.
- * If more read operations are executed the limit will be applied for
- * the reading. The `read_limit_bytes' specifies the maximum data
- * that is read. It is guaranteed that silc_stream_read never returns
- * more than `read_limit_bytes' of data. The `limit_sec' and `limit_usec'
- * specifies the time limit that is applied if `read_rate' and/or
- * `read_limit_bytes' is reached. If all arguments except `stream'
- * are zero this resets the QoS from the socket stream, all QoS for
- * this socket stream that may be pending will be cancelled.
- *
- ***/
-SilcBool silc_socket_stream_set_qos(SilcStream stream,
- SilcUInt32 read_rate,
- SilcUInt32 read_limit_bytes,
- SilcUInt32 limit_sec,
- SilcUInt32 limit_usec);
-
-#include "silcsocketstream_i.h"
-
-#endif /* SILCSOCKETSTREAM_H */
+++ /dev/null
-/*
-
- silcsocketstream_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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 SILCSOCKETSTREAM_I_H
-#define SILCSOCKETSTREAM_I_H
-
-#ifndef SILCSOCKETSTREAM_H
-#error "Do not include this header directly"
-#endif
-
-typedef struct SilcSocketStreamStruct *SilcSocketStream;
-
-/* Qos context */
-typedef struct SilcSocketQosStruct {
- SilcUInt16 read_limit_bytes; /* Max read bytes */
- SilcUInt16 read_rate; /* Max read rate/second */
- SilcUInt16 limit_sec; /* Limit seconds */
- SilcUInt32 limit_usec; /* Limit microseconds */
- struct timeval next_limit;
- unsigned int cur_rate : 31;
- unsigned int applied : 1;
- SilcUInt32 data_len;
- unsigned char *buffer;
- SilcSocketStream sock;
-} *SilcSocketQos;
-
-/* SILC Socket Stream context */
-struct SilcSocketStreamStruct {
- const SilcStreamOps *ops;
- SilcSchedule schedule;
- SilcSocket sock;
- char *hostname;
- char *ip;
- SilcUInt16 port;
- SilcUInt16 sock_error;
- SilcSocketQos qos;
- SilcStreamNotifier notifier;
- void *notifier_context;
- unsigned int ipv6 : 1; /* UDP IPv6 */
- unsigned int connected : 1; /* UDP connected state */
-};
-
-#define SILC_IS_SOCKET_STREAM(s) (s->ops == &silc_socket_stream_ops)
-#define SILC_IS_SOCKET_STREAM_UDP(s) (s->ops == &silc_socket_udp_stream_ops)
-
-extern const SilcStreamOps silc_socket_stream_ops;
-extern const SilcStreamOps silc_socket_udp_stream_ops;
-
-#endif /* SILCSOCKETSTREAM_I_H */
+++ /dev/null
-/*
-
- silcstack.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2006 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.
-
-*/
-
-/* #define SILC_STACK_DEBUG 1 */
-
-#include "silc.h"
-
-/* Allocate the stack */
-
-SilcStack silc_stack_alloc(SilcUInt32 stack_size)
-{
- SilcStack stack;
-
- stack = silc_calloc(1, sizeof(*stack));
- if (!stack)
- return NULL;
-
- stack->frames = silc_calloc(SILC_STACK_DEFAULT_NUM,
- sizeof(*stack->frames));
- if (!stack->frames) {
- silc_free(stack);
- return NULL;
- }
-
- /* Create initial stack */
- stack->stack_size = stack_size ? stack_size : SILC_STACK_DEFAULT_SIZE;
- stack->stack[0] = silc_malloc(stack->stack_size +
- SILC_STACK_ALIGN(sizeof(*stack->stack[0]),
- SILC_STACK_DEFAULT_ALIGN));
- if (!stack->stack[0]) {
- silc_free(stack->frames);
- silc_free(stack);
- return NULL;
- }
- stack->stack[0]->bytes_left = stack->stack_size;
-
- /* Use the allocated stack in first stack frame */
- stack->frame = &stack->frames[0];
- stack->frame->prev = NULL;
- stack->frame->bytes_used = stack->stack_size;
- stack->frame->sp = 1;
- stack->frame->si = 0;
-
- return stack;
-}
-
-/* Frees the stack and all allocated memory */
-
-void silc_stack_free(SilcStack stack)
-{
- int i;
-
- silc_free(stack->frames);
- for (i = 0; i < SILC_STACK_BLOCK_NUM; i++)
- silc_free(stack->stack[i]);
- silc_free(stack);
-}
-
-/* Push to next stack frame */
-
-SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame)
-{
- if (!stack)
- return 0;
-
- if (!frame) {
- /* See if all frames are in use, and allocate SILC_STACK_DEFAULT_NUM
- many new frames if needed. */
- if (stack->frame->sp >= SILC_STACK_ALIGN(stack->frame->sp,
- SILC_STACK_DEFAULT_NUM)) {
- int i = stack->frame->sp;
- SILC_LOG_DEBUG(("Allocating more stack frames"));
- frame = silc_realloc(stack->frames,
- SILC_STACK_ALIGN(i + 1, SILC_STACK_DEFAULT_NUM) *
- sizeof(*stack->frames));
- if (!frame)
- return 0;
- stack->frames = frame;
- stack->frame = &stack->frames[i - 1];
-
- /* The prev pointers may become invalid in silc_realloc() */
- for (i = 1; i < stack->frame->sp; i++)
- stack->frames[i].prev = &stack->frames[i - 1];
- }
-
- frame = &stack->frames[stack->frame->sp];
- }
-
- /* Push */
- frame->prev = stack->frame;
- frame->sp = stack->frame->sp + 1;
- frame->si = stack->frame->si;
- frame->bytes_used = stack->stack[frame->si]->bytes_left;
- stack->frame = frame;
-
- SILC_ST_DEBUG(("Push %p: sp %d -> %d, si %d", stack, frame->prev->sp,
- frame->sp, frame->si));
-
- return stack->frame->sp;
-}
-
-/* Pop to previous stack frame */
-
-SilcUInt32 silc_stack_pop(SilcStack stack)
-{
- SilcUInt32 si;
-
- if (!stack)
- return 0;
-
- /* Pop */
- assert(stack->frame->prev);
- si = stack->frame->si;
- while (si > stack->frame->prev->si) {
- if (stack->stack[si])
- stack->stack[si]->bytes_left = SILC_STACK_BLOCK_SIZE(stack, si);
- si--;
- }
- stack->stack[si]->bytes_left = stack->frame->bytes_used;
- stack->frame = stack->frame->prev;
-
- SILC_ST_DEBUG(("Pop %p: sp %d -> %d, si %d", stack, stack->frame->sp + 1,
- stack->frame->sp, stack->frame->si));
-
- return stack->frame->sp + 1;
-}
-
-/* Allocate memory. If the `aligned' is FALSE this allocates unaligned
- memory, otherwise memory is aligned. Returns pointer to the memory
- or NULL on error. */
-
-void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned)
-{
- void *ptr;
- SilcUInt32 bsize, bsize2;
- SilcUInt32 si = stack->frame->si;
-
- SILC_STACK_STAT(stack, num_malloc, 1);
- SILC_ST_DEBUG(("Allocating %d bytes (%s) from %p",
- size, aligned ? "align" : "not align", stack));
-
- if (silc_unlikely(!size)) {
- SILC_LOG_ERROR(("Allocation by zero (0)"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
-
- if (silc_unlikely(size > SILC_STACK_MAX_ALLOC)) {
- SILC_LOG_ERROR(("Allocating too much"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
-
- /* Align properly if wanted */
- size = (aligned ? SILC_STACK_ALIGN(size, SILC_STACK_DEFAULT_ALIGN) : size);
-
- /* Compute the size of current stack block */
- bsize = SILC_STACK_BLOCK_SIZE(stack, si);
-
- /* See if there is space in the current stack block */
- if (stack->stack[si]->bytes_left >= size) {
- /* Get pointer to the memory */
- ptr = SILC_STACK_DATA(stack, si, bsize);
- stack->stack[si]->bytes_left -= size;
- SILC_STACK_STAT(stack, bytes_malloc, size);
- return ptr;
- }
-
- /* There is not enough space in this block. Find the spot to stack
- block that can handle this size memory. */
- if (bsize < SILC_STACK_DEFAULT_SIZE)
- bsize = SILC_STACK_DEFAULT_SIZE;
- bsize += size;
- bsize2 = SILC_STACK_DEFAULT_SIZE;
- si = 0;
- while (bsize2 < bsize) {
- bsize2 <<= 1;
- si++;
- }
- if (silc_unlikely(si >= SILC_STACK_BLOCK_NUM)) {
- SILC_LOG_ERROR(("Allocating too large block"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
-
- /* Allocate the block if it doesn't exist yet */
- if (!stack->stack[si]) {
- SILC_ST_DEBUG(("Allocating new stack block, %d bytes", bsize2));
- stack->stack[si] = silc_malloc(bsize2 +
- SILC_STACK_ALIGN(sizeof(**stack->stack),
- SILC_STACK_DEFAULT_ALIGN));
- if (silc_unlikely(!stack->stack[si])) {
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
- stack->stack[si]->bytes_left = bsize2;
- }
-
- /* Now return memory from this new block. It is guaranteed that in this
- block there is enough space for this memory. */
- assert(stack->stack[si]->bytes_left >= size);
- ptr = SILC_STACK_DATA(stack, si, bsize2);
- stack->stack[si]->bytes_left -= size;
- stack->frame->si = si;
- SILC_STACK_STAT(stack, bytes_malloc, size);
-
- return ptr;
-}
-
-/* Attempts to reallocate memory by changing the size of the `ptr' into
- `size'. This routine works only if the previous allocation to `stack'
- was `ptr'. If there is another memory allocation between allocating
- `ptr' and this call this routine will return NULL. NULL is also returned
- if the `size' does not fit into the current block. If NULL is returned
- the old memory remains intact. */
-
-void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
- void *ptr, SilcUInt32 size, SilcBool aligned)
-{
- SilcUInt32 si = stack->frame->si;
- SilcUInt32 bsize;
- void *sptr;
-
- if (!ptr)
- return silc_stack_malloc(stack, size, aligned);
-
- SILC_STACK_STAT(stack, num_malloc, 1);
- SILC_ST_DEBUG(("Reallocating %d bytes (%d) (%s) from %p", size, old_size,
- aligned ? "align" : "not align", stack));
-
- if (silc_unlikely(!size || !old_size)) {
- SILC_LOG_ERROR(("Allocation by zero (0)"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
-
- if (silc_unlikely(size > SILC_STACK_MAX_ALLOC)) {
- SILC_LOG_ERROR(("Allocating too much"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
-
- /* Align the old size if needed */
- old_size = (aligned ?
- 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);
-
- /* Check that `ptr' is last allocation */
- sptr = (unsigned char *)stack->stack[si] +
- SILC_STACK_ALIGN(sizeof(**stack->stack), SILC_STACK_DEFAULT_ALIGN);
- if (stack->stack[si]->bytes_left + old_size +
- ((unsigned char *)ptr - (unsigned char *)sptr) != bsize) {
- SILC_LOG_DEBUG(("Cannot reallocate"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
- }
-
- /* 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);
- stack->stack[si]->bytes_left -= (size - old_size);
- SILC_STACK_STAT(stack, bytes_malloc, (size - old_size));
- return ptr;
- }
-
- SILC_LOG_DEBUG(("Cannot reallocate in this block"));
- SILC_STACK_STAT(stack, num_errors, 1);
- return NULL;
-}
-
-#ifdef SILC_DIST_INPLACE
-/* Statistics dumping. */
-
-void silc_stack_stats(SilcStack stack)
-{
- SilcUInt32 stack_size = 0;
- int i, c = 0;
-
- for (i = 0; i < SILC_STACK_BLOCK_NUM; i++) {
- if (!stack->stack[i])
- continue;
- stack_size += SILC_STACK_BLOCK_SIZE(stack, i);
- c++;
- }
-
- fprintf(stdout, "\nSilcStack %p statistics :\n\n", stack);
- fprintf(stdout, " Size of stack : %u\n",
- (unsigned int)stack_size);
- fprintf(stdout, " Number of allocs : %u\n",
- (unsigned int)stack->snum_malloc);
- fprintf(stdout, " Bytes allocated : %u\n",
- (unsigned int)stack->sbytes_malloc);
- fprintf(stdout, " Average alloc size : %.2f\n",
- (double)((double)stack->sbytes_malloc / (double)stack->snum_malloc));
- fprintf(stdout, " Number of alloc errors : %u\n",
- (unsigned int)stack->snum_errors);
- fprintf(stdout, " Number of frames : %u\n",
- (unsigned int)SILC_STACK_ALIGN(stack->frame->sp,
- SILC_STACK_DEFAULT_NUM));
- fprintf(stdout, " Number of blocks : %u\n", c);
-}
-#endif /* SILC_DIST_INPLACE */
+++ /dev/null
-/*
-
- silcstack.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2006 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* silcutil/SilcStack Interface
- *
- * DESCRIPTION
- *
- * Implementation of data stack which can be used to allocate memory from
- * the stack. Basicly SilcStack is a pre-allocated memory pool system
- * which allows fast memory allocation for routines and applications that
- * frequently allocate small amounts of memory. Other advantage of this
- * system is that there are no memory leaks, as long as the stack is
- * freed eventually. Since the stack is usually allocated only once this
- * is not an issue.
- *
- * SilcStack can be used to allocate both aligned and unaligned memory so
- * it is suitable for allocating structures and is optimal for allocating
- * strings and data buffers. SilcStack also supports stack pushing and
- * popping allowing to push the stack, allocate memory and then pop it
- * to free the allocated memory. The freeing does not actually do any
- * real memory freeing so it is optimized for performance.
- *
- * A basic set of utility functions are provided for application that wish
- * to use the SilcStack as their primary memory allocation source. The
- * following functions support SilcStack:
- *
- * silc_smalloc, silc_smalloc_ua, silc_scalloc, silc_srealloc, silc_smemdup,
- * silc_sstrdup, silc_buffer_salloc, silc_buffer_salloc_size,
- * silc_buffer_srealloc, silc_buffer_srealloc_size, silc_buffer_scopy,
- * silc_buffer_sclone, silc_buffer_sformat, silc_buffer_sformat_vp,
- * silc_buffer_sstrformat, silc_buffer_senlarge, silc_mp_sinit
- *
- * The data stack is not thread-safe. If the same stack context must be
- * used in multithreaded environment concurrency control must be employed.
- *
- ***/
-
-#ifndef SILCSTACK_H
-#define SILCSTACK_H
-
-/****s* silcutil/SilcStackAPI/SilcStack
- *
- * NAME
- *
- * typedef struct SilcStackStruct *SilcStack;
- *
- * DESCRIPTION
- *
- * This context represents the stack and it is allocated by
- * silc_stack_alloc and is destroyed with silc_stack_free functions.
- * The context is given as argument to all routines that use this
- * stack allocation library.
- *
- ***/
-typedef struct SilcStackStruct *SilcStack;
-
-/****s* silcutil/SilcStackAPI/SilcStackFrame
- *
- * NAME
- *
- * typedef struct SilcStackFrameStruct SilcStackFrame;
- *
- * DESCRIPTION
- *
- * Static stack frame context that optionally can be used as stack
- * frame in SilcStack. By default silc_stack_push use pre-allocated
- * stack frame (or allocates new one if all frames are reserved), but
- * user may also use staticly allocated SilcStackFrame instead. This
- * is recommended when using SilcStack in recursive routine and the
- * recursion may become deep. Using static frame assures that during
- * recursion frames never run out and silc_stack_push never allocates
- * any memory. In other normal usage staticly allocated SilcStackFrame
- * is not needed, unless performance is critical.
- *
- ***/
-typedef struct SilcStackFrameStruct SilcStackFrame;
-
-/****f* silcutil/SilcStackAPI/silc_stack_alloc
- *
- * SYNOPSIS
- *
- * SilcStack silc_stack_alloc(SilcUInt32 stack_size);
- *
- * DESCRIPTION
- *
- * Allocates new data stack that can be used as stack for fast memory
- * allocation by various routines. Returns the pointer to the stack
- * that must be freed with silc_stack_free function when it is not
- * needed anymore. If the `stack_size' is zero (0) by default a
- * 1 kilobyte (1024 bytes) stack is allocated. If the `stack_size'
- * is non-zero the byte value must be multiple by 8.
- *
- ***/
-SilcStack silc_stack_alloc(SilcUInt32 stack_size);
-
-/****f* silcutil/SilcStackAPI/silc_stack_free
- *
- * SYNOPSIS
- *
- * void silc_stack_free(SilcStack stack);
- *
- * DESCRIPTION
- *
- * Frees the data stack context. The stack cannot be used anymore after
- * this and all allocated memory are freed.
- *
- ***/
-void silc_stack_free(SilcStack stack);
-
-/****f* silcutil/SilcStackAPI/silc_stack_push
- *
- * SYNOPSIS
- *
- * SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame);
- *
- * DESCRIPTION
- *
- * Push the top of the stack down which becomes the new top of the stack.
- * For every silc_stack_push call there must be silc_stack_pop call. All
- * allocations between these two calls will be done from the top of the
- * stack and all allocated memory is freed after the next silc_stack_pop
- * is called. This returns so called stack pointer for the new stack
- * frame, which the caller may use to check that all calls to
- * silc_stack_pop has been made. This call may do a small memory
- * allocation in some cases, but usually it does not allocate any memory.
- * If this returns zero (0) the system is out of memory.
- *
- * If the `frame' is non-NULL then that SilcStackFrame is used as
- * stack frame. Usually `frame' is set to NULL by user. Staticly
- * allocated SilcStackFrame should be used when using silc_stack_push
- * in recursive function and the recursion may become deep. In this
- * case using staticly allocated SilcStackFrame is recommended since
- * it assures that frames never run out and silc_stack_push never
- * allocates any memory. If your routine is not recursive then
- * setting `frame' to NULL is recommended, unless performance is
- * critical.
- *
- * This function is used when a routine is doing frequent allocations
- * from the stack. If the stack is not pushed and later popped all
- * allocations are made from the stack and the stack eventually runs out
- * (it gets enlarged by normal memory allocation). By pushing and then
- * later popping the frequent allocations does not consume the stack.
- *
- * If `stack' is NULL this call has no effect.
- *
- * EXAMPLE
- *
- * All memory allocations in silc_foo_parse_packet will be done in
- * a fresh stack frame and that data is freed after the parsing is
- * completed.
- *
- * silc_stack_push(stack, NULL);
- * silc_foo_parse_packet(packet, stack);
- * silc_stack_pop(stack);
- *
- * Another example with recursion and using staticly allocated
- * SilcStackFrame. After popping the staticly allocated frame can
- * be reused if necessary.
- *
- * void silc_foo_this_function(SilcStack stack)
- * {
- * SilcStackFrame frame;
- * ...
- * silc_stack_push(stack, &frame);
- * silc_foo_this_function(stack); // Call recursively
- * silc_stack_pop(stack);
- * ...
- * }
- *
- ***/
-SilcUInt32 silc_stack_push(SilcStack stack, SilcStackFrame *frame);
-
-/****f* silcutil/SilcStackAPI/silc_stack_pop
- *
- * SYNOPSIS
- *
- * SilcUInt32 silc_stack_pop(SilcStack stack);
- *
- * DESCRIPTION
- *
- * Pop the top of the stack upwards which reveals the previous stack frame
- * and becomes the top of the stack. After popping, memory allocated in
- * the old frame is freed. For each silc_stack_push call there must be
- * silc_stack_pop call to free all memory (in reality any memory is not
- * freed but within the stack it is). This returns the stack pointer of
- * old frame after popping and caller may check that it is same as
- * returned by the silc_stack_push. If it they differ, some routine
- * has called silc_stack_push but has not called silc_stack_pop, or
- * silc_stack_pop has been called too many times. Application should
- * treat this as a fatal error, as it is a bug in the application code.
- *
- * If `stack' is NULL this call has no effect.
- *
- * EXAMPLE
- *
- * This example saves the stack pointer which is checked when popping
- * the current stack frame. If the stack pointer differs then someone
- * has pushed the stack frame but forgot to pop it (or has called it
- * too many times).
- *
- * sp = silc_stack_push(stack, NULL);
- * silc_foo_parse_packet(packet, stack);
- * if (silc_stack_pop(stack) != sp)
- * fatal("corrupted stack");
- *
- ***/
-SilcUInt32 silc_stack_pop(SilcStack stack);
-
-#include "silcstack_i.h"
-
-#endif /* SILCSTACK_H */
+++ /dev/null
-/*
-
- silcstack_i.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- 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
- 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 SILCSTACK_I_H
-#define SILCSTACK_I_H
-
-#ifndef SILCSTACK_H
-#error "Do not include this header directly"
-#endif
-
-/* The default stack size when stack is created */
-#define SILC_STACK_DEFAULT_SIZE 1024
-
-/* Number of pre-allocated stack frames */
-#define SILC_STACK_DEFAULT_NUM 8
-
-/* Default alignment */
-#define SILC_STACK_DEFAULT_ALIGN sizeof(unsigned long)
-
-/* Maximum allocation that can be made with SilcStack. This is
- SILC_STACK_DEFAULT_SIZE * (2 ^ (SILC_STACK_BLOCK_NUM - 1)). */
-#define SILC_STACK_MAX_ALLOC 0x02000000
-#define SILC_STACK_BLOCK_NUM 16
-
-/* Stack frame data area */
-typedef struct SilcStackDataStruct {
- SilcUInt32 bytes_left; /* Free bytes in stack */
- /* Stack data area starts here */
-} *SilcStackData;
-
-/* Stack frame */
-struct SilcStackFrameStruct {
- struct SilcStackFrameStruct *prev; /* Pointer to previous frame */
- SilcUInt32 bytes_used; /* Bytes used when pushed */
- unsigned int sp : 27; /* Stack pointer */
- unsigned int si : 5; /* Stack index */
-};
-
-/* The SilcStack context */
-struct SilcStackStruct {
- SilcStackData stack[SILC_STACK_BLOCK_NUM]; /* Allocated stack blocks */
- SilcStackFrame *frames; /* Allocated stack frames */
- SilcStackFrame *frame; /* Current stack frame */
- SilcUInt32 stack_size; /* Default stack size */
-#ifdef SILC_DIST_INPLACE
- /* Statistics */
- SilcUInt32 snum_malloc;
- SilcUInt32 sbytes_malloc;
- SilcUInt32 snum_errors;
-#endif /* SILC_DIST_INPLACE */
-};
-
-/* Align the requested amount bytes. The `align' defines the requested
- alignment. */
-#define SILC_STACK_ALIGN(bytes, align) (((bytes) + (align - 1)) & ~(align - 1))
-
-/* Computes the size of stack block si. */
-#define SILC_STACK_BLOCK_SIZE(stack, si) \
- (((si) == 0) ? stack->stack_size : \
- SILC_STACK_DEFAULT_SIZE * (1L << ((si) - 1)) << 1);
-
-/* Returns a pointer to the data in the frame */
-#define SILC_STACK_DATA(stack, si, bsize) \
- (((unsigned char *)(stack)->stack[si]) + \
- SILC_STACK_ALIGN(sizeof(**(stack)->stack), SILC_STACK_DEFAULT_ALIGN) + \
- ((bsize) - (stack)->stack[si]->bytes_left))
-
-#ifdef SILC_DIST_INPLACE
-/* Statistics updating */
-#define SILC_STACK_STAT(stack, stat, val) ((stack)->s ## stat += (val))
-#define SILC_ST_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
-#else /* !SILC_DIST_INPLACE */
-#define SILC_STACK_STAT(stack, stat, val)
-#define SILC_ST_DEBUG(fmt)
-#endif /* SILC_DIST_INPLACE */
-
-/* Allocate memory. If the `aligned' is FALSE this allocates unaligned
- memory, otherwise memory is aligned. Returns pointer to the memory
- or NULL on error. */
-void *silc_stack_malloc(SilcStack stack, SilcUInt32 size, SilcBool aligned);
-
-/* Attempts to reallocate memory by changing the size of the `ptr' into
- `size'. This routine works only if the previous allocation to `stack'
- was `ptr'. If there is another memory allocation between allocating
- `ptr' and this call this routine will return NULL. NULL is also returned
- if the `size' does not fit into the current block. If NULL is returned
- the old memory remains intact. */
-void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
- void *ptr, SilcUInt32 size, SilcBool aligned);
-
-#ifdef SILC_DIST_INPLACE
-/* Prints statistics of the usage of SilcStack to stdout. */
-void silc_stack_stats(SilcStack stack);
-#endif /* SILC_DIST_INPLACE */
-
-#endif /* SILCSTACK_I_H */
+++ /dev/null
-/*
-
- silcstream.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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"
-
-typedef struct {
- SilcStreamOps *ops;
-} *SilcStreamHeader;
-
-int silc_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- SilcStreamHeader h = stream;
- return h->ops->read(stream, buf, buf_len);
-}
-
-int silc_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcStreamHeader h = stream;
- return h->ops->write(stream, data, data_len);
-}
-
-SilcBool silc_stream_close(SilcStream stream)
-{
- SilcStreamHeader h = stream;
- return h->ops->close(stream);
-}
-
-void silc_stream_destroy(SilcStream stream)
-{
- SilcStreamHeader h = stream;
- h->ops->destroy(stream);
-}
-
-SilcBool silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
- SilcStreamNotifier notifier, void *context)
-{
- SilcStreamHeader h = stream;
- return h->ops->notifier(stream, schedule, notifier, context);
-}
-
-SilcSchedule silc_stream_get_schedule(SilcStream stream)
-{
- SilcStreamHeader h = stream;
- return h->ops->get_schedule(stream);
-}
+++ /dev/null
-/*
-
- silcstream.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2006 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* silcutil/SILC Stream Interface
- *
- * DESCRIPTION
- *
- * SILC Stream API is a generic representation of a stream. A common API
- * is defined that can be used to read from and write to the stream. Any
- * other stream API derived from this API can use this same interface for
- * reading and writing.
- *
- * Note that stream implementations usually are not thread-safe. Always
- * verify whether a stream implementation is thread-safe by checking their
- * corresponding documentation.
- *
- ***/
-
-#ifndef SILCSTREAM_H
-#define SILCSTREAM_H
-
-/****s* silcutil/SilcStreamAPI/SilcStream
- *
- * NAME
- *
- * typedef void *SilcStream;
- *
- * DESCRIPTION
- *
- * Abstact stream context representing any stream. All streams are using
- * this abstraction so that the stream can be accessed using the standard
- * silc_stream_* functions. All streams are destroyed by calling the
- * silc_stream_destroy function.
- *
- ***/
-typedef void *SilcStream;
-
-/****d* silcutil/SilcStreamAPI/SilcStreamStatus
- *
- * NAME
- *
- * typedef enum { ... } SilcStreamStatus;
- *
- * DESCRIPTION
- *
- * Stream status. This status is returned into the SilcStreamNotifier
- * callback function to indicate the status of the stream at a given
- * moment.
- *
- * SOURCE
- */
-typedef enum {
- SILC_STREAM_CAN_READ, /* Data available for reading */
- SILC_STREAM_CAN_WRITE, /* Stream ready for writing */
- SILC_STREAM_EOS, /* End of stream */
- SILC_STREAM_CLOSED, /* Stream is closed */
- SILC_STREAM_INVALID, /* Stream is invalid */
- SILC_STREAM_NO_MEMORY, /* System out of memory */
- SILC_STREAM_ERROR, /* Unknown error */
-} SilcStreamStatus;
-/***/
-
-/****f* silcutil/SilcStreamAPI/SilcStreamNotifier
- *
- * SYNOPSIS
- *
- * typedef void (*SilcStreamNotifier)(SilcStream stream,
- * SilcStreamStatus status,
- * void *context);
- *
- * DESCRIPTION
- *
- * A callback of this type is called as stream notifier to notify of a
- * certain action taken over the stream. This is called to notify for
- * example that data is ready for reading, or writing or that end of
- * stream occurred.
- *
- ***/
-typedef void (*SilcStreamNotifier)(SilcStream stream,
- SilcStreamStatus status,
- void *context);
-
-/****s* silcutil/SilcStreamAPI/SilcStreamOps
- *
- * NAME
- *
- * typedef struct { ... } SilcStreamOps;
- *
- * DESCRIPTION
- *
- * SILC Stream operations structure. This structure includes callback
- * functions to the actual stream implementation. Any stream that
- * use SILC Stream abstraction must fill this structure with the actual
- * stream implementation.
- *
- * Each stream implementation MUST set this structure as the first field
- * in their stream structure. As it is that structure that is passed
- * to the silc_stream_* routines, the SILC Stream API expects that the
- * SilcStream context starts with this structure.
- *
- * EXAMPLE
- *
- * typedef struct {
- * const SilcStreamOps *ops;
- * ... other stuff ...
- * } *SilcFooStream;
- *
- * SilcFooStream foo;
- * silc_stream_write(foo, data, data_len);
- *
- * SOURCE
- */
-typedef struct {
- /* This is called to read data from the stream. This is called when
- silc_stream_read function was called. */
- int (*read)(SilcStream stream, unsigned char *buf, SilcUInt32 buf_len);
-
- /* This is called when writing data to the stream. This is called when
- silc_stream_write function was called. */
- int (*write)(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len);
-
- /* This is called to close the stream. This is called when the
- silc_stream_close function was called. */
- SilcBool (*close)(SilcStream stream);
-
- /* This is called to destroy the stream. This is called when the
- silc_stream_destroy function was called. */
- void (*destroy)(SilcStream stream);
-
- /* 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.
- Returns FALSE if the stream could not be scheduled. */
- SilcBool (*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;
-/***/
-
-/****f* silcutil/SilcStreamAPI/silc_stream_read
- *
- * SYNOPSIS
- *
- * int silc_stream_read(SilcStream stream, unsigned char *buf,
- * SilcUInt32 buf_len);
- *
- * DESCRIPTION
- *
- * Reads data from the stream indicated by `stream' into the data buffer
- * indicated by `buf' which is size of `buf_len'. This returns the amount
- * of data read, zero (0) if end of stream occurred, -1 if data could
- * not be read at this moment, or -2 if error occurred. If -1 is returned
- * the notifier callback will later be called with SILC_STREAM_CAN_READ
- * status when stream is again ready for reading.
- *
- ***/
-int silc_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len);
-
-/****f* silcutil/SilcStreamAPI/silc_stream_write
- *
- * SYNOPSIS
- *
- * int silc_stream_write(SilcStream stream, const unsigned char *data,
- * SilcUInt32 data_len);
- *
- * DESCRIPTION
- *
- * Writes `data_len' bytes of data to the stream indicated by `stream' from
- * data buffer indicated by `data'. Returns the amount of data written,
- * zero (0) if end of stream occurred, -1 if data could not be written
- * at this moment, or -2 if error occurred. If -1 is returned the
- * notifier callback will later be called with SILC_STREAM_CAN_WRITE
- * status when stream is again ready for writing.
- *
- ***/
-int silc_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len);
-
-/****f* silcutil/SilcStreamAPI/silc_stream_close
- *
- * SYNOPSIS
- *
- * SilcBool silc_stream_close(SilcStream stream);
- *
- * DESCRIPTION
- *
- * Closes the stream indicated by `stream'. No data can be read or written
- * to the stream after calling this function. Return TRUE if the stream
- * could be closed. If action is taken on closed stream the notifier
- * callback may be called with an error status.
- *
- ***/
-SilcBool silc_stream_close(SilcStream stream);
-
-/****f* silcutil/SilcStreamAPI/silc_stream_destroy
- *
- * SYNOPSIS
- *
- * void silc_stream_destroy(SilcStream stream);
- *
- * DESCRIPTION
- *
- * Destroy the stream indicated by `stream'. The `stream' will become
- * invalid after this function returns. All streams are destroyed by
- * calling this function. The silc_stream_close should be called
- * before calling this function. However, if it is not called this
- * function will call it.
- *
- ***/
-void silc_stream_destroy(SilcStream stream);
-
-/****f* silcutil/SilcStreamAPI/silc_stream_set_notifier
- *
- * SYNOPSIS
- *
- * SilcBool 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. 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.
- *
- * This function returns FALSE if the `schedule' was provided and the
- * stream could not be scheduled. The actual API for `stream' may provide
- * access to the actual error information. Returns TRUE on success.
- *
- ***/
-SilcBool 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'.
- *
- ***/
-SilcSchedule silc_stream_get_schedule(SilcStream stream);
-
-#endif /* SILCSTREAM_H */
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "silcstringprep.h"
-#include "stringprep.h"
+#include <stringprep.h>
/* We use GNU Libidn which has stringprep to do the magic. Only bad thing
is that its interface is idiotic. We have our own API here in case
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcstrutil.h"
static unsigned char pem_enc[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-/* Encodes data into Base 64 encoding. Returns NULL terminated base 64 encoded
+/* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
data string. */
-char *silc_base64_encode(unsigned char *data, SilcUInt32 len)
+char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
{
int i, j;
SilcUInt32 bits, c, char_count;
/* Same as above but puts newline ('\n') every 72 characters. */
-char *silc_base64_encode_file(unsigned char *data, SilcUInt32 data_len)
+char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
{
int i, j;
SilcUInt32 len, cols;
char *pem, *pem2;
- pem = silc_base64_encode(data, data_len);
+ pem = silc_pem_encode(data, data_len);
len = strlen(pem);
pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
return pem2;
}
-/* Decodes Base 64 into data. Returns the decoded data. */
+/* Decodes PEM into data. Returns the decoded data. */
-unsigned char *silc_base64_decode(unsigned char *base64,
- SilcUInt32 base64_len,
- SilcUInt32 *ret_len)
+unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
+ SilcUInt32 *ret_len)
{
int i, j;
SilcUInt32 len, c, char_count, bits;
bits = 0;
j = 0;
- if (!base64_len)
- len = strlen(base64);
+ if (!pem_len)
+ len = strlen(pem);
else
- len = base64_len;
+ len = pem_len;
data = silc_calloc(((len * 6) / 8), sizeof(*data));
for (i = 0; i < len; i++) {
- c = base64[i];
+ c = pem[i];
if (c == '=')
break;
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. */
+
+bool
+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. */
return dest;
}
-/* Compares two strings. Strings may include wildcards '*' and '?'.
- Returns TRUE if strings match. */
-
-int silc_string_compare(char *string1, char *string2)
+/* 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, channel names,
+ server names, usernames, hostnames, service names, algorithm names,
+ other security property names, and SILC Public Key name. */
+
+unsigned char *silc_identifier_check(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length,
+ SilcUInt32 *out_len)
{
- int i;
- int slen1;
- int slen2;
- char *tmpstr1, *tmpstr2;
+ unsigned char *utf8s;
+ SilcUInt32 utf8s_len;
+ SilcStringprepStatus status;
- if (!string1 || !string2)
- return FALSE;
+ if (!identifier || !identifier_len)
+ return NULL;
- slen1 = strlen(string1);
- slen2 = strlen(string2);
-
- /* See if they are same already */
- if (!strncmp(string1, string2, slen2) && slen2 == slen1)
- return TRUE;
-
- if (slen2 < slen1)
- if (!strchr(string1, '*'))
- return FALSE;
-
- /* Take copies of the original strings as we will change them */
- tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
- memcpy(tmpstr1, string1, slen1);
- tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
- memcpy(tmpstr2, string2, slen2);
-
- for (i = 0; i < slen1; i++) {
-
- /* * wildcard. Only one * wildcard is possible. */
- if (tmpstr1[i] == '*')
- if (!strncmp(tmpstr1, tmpstr2, i)) {
- memset(tmpstr2, 0, slen2);
- strncpy(tmpstr2, tmpstr1, i);
- break;
- }
-
- /* ? wildcard */
- if (tmpstr1[i] == '?') {
- if (!strncmp(tmpstr1, tmpstr2, i)) {
- if (!(slen1 < i + 1))
- if (tmpstr1[i + 1] != '?' &&
- tmpstr1[i + 1] != tmpstr2[i + 1])
- continue;
-
- if (!(slen1 < slen2))
- tmpstr2[i] = '?';
- }
- }
+ if (max_allowed_length && identifier_len > max_allowed_length)
+ return NULL;
+
+ status = silc_stringprep(identifier, identifier_len,
+ identifier_encoding, SILC_IDENTIFIER_PREP, 0,
+ &utf8s, &utf8s_len, SILC_STRING_UTF8);
+ if (status != SILC_STRINGPREP_OK) {
+ SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
+ return NULL;
}
- /* if using *, remove it */
- if (strchr(tmpstr1, '*'))
- *strchr(tmpstr1, '*') = 0;
+ if (out_len)
+ *out_len = utf8s_len;
+
+ return utf8s;
+}
+
+/* Same as above but does not allocate memory, just checks the
+ validity of the string. */
+
+bool silc_identifier_verify(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length)
+{
+ SilcStringprepStatus status;
+
+ if (!identifier || !identifier_len)
+ return FALSE;
- if (!strcmp(tmpstr1, tmpstr2)) {
- memset(tmpstr1, 0, slen1);
- memset(tmpstr2, 0, slen2);
- silc_free(tmpstr1);
- silc_free(tmpstr2);
- return TRUE;
+ if (max_allowed_length && identifier_len > max_allowed_length)
+ return FALSE;
+
+ status = silc_stringprep(identifier, identifier_len,
+ identifier_encoding, SILC_IDENTIFIER_PREP, 0,
+ NULL, NULL, SILC_STRING_UTF8);
+ if (status != SILC_STRINGPREP_OK) {
+ SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
+ return FALSE;
}
- memset(tmpstr1, 0, slen1);
- memset(tmpstr2, 0, slen2);
- silc_free(tmpstr1);
- silc_free(tmpstr2);
- return FALSE;
+ return TRUE;
}
-/* Splits a string containing separator `ch' and returns an array of the
- splitted strings. */
-
-char **silc_string_split(const char *string, char ch, int *ret_count)
+unsigned char *silc_channel_name_check(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length,
+ SilcUInt32 *out_len)
{
- char **splitted = NULL, sep[1], *item, *cp;
- int i = 0, len;
+ unsigned char *utf8s;
+ SilcUInt32 utf8s_len;
+ SilcStringprepStatus status;
- if (!string)
- return NULL;
- if (!ret_count)
+ if (!identifier || !identifier_len)
return NULL;
- splitted = silc_calloc(1, sizeof(*splitted));
- if (!splitted)
+ if (max_allowed_length && identifier_len > max_allowed_length)
return NULL;
- if (!strchr(string, ch)) {
- splitted[0] = silc_memdup(string, strlen(string));
- *ret_count = 1;
- return splitted;
+ status = silc_stringprep(identifier, identifier_len,
+ identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
+ &utf8s, &utf8s_len, SILC_STRING_UTF8);
+ if (status != SILC_STRINGPREP_OK) {
+ SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
+ return NULL;
}
- sep[0] = ch;
- cp = (char *)string;
- while(cp) {
- len = strcspn(cp, sep);
- item = silc_memdup(cp, len);
- if (!item) {
- silc_free(splitted);
- return NULL;
- }
+ if (out_len)
+ *out_len = utf8s_len;
+
+ return utf8s;
+}
+
+/* Same as above but does not allocate memory, just checks the
+ validity of the string. */
+
+bool silc_channel_name_verify(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length)
+{
+ SilcStringprepStatus status;
- cp += len;
- if (strlen(cp) == 0)
- cp = NULL;
- else
- cp++;
+ if (!identifier || !identifier_len)
+ return FALSE;
- splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted));
- if (!splitted)
- return NULL;
- splitted[i++] = item;
+ if (max_allowed_length && identifier_len > max_allowed_length)
+ return FALSE;
+
+ status = silc_stringprep(identifier, identifier_len,
+ identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
+ NULL, NULL, SILC_STRING_UTF8);
+ if (status != SILC_STRINGPREP_OK) {
+ SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
+ return FALSE;
}
- *ret_count = i;
- return splitted;
+ return TRUE;
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 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
} SilcStringEncoding;
/***/
-/****f* silcutil/SilcStrUtilAPI/silc_base64_encode
+/****f* silcutil/SilcStrUtilAPI/silc_pem_encode
*
* SYNOPSIS
*
- * char *silc_base64_encode(unsigned char *data, SilcUInt32 len);
+ * char *silc_pem_encode(unsigned char *data, SilcUInt32 len);
*
* DESCRIPTION
*
- * Encodes data into Base 64 (PEM) encoding. Returns NULL terminated
- * Base 64 encoded data string.
+ * Encodes data into PEM encoding. Returns NULL terminated PEM encoded
+ * data string. Note: This is originally public domain code and is
+ * still PD.
*
***/
-char *silc_base64_encode(unsigned char *data, SilcUInt32 len);
+char *silc_pem_encode(unsigned char *data, SilcUInt32 len);
-/****f* silcutil/SilcStrUtilAPI/silc_base64_encode_file
+/****f* silcutil/SilcStrUtilAPI/silc_pem_encode_file
*
* SYNOPSIS
*
- * char *silc_base64_encode_file(unsigned char *data, SilcUInt32 data_len);
+ * char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len);
*
* DESCRIPTION
*
- * Same as silc_base64_encode() but puts newline ('\n') every 72
- * characters.
+ * Same as silc_pem_encode() but puts newline ('\n') every 72 characters.
*
***/
-char *silc_base64_encode_file(unsigned char *data, SilcUInt32 data_len);
+char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len);
-/****f* silcutil/SilcStrUtilAPI/silc_base_decode
+/****f* silcutil/SilcStrUtilAPI/silc_pem_decode
*
* SYNOPSIS
*
- * unsigned char *silc_base_decode(unsigned char *base64,
- * SilcUInt32 base64_len,
- * SilcUInt32 *ret_len);
+ * unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
+ * SilcUInt32 *ret_len);
*
* DESCRIPTION
*
- * Decodes Base 64 (PEM) into data. Returns the decoded data.
+ * Decodes PEM into data. Returns the decoded data. Note: This is
+ * originally public domain code and is still PD.
*
***/
-unsigned char *silc_base64_decode(unsigned char *base64,
- SilcUInt32 base64_len,
- SilcUInt32 *ret_len);
+unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
+ SilcUInt32 *ret_len);
-/****f* silcutil/SilcStrStrUtilAPI/silc_strncat
+/****f* silcutil/SilcStrUtilAPI/silc_mime_parse
+ *
+ * SYNOPSIS
+ *
+ * bool
+ * 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.
+ *
+ * NOTES
+ *
+ * This function is deprecated. Use the SilcMime API instead.
+ *
+ ***/
+bool
+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
*
char *silc_strncat(char *dest, SilcUInt32 dest_size,
const char *src, SilcUInt32 src_len);
-/****f* silcutil/SilcStrUtilAPI/silc_string_regexify
+/****f* silcutil/SilcStrUtilAPI/silc_identifier_check
*
* SYNOPSIS
*
- * char *silc_string_regexify(const char *string);
+ * unsigned char *
+ * silc_identifier_check(const unsigned char *identifier,
+ * SilcUInt32 identifier_len,
+ * SilcStringEncoding identifier_encoding,
+ * SilcUInt32 max_allowed_length,
+ * SilcUInt32 *out_len);
*
* DESCRIPTION
*
- * Inspects the `string' for wildcards and returns regex string that can
- * be used by the GNU regex library. A comma (`,') in the `string' means
- * that the string is list.
+ * 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
+ * property names, and SILC Public Key name.
*
- * This function is system dependant.
+ * 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
+* one anyway.
+ *
+ * Returns the validated string, that the caller must free. Returns
+ * NULL if the identifier string is not valid or contain unassigned or
+ * prohibited characters. Such identifier strings must not be used
+ * SILC protocol. The returned string is always in UTF-8 encoding.
+ * The length of the returned string is in 'out_len'.
+ *
+ * NOTES
+ *
+ * In addition of validating the identifier string, this function
+ * may map characters to other characters or remove characters from the
+ * original string. This is done as defined in the SILC protocol. Error
+ * is returned only if the string contains unassigned or prohibited
+ * characters. The original 'identifier' is not modified at any point.
*
***/
-char *silc_string_regexify(const char *string);
+unsigned char *silc_identifier_check(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length,
+ SilcUInt32 *out_len);
-/****f* silcutil/SilcStrUtilAPI/silc_string_regex_match
+/****f* silcutil/SilcStrUtilAPI/silc_identifier_verify
*
* SYNOPSIS
*
- * int silc_string_regex_match(const char *regex, const char *string);
+ * bool
+ * silc_identifier_check(const unsigned char *identifier,
+ * SilcUInt32 identifier_len,
+ * SilcStringEncoding identifier_encoding,
+ * SilcUInt32 max_allowed_length);
*
* DESCRIPTION
*
- * Matches the two strings and returns TRUE if the strings match.
+ * 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
+ * property names, and SILC Public Key name.
*
- * This function is system dependant.
+ * 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
+ * one anyway.
+ *
+ * Returns TRUE if the string is valid and FALSE if it is prohibited.
*
***/
-int silc_string_regex_match(const char *regex, const char *string);
+bool silc_identifier_verify(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length);
-/****f* silcutil/SilcStrUtilAPI/silc_string_match
+/****f* silcutil/SilcStrUtilAPI/silc_channel_name_check
*
* SYNOPSIS
*
- * int silc_string_match(const char *string1, const char *string2);
+ * unsigned char *
+ * silc_channel_name_check(const unsigned char *identifier,
+ * SilcUInt32 identifier_len,
+ * SilcStringEncoding identifier_encoding,
+ * SilcUInt32 max_allowed_length,
+ * SilcUInt32 *out_len);
*
* DESCRIPTION
*
- * Do regex match to the two strings `string1' and `string2'. If the
- * `string2' matches the `string1' this returns TRUE.
- *
- * This function is system dependant.
- *
- ***/
-int silc_string_match(const char *string1, const char *string2);
-
-/****f* silcutil/SilcStrUtilAPI/silc_string_compare
+ * Checks that the 'identifier' string is valid channel name string
+ * and does not contain any unassigned or prohibited character.
*
- * SYNOPSIS
+ * 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 channel names the max length must be 256
+ * bytes.
*
- * int silc_string_compare(char *string1, char *string2);
+ * Returns the validated string, that the caller must free. Returns
+ * NULL if the identifier string is not valid or contain unassigned or
+ * prohibited characters. Such identifier strings must not be used
+ * SILC protocol. The returned string is always in UTF-8 encoding.
+ * The length of the returned string is in 'out_len'.
*
- * DESCRIPTION
+ * NOTES
*
- * Compares two strings. Strings may include wildcards '*' and '?'.
- * Returns TRUE if strings match.
+ * In addition of validating the channel name string, this function
+ * may map characters to other characters or remove characters from the
+ * original string. This is done as defined in the SILC protocol. Error
+ * is returned only if the string contains unassigned or prohibited
+ * characters. The original 'identifier' is not modified at any point.
*
***/
-int silc_string_compare(char *string1, char *string2);
+unsigned char *silc_channel_name_check(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length,
+ SilcUInt32 *out_len);
-/****f* silcutil/SilcStrUtilAPI/silc_string_split
+/****f* silcutil/SilcStrUtilAPI/silc_channel_name_verify
*
* SYNOPSIS
*
- * char **silc_string_split(const char *string, char ch, int *ret_count);
+ * bool
+ * silc_channel_name_check(const unsigned char *identifier,
+ * SilcUInt32 identifier_len,
+ * SilcStringEncoding identifier_encoding,
+ * SilcUInt32 max_allowed_length);
*
* DESCRIPTION
*
- * Splits a `string' that has a separator `ch' into an array of strings
- * and returns the array. The `ret_count' will contain the number of
- * strings in the array. Caller must free the strings and the array.
- * Returns NULL on error. If the string does not have `ch' separator
- * this returns the `string' in the array.
+ * Checks that the 'identifier' string is valid channel name string
+ * and does not contain any unassigned or prohibited character.
+ *
+ * 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 channel names the max length must be 256
+ * bytes.
+ *
+ * Returns TRUE if the string is valid and FALSE if it is prohibited.
*
***/
-char **silc_string_split(const char *string, char ch, int *ret_count);
+bool silc_channel_name_verify(const unsigned char *identifier,
+ SilcUInt32 identifier_len,
+ SilcStringEncoding identifier_encoding,
+ SilcUInt32 max_allowed_length);
#endif /* SILCSTRUTIL_H */
* SYNOPSIS
*
* SilcThread silc_thread_create(SilcThreadStart start_func,
- * void *context, SilcBool waitable);
+ * void *context, bool waitable);
* DESCRIPTION
*
* Creates a new thread. The `start_func' with `context' will be
*
***/
SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- SilcBool waitable);
+ bool waitable);
/****f* silcutil/SilcThreadAPI/silc_thread_exit
*
*
* SYNOPSIS
*
- * SilcBool silc_thread_wait(SilcThread thread, void **exit_value);
+ * bool silc_thread_wait(SilcThread thread, void **exit_value);
*
* DESCRIPTION
*
* FALSE value.
*
***/
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value);
+bool silc_thread_wait(SilcThread thread, void **exit_value);
#endif
+++ /dev/null
-/*
-
- silctime.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2007 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"
-
-/* 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 msec)
-{
- if (year > (1 << 15))
- return FALSE;
- if (month < 1 || month > 12)
- return FALSE;
- if (day < 1 || day > 31)
- return FALSE;
- if (hour > 23)
- return FALSE;
- if (minute > 60)
- return FALSE;
- if (second > 61)
- return FALSE;
- if (msec > 1000)
- return FALSE;
-
- time->year = year;
- time->month = month;
- time->day = day;
- time->hour = hour;
- time->minute = minute;
- time->second = second;
- time->msecond = msec;
-
- return TRUE;
-}
-
-/* Return time since Epoch */
-
-SilcInt64 silc_time(void)
-{
- return (SilcInt64)time(NULL);
-}
-
-/* Return time since Epoch in milliseconds */
-
-SilcInt64 silc_time_msec(void)
-{
- struct timeval curtime;
- silc_gettimeofday(&curtime);
- return (curtime.tv_sec * 1000) + (curtime.tv_usec / 1000);
-}
-
-/* Return time since Epoch in microseconds */
-
-SilcInt64 silc_time_usec(void)
-{
- struct timeval curtime;
- silc_gettimeofday(&curtime);
- return (curtime.tv_sec * 1000000) + curtime.tv_usec;
-}
-
-/* Returns time as string */
-
-const char *silc_time_string(SilcInt64 time_val)
-{
- time_t curtime;
- char *return_time;
-
- if (!time_val)
- curtime = silc_time();
- else
- curtime = (time_t)time_val;
- return_time = ctime(&curtime);
- if (!return_time)
- return NULL;
- return_time[strlen(return_time) - 1] = '\0';
-
- return (const char *)return_time;
-}
-
-/* Returns time as SilcTime structure */
-
-SilcBool silc_time_value(SilcInt64 time_val, SilcTime ret_time)
-{
- struct tm *time;
- unsigned int msec = 0;
- time_t timeval;
-
- if (!ret_time)
- return TRUE;
-
- if (!time_val)
- time_val = silc_time_msec();
-
- msec = (SilcUInt64)time_val % (SilcUInt64)1000;
- timeval = (time_t)((SilcUInt64)time_val / (SilcUInt64)1000);
-
- time = localtime(&timeval);
- if (!time)
- return FALSE;
-
- memset(ret_time, 0, sizeof(*ret_time));
- if (!silc_time_fill(ret_time, time->tm_year + 1900, time->tm_mon + 1,
- time->tm_mday, time->tm_hour, time->tm_min,
- time->tm_sec, msec))
- return FALSE;
-
- ret_time->dst = time->tm_isdst ? 1 : 0;
-#ifdef SILC_WIN32
- ret_time->utc_east = _timezone < 0 ? 1 : 0;
- ret_time->utc_hour = (ret_time->utc_east ? (-(_timezone)) / 3600 :
- _timezone / 3600);
- ret_time->utc_minute = (ret_time->utc_east ? (-(_timezone)) % 3600 :
- _timezone % 3600);
-#else
-#if defined(HAVE_TZSET)
- ret_time->utc_east = timezone < 0 ? 1 : 0;
- ret_time->utc_hour = (ret_time->utc_east ? (-(timezone)) / 3600 :
- timezone / 3600);
- ret_time->utc_minute = (ret_time->utc_east ? (-(timezone)) % 3600 :
- timezone % 3600);
-#endif /* HAVE_TZSET */
-#endif /* SILC_WIN32 */
-
- return TRUE;
-}
-
-/* Returns timezone */
-
-SilcBool silc_timezone(char *timezone, SilcUInt32 timezone_size)
-{
- SilcTimeStruct curtime;
-
- if (timezone_size < 6)
- return FALSE;
-
- if (!silc_time_value(0, &curtime))
- return FALSE;
-
- if (!curtime.utc_hour && curtime.utc_minute)
- silc_snprintf(timezone, timezone_size, "Z");
- else if (curtime.utc_minute)
- silc_snprintf(timezone, timezone_size, "%c%02d:%02d",
- curtime.utc_east ? '+' : '-', curtime.utc_hour,
- curtime.utc_minute);
- else
- silc_snprintf(timezone, timezone_size, "%c%02d",
- curtime.utc_east ? '+' : '-', curtime.utc_hour);
-
- return TRUE;
-}
-
-/* Returns time from universal time string into SilcTime */
-
-SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time)
-{
- int ret;
- unsigned int year, month, day, hour = 0, minute = 0, second = 0;
- unsigned char z = 0;
-
- if (!ret_time)
- return TRUE;
- memset(ret_time, 0, sizeof(*ret_time));
-
- /* Parse the time string */
- ret = sscanf(universal_time, "%02u%02u%02u%02u%02u%02u%c", &year, &month,
- &day, &hour, &minute, &second, &z);
- if (ret < 3) {
- SILC_LOG_DEBUG(("Invalid UTC time string"));
- return FALSE;
- }
-
- /* Fill the SilcTime structure */
- ret = silc_time_fill(ret_time, year, month, day, hour, minute, second, 0);
- if (!ret) {
- SILC_LOG_DEBUG(("Incorrect values in UTC time string"));
- return FALSE;
- }
-
- /* Check timezone */
- if (z == '-' || z == '+') {
- ret = sscanf(universal_time + (ret * 2) + 1, "%02u%02u", &hour, &minute);
- if (ret != 2) {
- SILC_LOG_DEBUG(("Malformed UTC time string"));
- return FALSE;
- }
-
- if (hour < 0 || hour > 23)
- return FALSE;
- if (minute < 0 || minute > 60)
- return FALSE;
-
- ret_time->utc_hour = hour;
- ret_time->utc_minute = minute;
- ret_time->utc_east = (z == '-') ? 0 : 1;
- } else if (z != 'Z') {
- SILC_LOG_DEBUG(("Invalid timezone"));
- return FALSE;
- }
-
- /* UTC year must be fixed since it's represented only as YY not YYYY. */
- ret_time->year += 1900;
- if (ret_time->year < 1950)
- ret_time->year += 100;
-
- return TRUE;
-}
-
-/* Encode universal time string. */
-
-SilcBool silc_time_universal_string(SilcTime time_val, char *ret_string,
- SilcUInt32 ret_string_size)
-{
- int ret, len = 0;
- memset(ret_string, 0, ret_string_size);
- ret = silc_snprintf(ret_string, ret_string_size - 1,
- "%02u%02u%02u%02u%02u%02u",
- time_val->year % 100, time_val->month, time_val->day,
- time_val->hour, time_val->minute, time_val->second);
- if (ret < 0)
- return FALSE;
- len += ret;
-
- if (!time_val->utc_hour && !time_val->utc_minute) {
- ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len, "Z");
- if (ret < 0)
- return FALSE;
- len += ret;
- } else {
- ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len,
- "%c%02u%02u", time_val->utc_east ? '+' : '-',
- time_val->utc_hour, time_val->utc_minute);
- if (ret < 0)
- return FALSE;
- len += ret;
- }
-
- return TRUE;
-}
-
-/* Returns time from generalized time string into SilcTime */
-
-SilcBool silc_time_generalized(const char *generalized_time, SilcTime ret_time)
-{
- int ret, i;
- unsigned int year, month, day, hour = 0, minute = 0, second = 0;
- unsigned int msecond = 0;
- unsigned char z = 0;
-
- if (!ret_time)
- return TRUE;
- memset(ret_time, 0, sizeof(*ret_time));
-
- /* Parse the time string */
- ret = sscanf(generalized_time, "%04u%02u%02u%02u%02u%02u", &year, &month,
- &day, &hour, &minute, &second);
- if (ret < 3) {
- SILC_LOG_DEBUG(("Invalid generalized time string"));
- return FALSE;
- }
-
- /* Fill the SilcTime structure */
- ret = silc_time_fill(ret_time, year, month, day, hour, minute, second, 0);
- if (!ret) {
- SILC_LOG_DEBUG(("Incorrect values in generalized time string"));
- return FALSE;
- }
-
- /* Check fractions of second and/or timezone */
- i = ret * 4;
- ret = sscanf(generalized_time + i, "%c", &z);
- if (ret != 1) {
- SILC_LOG_DEBUG(("Malformed generalized time string"));
- return FALSE;
- }
-
- if (z == '.') {
- /* Take fractions of second */
- int l;
- i++;
- ret = sscanf(generalized_time + i, "%u%n", &msecond, &l);
- if (ret != 1) {
- SILC_LOG_DEBUG(("Malformed generalized time string"));
- return FALSE;
- }
- while (l > 4) {
- msecond /= 10;
- l--;
- }
- ret_time->msecond = msecond;
- i += l;
-
- /* Read optional timezone */
- if (strlen(generalized_time) < i)
- sscanf(generalized_time + i, "%c", &z);
- }
-
- /* Check timezone if present */
- if (z == '-' || z == '+') {
- ret = sscanf(generalized_time + i + 1, "%02u%02u", &hour, &minute);
- if (ret != 2) {
- SILC_LOG_DEBUG(("Malformed UTC time string"));
- return FALSE;
- }
-
- if (hour < 0 || hour > 23)
- return FALSE;
- if (minute < 0 || minute > 60)
- return FALSE;
-
- ret_time->utc_hour = hour;
- ret_time->utc_minute = minute;
- ret_time->utc_east = (z == '-') ? 0 : 1;
- }
-
- return TRUE;
-}
-
-/* Encode generalized time string */
-
-SilcBool silc_time_generalized_string(SilcTime time_val, char *ret_string,
- SilcUInt32 ret_string_size)
-{
- int len = 0, ret;
- memset(ret_string, 0, ret_string_size);
- ret = silc_snprintf(ret_string, ret_string_size - 1,
- "%04u%02u%02u%02u%02u%02u",
- time_val->year, time_val->month, time_val->day, time_val->hour,
- time_val->minute, time_val->second);
- if (ret < 0)
- return FALSE;
- len += ret;
-
- if (time_val->msecond) {
- ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len,
- ".%lu", (unsigned long)time_val->msecond);
- if (ret < 0)
- return FALSE;
- len += ret;
- }
-
- if (!time_val->utc_hour && !time_val->utc_minute) {
- ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len, "Z");
- if (ret < 0)
- return FALSE;
- len += ret;
- } else {
- ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len,
- "%c%02u%02u", time_val->utc_east ? '+' : '-',
- time_val->utc_hour, time_val->utc_minute);
- if (ret < 0)
- return FALSE;
- len += ret;
- }
-
- return TRUE;
-}
-
-/* Return TRUE if `smaller' is smaller than `bigger'. */
-
-SilcBool silc_compare_timeval(struct timeval *smaller,
- struct timeval *bigger)
-{
- if ((smaller->tv_sec < bigger->tv_sec) ||
- ((smaller->tv_sec == bigger->tv_sec) &&
- (smaller->tv_usec < bigger->tv_usec)))
- return TRUE;
-
- return FALSE;
-}
+++ /dev/null
-/*
-
- silctime.h
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2003 - 2007 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* silcutil/SILC Time Interface
- *
- * DESCRIPTION
- *
- * This interface provides various utility functions for getting current
- * time and converting different time representations into the SilcTime
- * representation.
- *
- ***/
-
-#ifndef SILCTIME_H
-#define SILCTIME_H
-
-/****s* silcutil/SilcTimeAPI/SilcTime
- *
- * NAME
- *
- * typedef struct { ... } *SilcTime, SilcTimeStruct;
- *
- * DESCRIPTION
- *
- * This context represents time value. It includes date and time
- * down to millisecond precision. The structure size is 64 bits.
- *
- * SOURCE
- *
- ***/
-typedef struct {
- unsigned int year : 15; /* Year, 0 - 32768 */
- unsigned int month : 4; /* Month, 1 - 12 */
- unsigned int day : 5; /* Day, 1 - 31 */
- unsigned int hour : 5; /* Hour, 0 - 23 */
- unsigned int minute : 6; /* Minute, 0 - 59 */
- unsigned int second : 6; /* Second, 0 - 61 */
- unsigned int msecond : 10; /* Millisec, 0 - 1000 */
- unsigned int utc_hour : 5; /* Offset to Zulu (UTC) hours */
- unsigned int utc_minute : 6; /* Offset to Zulu (UTC) minutes */
- unsigned int utc_east : 1; /* Offset, 1 east (+), 0 west (-) */
- unsigned int dst : 1; /* Set if daylight saving time */
-} *SilcTime, SilcTimeStruct;
-/***/
-
-/****f* silcutil/SilcTimeAPI/silc_time
- *
- * SYNOPSIS
- *
- * SilcInt64 silc_time(void);
- *
- * DESCRIPTION
- *
- * Returns the current time of the system since Epoch. The returned
- * value is seconds since Epoch (1.1.1970). Returns -1 on error.
- *
- ***/
-SilcInt64 silc_time(void);
-
-/****f* silcutil/SilcTimeAPI/silc_time_msec
- *
- * SYNOPSIS
- *
- * SilcInt64 silc_time_msec(void);
- *
- * DESCRIPTION
- *
- * Returns the current time of the system since Epoch in millisecond
- * resolution. Returns - 1 on error.
- *
- ***/
-SilcInt64 silc_time_msec(void);
-
-/****f* silcutil/SilcTimeAPI/silc_time_usec
- *
- * SYNOPSIS
- *
- * SilcInt64 silc_time_usec(void);
- *
- * DESCRIPTION
- *
- * Returns the current time of the system since Epoch in microsecond
- * resolution. Returns - 1 on error.
- *
- ***/
-SilcInt64 silc_time_usec(void);
-
-/****f* silcutil/SilcTimeAPI/silc_time_string
- *
- * SYNOPSIS
- *
- * const char *silc_time_string(SilcInt64 time_val_sec);
- *
- * DESCRIPTION
- *
- * Returns time and date as string. The caller must not free the string
- * and next call to this function will delete the old string. If the
- * `time_val_sec' is zero (0) returns current time as string, otherwise the
- * `time_val_sec' as string. The `time_val_sec' is in seconds since Epoch.
- * Returns NULL on error.
- *
- ***/
-const char *silc_time_string(SilcInt64 time_val_sec);
-
-/****f* silcutil/SilcTimeAPI/silc_time_value
- *
- * SYNOPSIS
- *
- * SilcBool silc_time_value(SilcInt64 time_val_msec, SilcTime ret_time);
- *
- * DESCRIPTION
- *
- * Returns time and date as SilcTime. If the `time_val_msec' is zero (0)
- * returns current time as SilcTime, otherwise the `time_val_msec' as
- * SilcTime. The `time_val_msec' is in milliseconds since Epoch. Returns
- * FALSE on error, TRUE otherwise.
- *
- ***/
-SilcBool silc_time_value(SilcInt64 time_val_msec, SilcTime ret_time);
-
-/****f* silcutil/SilcTimeAPI/silc_timezone
- *
- * SYNOPSIS
- *
- * SilcBool silc_timezone(char *timezone, SilcUInt32 timezone_size);
- *
- * DESCRIPTION
- *
- * Returns current timezone in Universal time format into the `timezone'
- * buffer of size of `timezone_size'. The possible values this function
- * returns are: Z (For UTC timezone), +hh (UTC + hours) -hh (UTC - hours),
- * +hh:mm (UTC + hours:minutes) or -hh:mm (UTC - hours:minutes).
- *
- * Returns FALSE on error, TRUE otherwise.
- *
- ***/
-SilcBool silc_timezone(char *timezone, SilcUInt32 timezone_size);
-
-/****f* silcutil/SilcTimeAPI/silc_time_universal
- *
- * SYNOPSIS
- *
- * SilcBool silc_time_universal(const char *universal_time,
- * SilcTime ret_time);
- *
- * DESCRIPTION
- *
- * Returns time and date as SilcTime from `universal_time' string which
- * format is "YYMMDDhhmmssZ", where YY is year, MM is month, DD is day,
- * hh is hour, mm is minutes, ss is seconds and Z is timezone, which
- * by default is Zulu (UTC). Universal time is defined in ISO/EIC 8824-1.
- *
- * Returns FALSE on error, TRUE otherwise.
- *
- * EXAMPLE
- *
- * SilcTimeStruct ret_time;
- *
- * time is 03/02/19 19:04:03 Zulu (UTC)
- * silc_time_universal("030219190403Z", &ret_time);
- *
- ***/
-SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time);
-
-/****f* silcutil/SilcTimeAPI/silc_time_universal_string
- *
- * SYNOPSIS
- *
- * SilcBool silc_time_universal_string(SilcTime time_val, char *ret_string,
- * SilcUInt32 ret_string_size);
- *
- * DESCRIPTION
- *
- * Encodes the SilcTime `time' into the universal time format into the
- * `ret_string' buffer. Returns FALSE if the buffer is too small.
- *
- ***/
-SilcBool silc_time_universal_string(SilcTime time_val, char *ret_string,
- SilcUInt32 ret_string_size);
-
-/****f* silcutil/SilcTimeAPI/silc_time_generalized
- *
- * SYNOPSIS
- *
- * SilcBool silc_time_generalized(const char *generalized_time,
- * SilcTime ret_time);
- *
- * DESCRIPTION
- *
- * Returns time and date as SilcTime from `generalized_time' string which
- * format is "YYYYMMDDhhmmss.ppZ", where YYYY is year, MM is month, DD
- * is day, hh is hour, mm is minutes, ss is seconds which may have optional
- * precision pp, and Z is timezone, which by default is Zulu (UTC).
- * Generalized time is defined in ISO/EIC 8824-1.
- *
- * Returns FALSE on error, TRUE otherwise.
- *
- * EXAMPLE
- *
- * SilcTimeStruct ret_time;
- *
- * time is 2003/02/19 19:04:03 Zulu (UTC)
- * silc_time_generalized("20030219190403Z", &ret_time);
- *
- * time is 2003/02/19 19:05:10.212 Zulu (UTC)
- * silc_time_generalized("20030219190510.212Z", &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 time_val,
- * char *ret_string,
- * SilcUInt32 ret_string_size);
- *
- * DESCRIPTION
- *
- * Encodes the SilcTime `time' into the generalized time format into the
- * `ret_string' buffer. Returns FALSE if the buffer is too small.
- *
- ***/
-SilcBool silc_time_generalized_string(SilcTime time_val, char *ret_string,
- SilcUInt32 ret_string_size);
-
-/****f* silcutil/SilcTimeAPI/silc_compare_timeval
- *
- * SYNOPSIS
- *
- * SilcBool silc_compare_timeval(struct time_val *smaller,
- * struct time_val *bigger)
- *
- * DESCRIPTION
- *
- * Compare two timeval structures and return TRUE if the first
- * time value is smaller than the second time value.
- *
- ***/
-SilcBool silc_compare_timeval(struct timeval *smaller,
- struct timeval *bigger);
-
-/****f* silcutil/SilcTimeAPI/silc_gettimeofday
- *
- * SYNOPSIS
- *
- * int silc_gettimeofday(struct timeval *p);
- *
- * DESCRIPTION
- *
- * Return current time to struct timeval. This function is system
- * dependant. Returns 0 on success and -1 on error.
- *
- ***/
-int silc_gettimeofday(struct timeval *p);
-
-/****f* silcutil/SilcTimeAPI/silc_usleep
- *
- * SYNOPSIS
- *
- * void silc_usleep(long microseconds);
- *
- * DESCRIPTION
- *
- * Delays the execution of process/thread for the specified amount of
- * time, which is in microseconds.
- *
- * NOTES
- *
- * The delay is only approximate and on some platforms the resolution is
- * in fact milliseconds.
- *
- ***/
-static inline
-void silc_usleep(long microseconds)
-{
-#ifdef SILC_UNIX
-#ifdef HAVE_NANOSLEEP
- struct timespec tv;
- tv.tv_sec = 0;
- tv.tv_nsec = microseconds * 1000;
-#endif /* HAVE_NANOSLEEP */
-#endif /* SILC_UNIX */
-
-#ifdef SILC_UNIX
-#ifdef HAVE_NANOSLEEP
- nanosleep(&tv, NULL);
-#else
- usleep(microseconds);
-#endif /* HAVE_NANOSLEEP */
-#endif /* SILC_UNIX */
-#ifdef SILC_WIN32
- Sleep(microseconds / 1000);
-#endif /* SILC_WIN32 */
-#ifdef SILC_SYMBIAN
- User::After(microseconds / 1000);
-#endif /* SILC_SYMBIAN */
-}
-
-#endif /* SILCTIME_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2007 Pekka Riikonen
+ Copyright (C) 2002 - 2004 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 SILCTYPES_H
#define SILCTYPES_H
-/****d* silcutil/SILCTypes/SilcBool
- *
- * NAME
- *
- * typedef unigned char SilcBool;
- *
- * DESCRIPTION
- *
- * Boolean value, and is always 8-bits. Represents value 0 or 1.
- *
- ***/
-typedef unsigned char SilcBool;
-
-/* The bool macro is deprecated. Use SilcBool instead. */
-#ifdef SILC_MACOSX
-#define bool _Bool
-#endif
-#ifndef __cplusplus
-#ifndef bool
-#define bool unsigned char
-#endif
-#endif
-
/****d* silcutil/SILCTypes/TRUE
*
* NAME
#endif
/***/
-/* Our offsetof macro */
-#define silc_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+/****d* silcutil/SILCTypes/bool
+ *
+ * NAME
+ *
+ * #define bool ...
+ *
+ * DESCRIPTION
+ *
+ * Boolean value, and is 8-bits. Represents value 0 or 1. In
+ * C++ code this type is defined by the C++, and this definition is
+ * not used.
+ *
+ * SOURCE
+ */
+#ifdef SILC_MACOSX
+#define bool _Bool
+#endif
-/* silc_likely and silc_unlikely GCC branch prediction macros. Use only if
- you have profiled the code first. */
-#if __GNUC__ >= 3
-#define silc_likely(expr) __builtin_expect(!!(expr), 1)
-#define silc_unlikely(expr) __builtin_expect(!!(expr), 0)
-#else
-#define silc_likely(expr) (expr)
-#define silc_unlikely(expr) (expr)
-#endif /* __GNUC__ >= 3 */
+#ifndef __cplusplus
+#ifndef bool
+#define bool unsigned char
+#endif
+#endif
+/***/
+
+#define silc_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#if SILC_SIZEOF_SHORT > 2
#error "size of the short must be 2 bytes"
typedef SilcUInt32 * void *;
#endif
-/****d* silcutil/SILCTypes/SilcSocket
- *
- * NAME
- *
- * SilcSocket
- *
- * DESCRIPTION
- *
- * Platform specific socket. On POSIX compliant systems this is simply
- * an integer, representing the socket. On other systems it is platform
- * specific socket context. Access it only through routines that can
- * handle SilcSocket types, unless you know what you are doing.
- *
- * SOURCE
- */
-#if defined(SILC_UNIX) || defined(SILC_WIN32)
-typedef int SilcSocket;
-#elif defined(SILC_SYMBIAN)
-typedef void * SilcSocket;
-#endif
-/***/
-
/* Macros */
#define SILC_GET_WORD(cp) ((SilcUInt32)(SilcUInt8)(cp)[0]) << 24 \
*/
#define SILC_GET16_MSB(l, cp) \
do { \
- (l) = ((SilcUInt32)(SilcUInt8)(cp)[0] << 8) \
- | ((SilcUInt32)(SilcUInt8)(cp)[1]); \
+ (l) = ((SilcUInt32)(SilcUInt8)(cp)[0] << 8) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[1]); \
} while(0)
/***/
*/
#define SILC_GET32_MSB(l, cp) \
do { \
- (l) = ((SilcUInt32)(SilcUInt8)(cp)[0]) << 24 \
- | ((SilcUInt32)(SilcUInt8)(cp)[1] << 16) \
- | ((SilcUInt32)(SilcUInt8)(cp)[2] << 8) \
- | ((SilcUInt32)(SilcUInt8)(cp)[3]); \
+ (l) = ((SilcUInt32)(SilcUInt8)(cp)[0]) << 24 \
+ | ((SilcUInt32)(SilcUInt8)(cp)[1] << 16) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[2] << 8) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[3]); \
} while(0)
/***/
*/
#define SILC_GET64_MSB(l, cp) \
do { \
- (l) = ((((SilcUInt64)SILC_GET_WORD((cp))) << 32) | \
- ((SilcUInt64)SILC_GET_WORD((cp) + 4))); \
+ (l) = ((((SilcUInt64)SILC_GET_WORD((cp))) << 32) | \
+ ((SilcUInt64)SILC_GET_WORD((cp) + 4))); \
} while(0)
/***/
*
* SOURCE
*/
-#if defined(SILC_I486) && defined(__GNUC__)
-#define SILC_GET16_LSB(l, cp) (l) = (*(SilcUInt16 *)(cp))
-#else
#define SILC_GET16_LSB(l, cp) \
do { \
- (l) = ((SilcUInt32)(SilcUInt8)(cp)[0]) \
- | ((SilcUInt32)(SilcUInt8)(cp)[1] << 8); \
+ (l) = ((SilcUInt32)(SilcUInt8)(cp)[0]) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[1] << 8); \
} while(0)
-#endif /* SILC_I486 && __GNUC__ */
/***/
/****d* silcutil/SILCTypes/SILC_GET32_LSB
*
* SOURCE
*/
-#if defined(SILC_I486) && defined(__GNUC__)
-#define SILC_GET32_LSB(l, cp) (l) = (*(SilcUInt32 *)(cp))
-#else
#define SILC_GET32_LSB(l, cp) \
do { \
- (l) = ((SilcUInt32)(SilcUInt8)(cp)[0]) \
- | ((SilcUInt32)(SilcUInt8)(cp)[1] << 8) \
- | ((SilcUInt32)(SilcUInt8)(cp)[2] << 16) \
- | ((SilcUInt32)(SilcUInt8)(cp)[3] << 24); \
+ (l) = ((SilcUInt32)(SilcUInt8)(cp)[0]) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[1] << 8) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[2] << 16) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[3] << 24); \
} while(0)
-#endif /* SILC_I486 && __GNUC__ */
/* Same as upper but XOR the result always. Special purpose macro. */
-#if defined(SILC_I486) && defined(__GNUC__)
-#define SILC_GET32_X_LSB(l, cp) (l) ^= (*(SilcUInt32 *)(cp))
-#else
#define SILC_GET32_X_LSB(l, cp) \
- (l) ^= ((SilcUInt32)(SilcUInt8)(cp)[0]) \
- | ((SilcUInt32)(SilcUInt8)(cp)[1] << 8) \
- | ((SilcUInt32)(SilcUInt8)(cp)[2] << 16) \
- | ((SilcUInt32)(SilcUInt8)(cp)[3] << 24)
-#endif /* SILC_I486 && __GNUC__ */
+ (l) ^= ((SilcUInt32)(SilcUInt8)(cp)[0]) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[1] << 8) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[2] << 16) \
+ | ((SilcUInt32)(SilcUInt8)(cp)[3] << 24)
/***/
/****d* silcutil/SILCTypes/SILC_PUT16_MSB
*/
#define SILC_PUT16_MSB(l, cp) \
do { \
- (cp)[0] = (SilcUInt8)((l) >> 8); \
- (cp)[1] = (SilcUInt8)(l); \
+ (cp)[0] = (SilcUInt8)((l) >> 8); \
+ (cp)[1] = (SilcUInt8)(l); \
} while(0)
/***/
*/
#define SILC_PUT32_MSB(l, cp) \
do { \
- (cp)[0] = (SilcUInt8)((l) >> 24); \
- (cp)[1] = (SilcUInt8)((l) >> 16); \
- (cp)[2] = (SilcUInt8)((l) >> 8); \
- (cp)[3] = (SilcUInt8)(l); \
+ (cp)[0] = (SilcUInt8)((l) >> 24); \
+ (cp)[1] = (SilcUInt8)((l) >> 16); \
+ (cp)[2] = (SilcUInt8)((l) >> 8); \
+ (cp)[3] = (SilcUInt8)(l); \
} while(0)
/***/
*
* SOURCE
*/
-#if defined(SILC_I486) && defined(__GNUC__)
-#define SILC_PUT16_LSB(l, cp) (*(SilcUInt16 *)(cp)) = (l)
-#else
#define SILC_PUT16_LSB(l, cp) \
do { \
- (cp)[0] = (SilcUInt8)(l); \
- (cp)[1] = (SilcUInt8)((l) >> 8); \
+ (cp)[0] = (SilcUInt8)(l); \
+ (cp)[1] = (SilcUInt8)((l) >> 8); \
} while(0)
-#endif /* SILC_I486 && __GNUC__ */
/***/
/****d* silcutil/SILCTypes/SILC_PUT32_LSB
*
* SOURCE
*/
-#if defined(SILC_I486) && defined(__GNUC__)
-#define SILC_PUT32_LSB(l, cp) (*(SilcUInt32 *)(cp)) = (l)
-#else
#define SILC_PUT32_LSB(l, cp) \
do { \
- (cp)[0] = (SilcUInt8)(l); \
- (cp)[1] = (SilcUInt8)((l) >> 8); \
- (cp)[2] = (SilcUInt8)((l) >> 16); \
- (cp)[3] = (SilcUInt8)((l) >> 24); \
+ (cp)[0] = (SilcUInt8)(l); \
+ (cp)[1] = (SilcUInt8)((l) >> 8); \
+ (cp)[2] = (SilcUInt8)((l) >> 16); \
+ (cp)[3] = (SilcUInt8)((l) >> 24); \
} while(0)
-#endif /* SILC_I486 && __GNUC__ */
/***/
/****d* silcutil/SILCTypes/SILC_SWAB_16
#if SILC_SIZEOF_VOID_P < 8
#define SILC_PTR_TO_64(_ptr__) ((SilcUInt64)((SilcUInt32)(_ptr__)))
#else
-#define SILC_PTR_TO_64(_ptr__) ((SilcUInt64)((SilcUInt64)(_ptr__)))
+#define SILC_PTR_TO_64(_ptr__) \
+ ((SilcUInt64)((SilcUInt64)(_ptr__) & (SilcUInt32)0xFFFFFFFFUL))
#endif
/***/
*
* NAME
*
- * #define SILC_32_TO_PTR ...
+ * #define SILC_PTR_TO_32 ...
*
* DESCRIPTION
*
*
* NAME
*
- * #define SILC_64_TO_PTR ...
+ * #define SILC_PTR_TO_64 ...
*
* DESCRIPTION
*
*/
-#include "silc.h"
+#include "silcincludes.h"
#include "silcutf8.h"
/* Encodes the string `bin' of which encoding is `bin_encoding' to the
if (enclen + 3 > bin_size)
return 0;
bin[enclen] = '\\';
- silc_snprintf(bin + enclen + 1, 3, "%02X", cv);
+ snprintf(bin + enclen + 1, 3, "%02X", cv);
}
enclen += 3;
continue;
/* Returns TRUE if the `utf8' string of length of `utf8_len' is valid
UTF-8 encoded string, FALSE if it is not UTF-8 encoded string. */
-SilcBool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len)
+bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len)
{
return silc_utf8_decode(utf8, utf8_len, 0, NULL, 0) != 0;
}
/* Pretty close strcasecmp */
-SilcBool silc_utf8_strcasecmp(const char *s1, const char *s2)
+bool silc_utf8_strcasecmp(const char *s1, const char *s2)
{
if (s1 == s2)
return TRUE;
/* Pretty close strcasecmp */
-SilcBool silc_utf8_strncasecmp(const char *s1, const char *s2, SilcUInt32 n)
+bool silc_utf8_strncasecmp(const char *s1, const char *s2, SilcUInt32 n)
{
unsigned char *s1u, *s2u;
SilcUInt32 s1u_len, s2u_len;
SilcStringprepStatus status;
- SilcBool ret;
+ bool ret;
if (s1 == s2)
return TRUE;
/* Casefold and normalize */
- status = silc_stringprep(s1, n, SILC_STRING_UTF8,
+ status = silc_stringprep(s1, strlen(s1), SILC_STRING_UTF8,
SILC_IDENTIFIERC_PREP, 0, &s1u,
&s1u_len, SILC_STRING_UTF8);
if (status != SILC_STRINGPREP_OK)
return FALSE;
/* Casefold and normalize */
- status = silc_stringprep(s2, n, SILC_STRING_UTF8,
+ status = silc_stringprep(s2, strlen(s2), SILC_STRING_UTF8,
SILC_IDENTIFIERC_PREP, 0, &s2u,
&s2u_len, SILC_STRING_UTF8);
if (status != SILC_STRINGPREP_OK)
*
* SYNOPSIS
*
- * SilcBool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len);
+ * bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len);
*
* DESCRIPTION
*
* UTF-8 encoded string, FALSE if it is not UTF-8 encoded string.
*
***/
-SilcBool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len);
+bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len);
/****f* silcutil/SilcStrUtilAPI/silc_utf8_strcasecmp
*
* SYNOPSIS
*
- * SilcBool silc_utf8_strcasecmp(const char *s1, const char *s2);
+ * bool silc_utf8_strcasecmp(const char *s1, const char *s2);
*
* DESCRIPTION
*
* Unicode characters will be ignored when comparing.
*
***/
-SilcBool silc_utf8_strcasecmp(const char *s1, const char *s2);
+bool silc_utf8_strcasecmp(const char *s1, const char *s2);
/****f* silcutil/SilcStrUtilAPI/silc_utf8_strncasecmp
*
* SYNOPSIS
*
- * SilcBool silc_utf8_strcasecmp(const char *s1, const char *s2,
+ * bool silc_utf8_strcasecmp(const char *s1, const char *s2,
* SilcUInt32 n);
*
* DESCRIPTION
* Unicode characters will be ignored when comparing.
*
***/
-SilcBool silc_utf8_strncasecmp(const char *s1, const char *s2, SilcUInt32 n);
+bool silc_utf8_strncasecmp(const char *s1, const char *s2, SilcUInt32 n);
#endif /* SILCUTF8_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.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
return 0;
}
+/* Returns time as string. If the the `timeval' is non-zero that
+ value is returned as string. If it is zero the current time of the
+ local machine is returned. */
+
+const char *silc_get_time(SilcUInt32 timeval)
+{
+ time_t curtime;
+ char *return_time;
+
+ if (!timeval)
+ curtime = time(NULL);
+ else
+ curtime = (time_t)timeval;
+ return_time = ctime(&curtime);
+ return_time[strlen(return_time) - 1] = '\0';
+
+ return (const char *)return_time;
+}
+
/* Converts string to capital characters. */
-SilcBool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
+bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
{
int i;
return FALSE;
for (i = 0; i < strlen(string); i++)
- dest[i] = (char)toupper((int)string[i]);
+ dest[i] = toupper(string[i]);
return TRUE;
}
/* Converts string to lower letter characters. */
-SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
+bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
{
int i;
return FALSE;
for (i = 0; i < strlen(string); i++)
- dest[i] = (char)tolower((int)string[i]);
+ dest[i] = tolower(string[i]);
return TRUE;
}
/* Parse userfqdn string which is in user@fqdn format. */
-int silc_parse_userfqdn(const char *string,
- char *user, SilcUInt32 user_size,
- char *fqdn, SilcUInt32 fqdn_size)
+bool silc_parse_userfqdn(const char *string, char **left, char **right)
{
SilcUInt32 tlen;
- if (!user && !fqdn)
- return 0;
-
- memset(user, 0, user_size);
- memset(fqdn, 0, fqdn_size);
-
if (!string)
- return 0;
+ return FALSE;
if (string[0] == '@') {
- if (user)
- silc_strncat(user, user_size, string, strlen(string));
-
- return 1;
+ if (left)
+ *left = strdup(string);
+ return TRUE;
}
if (strchr(string, '@')) {
tlen = strcspn(string, "@");
- if (user)
- silc_strncat(user, user_size, string, tlen);
-
- if (fqdn)
- silc_strncat(fqdn, fqdn_size, string + tlen + 1,
- strlen(string) - tlen - 1);
+ if (left) {
+ *left = silc_calloc(tlen + 1, sizeof(char));
+ memcpy(*left, string, tlen);
+ }
- return 2;
+ if (right) {
+ *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
+ memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
+ }
+ } else {
+ if (left)
+ *left = silc_memdup(string, strlen(string));
}
- if (user)
- silc_strncat(user, user_size, string, strlen(string));
-
- return 1;
+ return TRUE;
}
/* Parses command line. At most `max_args' is taken. Rest of the line
char *silc_format(char *fmt, ...)
{
va_list args;
- char buf[8192];
+ static char buf[8192];
memset(buf, 0, sizeof(buf));
va_start(args, fmt);
- silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+ vsnprintf(buf, sizeof(buf) - 1, fmt, args);
va_end(args);
return strdup(buf);
}
+/* Renders ID to suitable to print for example to log file. */
+
+static char rid[256];
+#define _PUT_STRING(__d__, __s__) \
+do { \
+ int __sp = sizeof(__d__) - 1 - strlen(__d__); \
+ if (__sp < strlen(__s__)) { \
+ if (__sp) \
+ strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \
+ } else { \
+ strncat(__d__, __s__, strlen(__s__)); \
+ } \
+} while(0)
+
+char *silc_id_render(void *id, SilcUInt16 type)
+{
+ char tmp[100];
+ unsigned char tmps[2];
+ char *cp;
+
+ memset(rid, 0, sizeof(rid));
+ switch(type) {
+ case SILC_ID_SERVER:
+ {
+ SilcServerID *server_id = (SilcServerID *)id;
+ if (server_id->ip.data_len > 4) {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+ memset(&ipv6, 0, sizeof(ipv6));
+ ipv6.sin6_family = AF_INET6;
+ memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
+ if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
+ tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
+ _PUT_STRING(rid, tmp);
+#endif
+ } else {
+ struct in_addr ipv4;
+ memmove(&ipv4.s_addr, server_id->ip.data, 4);
+ cp = inet_ntoa(ipv4);
+ if (cp)
+ _PUT_STRING(rid, cp);
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
+ _PUT_STRING(rid, tmp);
+ SILC_PUT16_MSB(server_id->rnd, tmps);
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
+ _PUT_STRING(rid, tmp);
+ }
+ break;
+ case SILC_ID_CLIENT:
+ {
+ SilcClientID *client_id = (SilcClientID *)id;
+ if (client_id->ip.data_len > 4) {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+ memset(&ipv6, 0, sizeof(ipv6));
+ ipv6.sin6_family = AF_INET6;
+ memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
+ if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
+ tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
+ _PUT_STRING(rid, tmp);
+#endif
+ } else {
+ struct in_addr ipv4;
+ memmove(&ipv4.s_addr, client_id->ip.data, 4);
+ cp = inet_ntoa(ipv4);
+ if (cp)
+ _PUT_STRING(rid, cp);
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
+ _PUT_STRING(rid, tmp);
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
+ client_id->hash[0], client_id->hash[1],
+ client_id->hash[2], client_id->hash[3]);
+ _PUT_STRING(rid, tmp);
+ }
+ break;
+ case SILC_ID_CHANNEL:
+ {
+ SilcChannelID *channel_id = (SilcChannelID *)id;
+ if (channel_id->ip.data_len > 4) {
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 ipv6;
+ memset(&ipv6, 0, sizeof(ipv6));
+ ipv6.sin6_family = AF_INET6;
+ memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
+ if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
+ tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
+ _PUT_STRING(rid, tmp);
+#endif
+ } else {
+ struct in_addr ipv4;
+ memmove(&ipv4.s_addr, channel_id->ip.data, 4);
+ cp = inet_ntoa(ipv4);
+ if (cp)
+ _PUT_STRING(rid, cp);
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
+ _PUT_STRING(rid, tmp);
+ SILC_PUT16_MSB(channel_id->rnd, tmps);
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
+ _PUT_STRING(rid, tmp);
+ }
+ break;
+ }
+
+ return rid;
+}
+#undef _PUT_STRING
+
+/* Compares two strings. Strings may include wildcards '*' and '?'.
+ Returns TRUE if strings match. */
+
+int silc_string_compare(char *string1, char *string2)
+{
+ int i;
+ int slen1;
+ int slen2;
+ char *tmpstr1, *tmpstr2;
+
+ if (!string1 || !string2)
+ return FALSE;
+
+ slen1 = strlen(string1);
+ slen2 = strlen(string2);
+
+ /* See if they are same already */
+ if (!strncmp(string1, string2, slen2) && slen2 == slen1)
+ return TRUE;
+
+ if (slen2 < slen1)
+ if (!strchr(string1, '*'))
+ return FALSE;
+
+ /* Take copies of the original strings as we will change them */
+ tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
+ memcpy(tmpstr1, string1, slen1);
+ tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
+ memcpy(tmpstr2, string2, slen2);
+
+ for (i = 0; i < slen1; i++) {
+
+ /* * wildcard. Only one * wildcard is possible. */
+ if (tmpstr1[i] == '*')
+ if (!strncmp(tmpstr1, tmpstr2, i)) {
+ memset(tmpstr2, 0, slen2);
+ strncpy(tmpstr2, tmpstr1, i);
+ break;
+ }
+
+ /* ? wildcard */
+ if (tmpstr1[i] == '?') {
+ if (!strncmp(tmpstr1, tmpstr2, i)) {
+ if (!(slen1 < i + 1))
+ if (tmpstr1[i + 1] != '?' &&
+ tmpstr1[i + 1] != tmpstr2[i + 1])
+ continue;
+
+ if (!(slen1 < slen2))
+ tmpstr2[i] = '?';
+ }
+ }
+ }
+
+ /* if using *, remove it */
+ if (strchr(tmpstr1, '*'))
+ *strchr(tmpstr1, '*') = 0;
+
+ if (!strcmp(tmpstr1, tmpstr2)) {
+ memset(tmpstr1, 0, slen1);
+ memset(tmpstr2, 0, slen2);
+ silc_free(tmpstr1);
+ silc_free(tmpstr2);
+ return TRUE;
+ }
+
+ memset(tmpstr1, 0, slen1);
+ memset(tmpstr2, 0, slen2);
+ silc_free(tmpstr1);
+ silc_free(tmpstr2);
+ return FALSE;
+}
+
/* Basic has function to hash strings. May be used with the SilcHashTable.
Note that this lowers the characters of the string (with tolower()) so
this is used usually with nicknames, channel and server names to provide
SilcUInt32 h = 0, g;
while (*s != '\0') {
- h = (h << 4) + tolower((int)*s);
+ h = (h << 4) + tolower(*s);
if ((g = h & 0xf0000000)) {
h = h ^ (g >> 24);
h = h ^ g;
return h;
}
-/* Hash public key of any type. */
+/* Hashed SILC Public key. */
SilcUInt32 silc_hash_public_key(void *key, void *user_context)
{
- SilcPublicKey public_key = key;
- unsigned char *pk;
- SilcUInt32 pk_len;
- SilcUInt32 hash = 0;
-
- pk = silc_pkcs_public_key_encode(public_key, &pk_len);
- if (!pk)
- return hash;
-
- hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len));
- silc_free(pk);
-
- return hash;
+ SilcPublicKey pk = (SilcPublicKey)key;
+ return (pk->len + (silc_hash_string(pk->name, NULL) ^
+ silc_hash_string(pk->identifier, NULL) ^
+ silc_hash_data(pk->pk, SILC_32_TO_PTR(pk->pk_len))));
}
/* Compares two strings. It may be used as SilcHashTable comparison
function. */
-SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
+bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
{
return !strcasecmp((char *)key1, (char *)key2);
}
The Client ID's compares only the hash of the Client ID not any other
part of the Client ID. Other ID's are fully compared. */
-SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
+bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
{
SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
return (id_type == SILC_ID_CLIENT ?
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)
+bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
{
return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
}
/* Compares binary data. May be used as SilcHashTable comparison function. */
-SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
+bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
{
SilcUInt32 len = SILC_PTR_TO_32(user_context);
return !memcmp(key1, key2, len);
/* Compares UTF-8 string. */
-SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
+bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
{
int l1 = strlen((char *)key1);
int l2 = strlen((char *)key2);
- if (l1 != l2)
- return FALSE;
+ if (l1 > l2)
+ l2 = l1;
return !memcmp(key1, key2, l2);
}
/* Compares two SILC Public keys. It may be used as SilcHashTable
comparison function. */
-SilcBool silc_hash_public_key_compare(void *key1, void *key2,
- void *user_context)
+bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
{
return silc_pkcs_public_key_compare(key1, key2);
}
+/* Parses mode mask and returns the mode as string. */
+
+char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
+{
+ char string[100];
+
+ if (!mode)
+ return NULL;
+
+ memset(string, 0, sizeof(string));
+
+ if (mode & SILC_CHANNEL_MODE_PRIVATE)
+ strncat(string, "p", 1);
+
+ if (mode & SILC_CHANNEL_MODE_SECRET)
+ strncat(string, "s", 1);
+
+ if (mode & SILC_CHANNEL_MODE_PRIVKEY)
+ strncat(string, "k", 1);
+
+ if (mode & SILC_CHANNEL_MODE_INVITE)
+ strncat(string, "i", 1);
+
+ if (mode & SILC_CHANNEL_MODE_TOPIC)
+ strncat(string, "t", 1);
+
+ if (mode & SILC_CHANNEL_MODE_ULIMIT)
+ strncat(string, "l", 1);
+
+ if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
+ strncat(string, "a", 1);
+
+ if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
+ strncat(string, "f", 1);
+
+ if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
+ strncat(string, "C", 1);
+
+ if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
+ strncat(string, "m", 1);
+
+ if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
+ strncat(string, "M", 1);
+
+ if (mode & SILC_CHANNEL_MODE_CIPHER)
+ strncat(string, "c", 1);
+
+ if (mode & SILC_CHANNEL_MODE_HMAC)
+ strncat(string, "h", 1);
+
+ if (mode & SILC_CHANNEL_MODE_CIPHER) {
+ if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
+ strncat(string, " ", 1);
+ strncat(string, cipher, strlen(cipher));
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_HMAC) {
+ if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
+ strncat(string, " ", 1);
+ strncat(string, hmac, strlen(hmac));
+ }
+ }
+
+ /* Rest of mode is ignored */
+
+ return strdup(string);
+}
+
+/* Parses channel user mode mask and returns te mode as string */
+
+char *silc_client_chumode(SilcUInt32 mode)
+{
+ char string[64];
+
+ if (!mode)
+ return NULL;
+
+ memset(string, 0, sizeof(string));
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO)
+ strncat(string, "f", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_CHANOP)
+ strncat(string, "o", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
+ strncat(string, "b", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
+ strncat(string, "u", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
+ strncat(string, "r", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_QUIET)
+ strncat(string, "q", 1);
+
+ return strdup(string);
+}
+
+/* Parses channel user mode and returns it as special mode character. */
+
+char *silc_client_chumode_char(SilcUInt32 mode)
+{
+ char string[64];
+
+ if (!mode)
+ return NULL;
+
+ memset(string, 0, sizeof(string));
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO)
+ strncat(string, "*", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_CHANOP)
+ strncat(string, "@", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_QUIET)
+ strncat(string, "&", 1);
+
+ return strdup(string);
+}
+
/* Creates fingerprint from data, usually used with SHA1 digests */
char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
memset(fingerprint, 0, sizeof(fingerprint));
cp = fingerprint;
for (i = 0; i < data_len; i++) {
- silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
+ snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
cp += 2;
if ((i + 1) % 2 == 0)
- silc_snprintf(cp++, sizeof(fingerprint), " ");
+ snprintf(cp++, sizeof(fingerprint), " ");
if ((i + 1) % 10 == 0)
- silc_snprintf(cp++, sizeof(fingerprint), " ");
+ snprintf(cp++, sizeof(fingerprint), " ");
}
i--;
if ((i + 1) % 2 == 0)
/* Return TRUE if the `data' is ASCII string. */
-SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
+bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
{
int i;
return TRUE;
}
+/* Parses SILC protocol style version string. */
+
+bool silc_parse_version_string(const char *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;
+
+ if (!strstr(version, "SILC-"))
+ return FALSE;
+
+ cp = (char *)version + 5;
+ if (!cp)
+ return FALSE;
+
+ /* Take protocol version */
+
+ maj = atoi(cp);
+ if (!strchr(cp, '.'))
+ return FALSE;
+ cp = strchr(cp, '.') + 1;
+ if (!cp || !(*cp))
+ return FALSE;
+ min = atoi(cp);
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+ if (protocol_version)
+ *protocol_version = atoi(buf);
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
+ if (protocol_version_string)
+ *protocol_version_string = strdup(buf);
+
+ /* Take software version */
+
+ maj = 0;
+ min = 0;
+ if (!strchr(cp, '-'))
+ return FALSE;
+ cp = strchr(cp, '-') + 1;
+ if (!cp || !(*cp))
+ return FALSE;
+
+ maj = atoi(cp);
+ if (strchr(cp, '.')) {
+ cp = strchr(cp, '.') + 1;
+ if (cp && *cp)
+ min = atoi(cp);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+ if (software_version)
+ *software_version = atoi(buf);
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
+ if (software_version_string)
+ *software_version_string = strdup(buf);
+
+ /* Take vendor string */
+
+ if (strchr(cp, '.')) {
+ cp = strchr(cp, '.') + 1;
+ if (cp && *cp && vendor_version)
+ *vendor_version = strdup(cp);
+ }
+
+ return TRUE;
+}
+
+/* Converts version string x.x into number representation. */
+
+SilcUInt32 silc_version_to_num(const char *version)
+{
+ int maj = 0, min = 0;
+ char *cp, buf[32];
+
+ if (!version)
+ return 0;
+
+ cp = (char *)version;
+ maj = atoi(cp);
+ cp = strchr(cp, '.');
+ if (cp)
+ min = atoi(cp + 1);
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
+ return (SilcUInt32)atoi(buf);
+}
+
/* Displays input prompt on command line and takes input data from user */
-char *silc_get_input(const char *prompt, SilcBool echo_off)
+char *silc_get_input(const char *prompt, bool echo_off)
{
#ifdef SILC_UNIX
int fd;
return NULL;
#endif /* SILC_UNIX */
}
+
+/* Return mode list */
+
+bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ SilcUInt32 **list)
+{
+ int i;
+
+ if (mode_list->len / 4 != mode_list_count)
+ return FALSE;
+
+ *list = silc_calloc(mode_list_count, sizeof(**list));
+
+ for (i = 0; i < mode_list_count; i++) {
+ SILC_GET32_MSB((*list)[i], mode_list->data);
+ silc_buffer_pull(mode_list, 4);
+ }
+
+ silc_buffer_push(mode_list, mode_list->data - mode_list->head);
+
+ return TRUE;
+}
+
+/* Status message structure. Messages are defined below. */
+typedef struct {
+ SilcStatus status;
+ const char *message;
+} SilcStatusMessage;
+
+#define STAT(x) SILC_STATUS_ERR_##x
+static const SilcStatusMessage silc_status_messages[] = {
+
+ { STAT(NO_SUCH_NICK), "There was no such nickname" },
+ { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
+ { STAT(NO_SUCH_SERVER), "There was no such server" },
+ { STAT(INCOMPLETE_INFORMATION), "Incomplete registration information" },
+ { STAT(NO_RECIPIENT), "No recipient given" },
+ { STAT(UNKNOWN_COMMAND), "Unknown command" },
+ { STAT(WILDCARDS), "Wilcrads not allowed" },
+ { STAT(NO_CLIENT_ID), "No Client ID given" },
+ { STAT(NO_CHANNEL_ID), "No Channel ID given" },
+ { STAT(NO_SERVER_ID), "No Server ID given" },
+ { STAT(BAD_CLIENT_ID), "Bad Client ID" },
+ { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
+ { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
+ { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
+ { STAT(NICKNAME_IN_USE), "Nickname already exists" },
+ { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
+ { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
+ { STAT(USER_ON_CHANNEL), "User already on the channel" },
+ { STAT(NOT_REGISTERED), "You have not registered" },
+ { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
+ { STAT(TOO_MANY_PARAMS), "Too many parameters" },
+ { STAT(PERM_DENIED), "Permission denied" },
+ { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
+ { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
+ { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
+ { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
+ { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
+ { STAT(UNKNOWN_MODE), "Unknown mode" },
+ { STAT(NOT_YOU), "Cannot change mode for other users" },
+ { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
+ { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
+ { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
+ { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
+ { STAT(BAD_NICKNAME), "Bad nickname" },
+ { STAT(BAD_CHANNEL), "Bad channel name" },
+ { STAT(AUTH_FAILED), "Authentication failed" },
+ { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
+ { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
+ { STAT(RESOURCE_LIMIT), "No more free resources" },
+ { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
+ { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
+ { STAT(BAD_SERVER_ID), "Server ID is not valid" },
+ { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
+ { STAT(BAD_VERSION), "Bad version" },
+ { STAT(TIMEDOUT), "Service timed out" },
+ { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" },
+ { STAT(OPERATION_ALLOWED), "Operation is not allowed" },
+ { STAT(BAD_SERVER), "Bad server name" },
+ { STAT(BAD_USERNAME), "Bad user name" },
+
+ { 0, NULL }
+};
+
+/* Returns status message string */
+
+const char *silc_get_status_message(unsigned char status)
+{
+ int i;
+
+ for (i = 0; silc_status_messages[i].message; i++) {
+ if (silc_status_messages[i].status == status)
+ break;
+ }
+
+ if (silc_status_messages[i].message == NULL)
+ return "";
+
+ return silc_status_messages[i].message;
+}
+
+static const char *packet_name[] = {
+ "NONE",
+ "DISCONNECT",
+ "SUCCESS",
+ "FAILURE",
+ "REJECT",
+ "NOTIFY",
+ "ERROR",
+ "CHANNEL MESSAGE",
+ "CHANNEL KEY",
+ "PRIVATE MESSAGE",
+ "PRIVATE MESSAGE KEY",
+ "COMMAND",
+ "COMMAND REPLY",
+ "KEY EXCHANGE",
+ "KEY EXCHANGE 1",
+ "KEY EXCHANGE 2",
+ "CONNECTION AUTH REQUEST",
+ "CONNECTION AUTH",
+ "NEW ID",
+ "NEW CLIENT",
+ "NEW SERVER",
+ "NEW CHANNEL",
+ "REKEY",
+ "REKEY_DONE",
+ "HEARTBEAT",
+ "KEY AGREEMENT",
+ "RESUME ROUTER",
+ "FTP",
+ "RESUME CLIENT",
+};
+
+/* Returns packet type name */
+
+const char *silc_get_packet_name(unsigned char type)
+{
+ if (type >= SILC_PACKET_MAX)
+ return "RESERVED";
+ if (type >= SILC_PACKET_PRIVATE)
+ return "PRIVATE RANGE";
+ if (type > (sizeof(packet_name) / sizeof(*packet_name)))
+ return "UNKNOWN";
+ return packet_name[type];
+}
+
+static const char *command_name[] = {
+ "NONE",
+ "WHOIS",
+ "WHOWAS",
+ "IDENTIFY",
+ "NICK",
+ "LIST",
+ "TOPIC",
+ "INVITE",
+ "QUIT",
+ "KILL",
+ "INFO",
+ "STATS",
+ "PING",
+ "OPER",
+ "JOIN",
+ "MOTD",
+ "UMODE",
+ "CMODE",
+ "CUMODE",
+ "KICK",
+ "BAN",
+ "DETACH",
+ "WATCH",
+ "SILCOPER",
+ "LEAVE",
+ "USERS",
+ "GETKEY",
+ "SERVICE",
+};
+
+/* Returns command name */
+
+const char *silc_get_command_name(unsigned char command)
+{
+ if (command >= SILC_COMMAND_RESERVED)
+ return "RESERVED";
+ if (command >= SILC_COMMAND_PRIVATE)
+ return "PRIVATE RANGE";
+ if (command > (sizeof(command_name) / sizeof(*command_name)))
+ return "UNKNOWN";
+ return command_name[command];
+}
+
+/* Return TRUE if `smaller' is smaller than `bigger'. */
+
+bool silc_compare_timeval(struct timeval *smaller,
+ struct timeval *bigger)
+{
+ if ((smaller->tv_sec < bigger->tv_sec) ||
+ ((smaller->tv_sec == bigger->tv_sec) &&
+ (smaller->tv_usec < bigger->tv_usec)))
+ return TRUE;
+
+ return FALSE;
+}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
***/
int silc_check_line(char *buf);
+/****f* silcutil/SilcUtilAPI/silc_get_time
+ *
+ * SYNOPSIS
+ *
+ * const char *silc_get_time(SilcUInt32 timeval)
+ *
+ * DESCRIPTION
+ *
+ * Returns time as string. If the the `timeval' is non-zero that
+ * value is returned as string. If it is zero the current time of the
+ * local machine is returned.
+ *
+ ***/
+const char *silc_get_time(SilcUInt32 timeval);
+
/****f* silcutil/SilcUtilAPI/silc_to_upper
*
* SYNOPSIS
*
- * SilcBool silc_to_upper(const char *string, char *dest,
- * SilcUInt32 dest_size);
+ * bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size);
*
* DESCRIPTION
*
* Converts string to capital characters.
*
***/
-SilcBool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size);
+bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size);
/****f* silcutil/SilcUtilAPI/silc_to_lower
*
* SYNOPSIS
*
- * SilcBool silc_to_lower(const char *string, char *dest,
- * SilcUInt32 dest_size);
+ * bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size);
*
* DESCRIPTION
*
* Converts string to capital characters.
*
***/
-SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size);
+bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size);
/****f* silcutil/SilcUtilAPI/silc_parse_userfqdn
*
* SYNOPSIS
*
- * int silc_parse_userfqdn(const char *string,
- * char *user, SilcUInt32 user_size,
- * char *fqdn, SilcUInt32 fqdn_size);
+ * bool silc_parse_userfqdn(const char *string, char **left, char **right);
*
* DESCRIPTION
*
- * 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.
+ * Parse userfqdn string which is in user@fqdn format.
*
***/
-int silc_parse_userfqdn(const char *string,
- char *user, SilcUInt32 user_size,
- char *fqdn, SilcUInt32 fqdn_size);
+bool silc_parse_userfqdn(const char *string, char **left, char **right);
/****f* silcutil/SilcUtilAPI/silc_parse_command_line
*
***/
char *silc_format(char *fmt, ...);
+/****f* silcutil/SilcUtilAPI/silc_id_render
+ *
+ * SYNOPSIS
+ *
+ * char *silc_id_render(void *id, SilcUInt16 type);
+ *
+ * DESCRIPTION
+ *
+ * Renders ID to suitable to print for example to log file.
+ *
+ ***/
+char *silc_id_render(void *id, SilcUInt16 type);
+
+/****f* silcutil/SilcUtilAPI/silc_string_compare
+ *
+ * SYNOPSIS
+ *
+ * int silc_string_compare(char *string1, char *string2);
+ *
+ * DESCRIPTION
+ *
+ * Compares two strings. Strings may include wildcards '*' and '?'.
+ * Returns TRUE if strings match.
+ *
+ ***/
+int silc_string_compare(char *string1, char *string2);
+
/****f* silcutil/SilcUtilAPI/silc_hash_string
*
* SYNOPSIS
*
* DESCRIPTION
*
- * Hash public key of any type.
+ * Hashed SILC Public key.
*
***/
SilcUInt32 silc_hash_public_key(void *key, void *user_context);
*
* SYNOPSIS
*
- * SilcBool silc_hash_string_compare(void *key1, void *key2,
+ * bool silc_hash_string_compare(void *key1, void *key2,
* void *user_context);
*
* DESCRIPTION
* function.
*
***/
-SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context);
+bool silc_hash_string_compare(void *key1, void *key2, void *user_context);
/****f* silcutil/SilcUtilAPI/silc_hash_id_compare
*
* SYNOPSIS
*
- * SilcBool silc_hash_id_compare(void *key1, void *key2,
- * void *user_context);
+ * bool silc_hash_id_compare(void *key1, void *key2, void *user_context);
*
* DESCRIPTION
*
* part of the Client ID. Other ID's are fully compared.
*
***/
-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);
+bool silc_hash_id_compare(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);
+ * bool 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);
+bool 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);
+ * bool silc_hash_data_compare(void *key1, void *key2, void *user_context);
*
* DESCRIPTION
*
* Compares binary data. May be used as SilcHashTable comparison function.
*
***/
-SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context);
+bool silc_hash_data_compare(void *key1, void *key2, void *user_context);
/****f* silcutil/SilcUtilAPI/silc_hash_utf8_compare
*
* SYNOPSIS
*
- * SilcBool silc_hash_utf8_compare(void *key1, void *key2,
- * void *user_context);
+ * bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context);
*
* DESCRIPTION
*
* expected. May be used as SilcHashTable comparison function.
*
***/
-SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context);
+bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context);
/****f* silcutil/SilcUtilAPI/silc_hash_public_key_compare
*
* SYNOPSIS
*
- * SilcBool silc_hash_public_key_compare(void *key1, void *key2,
- * void *user_context);
+ * bool silc_hash_public_key_compare(void *key1, void *key2,
+ * void *user_context);
*
* DESCRIPTION
*
* comparison function.
*
***/
-SilcBool silc_hash_public_key_compare(void *key1, void *key2,
- void *user_context);
+bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context);
+
+/****f* silcutil/SilcUtilAPI/silc_client_chmode
+ *
+ * SYNOPSIS
+ *
+ * char *silc_client_chmode(SilcUInt32 mode, const char *cipher,
+ * const char *hmac);
+ *
+ * DESCRIPTION
+ *
+ * Parses mode mask and returns the mode as string.
+ *
+ ***/
+char *silc_client_chmode(SilcUInt32 mode, const char *cipher,
+ const char *hmac);
+
+/****f* silcutil/SilcUtilAPI/silc_client_chumode
+ *
+ * SYNOPSIS
+ *
+ * char *silc_client_chumode(SilcUInt32 mode);
+ *
+ * DESCRIPTION
+ *
+ * Parses channel user mode mask and returns te mode as string.
+ *
+ ***/
+char *silc_client_chumode(SilcUInt32 mode);
+
+/****f* silcutil/SilcUtilAPI/silc_client_chumode_char
+ *
+ * SYNOPSIS
+ *
+ * char *silc_client_chumode_char(SilcUInt32 mode);
+ *
+ * DESCRIPTION
+ *
+ * Parses channel user mode and returns it as special mode character.
+ *
+ ***/
+char *silc_client_chumode_char(SilcUInt32 mode);
/****f* silcutil/SilcUtilAPI/silc_fingerprint
*
*
* SYNOPSIS
*
- * SilcBool silc_string_is_ascii(const unsigned char *data,
+ * bool silc_string_is_ascii(const unsigned char *data,
* SilcUInt32 data_len);
*
* DESCRIPTION
* Return TRUE if the `data' is ASCII string.
*
***/
-SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len);
+bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len);
+
+/****f* silcutil/SilcUtilAPI/silc_parse_version_string
+ *
+ * SYNOPSIS
+ *
+ * bool silc_parse_version_string(const char *version,
+ * SilcUInt32 *protocol_version,
+ * char **protocol_version_string,
+ * SilcUInt32 *software_version,
+ * char **software_version_string,
+ * char **vendor_version);
+ *
+ * DESCRIPTION
+ *
+ * Parses SILC protocol style version string.
+ *
+ ***/
+bool silc_parse_version_string(const char *version,
+ SilcUInt32 *protocol_version,
+ char **protocol_version_string,
+ SilcUInt32 *software_version,
+ char **software_version_string,
+ char **vendor_version);
+
+/****f* silcutil/SilcUtilAPI/silc_version_to_num
+ *
+ * SYNOPSIS
+ *
+ * SilcUInt32 silc_version_to_num(const char *version);
+ *
+ * DESCRIPTION
+ *
+ * Converts version string x.x into number representation.
+ *
+ ***/
+SilcUInt32 silc_version_to_num(const char *version);
/****f* silcutil/SilcUtilAPI/silc_get_input
*
* SYNOPSIS
*
- * char *silc_get_input(const char *prompt, SilcBool echo_off);
+ * char *silc_get_input(const char *prompt, bool echo_off);
*
* DESCRIPTION
*
* Displays input prompt on command line and takes input data from user.
*
***/
-char *silc_get_input(const char *prompt, SilcBool echo_off);
+char *silc_get_input(const char *prompt, bool echo_off);
/* System dependant prototypes */
+/****f* silcutil/SilcUtilAPI/silc_gettimeofday
+ *
+ * SYNOPSIS
+ *
+ * int silc_gettimeofday(struct timeval *p);
+ *
+ * DESCRIPTION
+ *
+ * Return current time to struct timeval. This function is system
+ * dependant. Returns 0 on success and -1 on error.
+ *
+ ***/
+int silc_gettimeofday(struct timeval *p);
+
+/****f* silcutil/SilcUtilAPI/silc_compare_timeval
+ *
+ * SYNOPSIS
+ *
+ * bool silc_compare_timeval(struct timeval *smaller,
+ * struct timeval *bigger)
+ *
+ * DESCRIPTION
+ *
+ * Compare two timeval structures and return TRUE if the first
+ * time value is smaller than the second time value.
+ *
+ ***/
+bool silc_compare_timeval(struct timeval *smaller,
+ struct timeval *bigger);
+
+/****f* silcutil/SilcUtilAPI/silc_string_regexify
+ *
+ * SYNOPSIS
+ *
+ * char *silc_string_regexify(const char *string);
+ *
+ * DESCRIPTION
+ *
+ * Inspects the `string' for wildcards and returns regex string that can
+ * be used by the GNU regex library. A comma (`,') in the `string' means
+ * that the string is list.
+ *
+ * This function is system dependant.
+ *
+ ***/
+char *silc_string_regexify(const char *string);
+
+/****f* silcutil/SilcUtilAPI/silc_string_regex_match
+ *
+ * SYNOPSIS
+ *
+ * int silc_string_regex_match(const char *regex, const char *string);
+ *
+ * DESCRIPTION
+ *
+ * Matches the two strings and returns TRUE if the strings match.
+ *
+ * This function is system dependant.
+ *
+ ***/
+int silc_string_regex_match(const char *regex, const char *string);
+
+/****f* silcutil/SilcUtilAPI/silc_string_match
+ *
+ * SYNOPSIS
+ *
+ * int silc_string_match(const char *string1, const char *string2);
+ *
+ * DESCRIPTION
+ *
+ * Do regex match to the two strings `string1' and `string2'. If the
+ * `string2' matches the `string1' this returns TRUE.
+ *
+ * This function is system dependant.
+ *
+ ***/
+int silc_string_match(const char *string1, const char *string2);
+
/****f* silcutil/SilcUtilAPI/silc_get_username
*
* SYNOPSIS
***/
char *silc_get_real_name();
-/****f* silcutil/SilcUtilAPI/silc_va_copy
+/****f* silcutil/SilcUtilAPI/silc_get_mode_list
+ *
+ * SYNOPSIS
+ *
+ * bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ * SilcUInt32 **list);
+ *
+ * DESCRIPTION
+ *
+ * Returns modes from list of 32 bit MSB first order values that are
+ * encoded one after the other in the `mode_list' into the `list'
+ * array. The caller must free the returned list. Return FALSE if
+ * there is error parsing the list.
+ *
+ ***/
+bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ SilcUInt32 **list);
+
+/****f* silcutil/SilcUtilAPI/silc_get_status_message
+ *
+ * SYNOPSIS
+ *
+ * char *silc_get_status_message(SilcStatus status)
+ *
+ * DESCRIPTION
+ *
+ * Returns status message string
+ *
+ ***/
+const char *silc_get_status_message(unsigned char status);
+
+/****f* silcutil/SilcUtilAPI/silc_get_packet_name
+ *
+ * SYNOPSIS
+ *
+ * char *silc_get_packet_name(SilcPacketType type);
+ *
+ * DESCRIPTION
+ *
+ * Returns the name corresponding packet type `type'.
+ *
+ ***/
+const char *silc_get_packet_name(unsigned char type);
+
+/****f* silcutil/SilcUtilAPI/silc_get_command_name
*
* SYNOPSIS
*
- * void silc_va_copy(va_list dest, va_list src);
+ * char *silc_get_command_name(SilcCommand command);
*
* DESCRIPTION
*
- * Copies variable argument list. This must be called in case the
- * variable argument list must be evaluated multiple times. For each
- * evaluation the list must be copied and va_end must be called for
- * each copied list.
+ * Returns the name corresponding SILC command `command'.
*
***/
-#if defined(HAVE_VA_COPY)
-#define silc_va_copy(dest, src) va_copy(dest, src);
-#elif defined(HAVE___VA_COPY)
-#define silc_va_copy(dest, src) __va_copy(dest, src);
-#elif defined(SILC_VA_COPY_ARRAY)
-#define silc_va_copy(dest, src) memmove(dest, src, sizeof(va_list));
-#else
-#define silc_va_copy(dest, src) dest = src;
-#endif
+const char *silc_get_command_name(unsigned char command);
#endif /* !SILCUTIL_H */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 - 2005 Pekka Riikonen
+ Copyright (C) 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
/* $Id$ */
/* Implementation of the VCard (RFC 2426) */
-#include "silc.h"
+#include "silcincludes.h"
#define VCARD_HEADER "BEGIN:VCARD\n"
#define VCARD_VERSION "VERSION:3.0\n"
silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STRFMT_END);
if (vcard_len)
- *vcard_len = silc_buffer_truelen(&buffer);
+ *vcard_len = buffer.truelen;
return buffer.head;
}
/* Decode VCard */
-SilcBool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
+bool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
SilcVCard vcard)
{
unsigned char *val;
- SilcBool has_begin = FALSE, has_end = FALSE;
+ bool has_begin = FALSE, has_end = FALSE;
int len, i, off = 0;
val = (unsigned char *)data;
*/
-/****h* silcvcard/SILC VCard
+/****h* silcutil/SILC VCard
*
* DESCRIPTION
*
#ifndef SILCVCARD_H
#define SILCVCARD_H
-/****s* silcvcard/SilcVCard/SilcVCard
+/****s* silcutil/SilcVCard/SilcVCard
*
* NAME
*
char *note; /* a note, string */
char *rev; /* revision of card, UTC date string */
- SilcBool dynamic; /* TRUE when dynamically allocated */
+ bool dynamic; /* TRUE when dynamically allocated */
} SilcVCardStruct, *SilcVCard;
/***/
-/****f* silcvcard/SilcVCard/silc_vcard_encode
+/****f* silcutil/SilcVCard/silc_vcard_encode
*
* SYNOPSIS
*
***/
unsigned char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len);
-/****f* silcvcard/SilcVCard/silc_vcard_decode
+/****f* silcutil/SilcVCard/silc_vcard_decode
*
* SYNOPSIS
*
- * SilcBool silc_vcard_decode(const unsigned char *data,
- * SilcUInt32 data_len, SilcVCard vcard);
+ * bool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
+ * SilcVCard vcard);
*
* DESCRIPTION
*
* is freed with silc_vcard_free function when it is not needed anymore.
*
***/
-SilcBool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
- SilcVCard vcard);
+bool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
+ SilcVCard vcard);
-/****f* silcvcard/SilcVCard/silc_vcard_alloc
+/****f* silcutil/SilcVCard/silc_vcard_alloc
*
* SYNOPSIS
*
***/
SilcVCard silc_vcard_alloc(void);
-/****f* silcvcard/SilcVCard/silc_vcard_free
+/****f* silcutil/SilcVCard/silc_vcard_free
*
* SYNOPSIS
*
***/
void silc_vcard_free(SilcVCard vcard);
-/****f* silcvcard/SilcVCard/silc_vcard_fprintf
+/****f* silcutil/SilcVCard/silc_vcard_fprintf
*
* SYNOPSIS
*
/*
- stacktrace.c
+ stacktrace.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002, 2007 Pekka Riikonen
+ Copyright (C) 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
*/
-#include "silc.h"
+#include "silcincludes.h"
#ifdef SILC_STACKTRACE
static void *st_blocks = NULL;
static unsigned long st_blocks_count = 0;
-static SilcBool dump = FALSE;
-static SilcBool malloc_check = FALSE;
+static bool dump = FALSE;
+static bool malloc_check = FALSE;
-#ifdef SILC_DEBUG
-#define SILC_ST_DEPTH 15
-#else
-#define SILC_ST_DEPTH 8
-#endif /* SILC_DEBUG */
+#define SILC_ST_DEPTH 10
/* Memory block with stack trace */
typedef struct SilcStBlockStruct {
for (s = stack; s; s = s->next) {
if (s->file == stack->file && s->line == stack->line &&
s->depth == stack->depth &&
- !memcmp(s->stack, stack->stack,
+ !memcmp(s->stack, stack->stack,
(s->depth * sizeof(stack->stack[0])))) {
blocks++;
bytes += s->size;
fprintf(fp, "<stacktrace>%s:%d: #blocks=%lu, bytes=%lu\n",
stack->file, stack->line, blocks, bytes);
for (i = 0; i < stack->depth; i++)
- fprintf(fp, "\tpc=%p\n", stack->stack[i]);
+ fprintf(fp, "<pc>%p\n", stack->stack[i]);
}
}
if (!leaks) {
fprintf(stderr, "\nNo memory leaks\n");
} else {
- fprintf(stderr,
+ fprintf(stderr,
"-----------------------------------------\n"
"-----------------------------------------\n"
" Memory leaks dumped to 'stacktrace.log'\n"
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2007 Pekka Riikonen
+# Copyright (C) 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
--- /dev/null
+/*
+
+ silcepocsockconn.cpp
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 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.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.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.
+ The data is written from the data section of the buffer, not from head
+ or tail section. This automatically pulls the data section towards end
+ after writing the data. */
+
+int silc_socket_write(SilcSocketConnection sock)
+{
+ /* XXX */
+}
+
+/* Reads data from the socket connection into the incoming data buffer.
+ It reads as much as possible from the socket connection. This returns
+ amount of bytes read or -1 on error or -2 on case where all of the
+ data could not be read at once. */
+
+int silc_socket_read(SilcSocketConnection sock)
+{
+ /* XXX */
+}
+
+/* Returns human readable socket error message. These are copied from the
+ PuTTY. */
+
+#define PUT_ERROR(s)
+do {
+ if (strlen(s) > err_len)
+ return FALSE;
+ memset(error, 0, error_len);
+ memcpy(error, s, strlen(s));
+ return TRUE;
+} while(0)
+
+bool silc_socket_get_error(SilcSocketConnection sock, char *error,
+ SilcUInt32 error_len)
+{
+ if (sock->sock_error == KErrNone)
+ return FALSE;
+
+ switch (sock->sock_error) {
+ case KErrNotFound:
+ PUT_ERROR("Item not found. (NotFound)");
+ case KErrGeneral:
+ PUT_ERROR("Uncategorized error. (General)");
+ case KErrCancel:
+ PUT_ERROR("Operation cancelled. (Cancel)");
+ case KErrNoMemory:
+ PUT_ERROR("A memory allocation failed. (NoMemory)");
+ case KErrNotSupported:
+ PUT_ERROR("A function is not supported in a given context. "
+ "(NotSupported)");
+ case KErrArgument:
+ PUT_ERROR("An argument is out of range. (Argument)");
+ case KErrBadHandle:
+ PUT_ERROR("Bad handle. (BadHandle)");
+ case KErrOverflow:
+ PUT_ERROR("Overflow. (Overflow)");
+ case KErrUnderflow:
+ PUT_ERROR("Underflow. (Underflow)");
+ case KErrAlreadyExists:
+ PUT_ERROR("The resource already exists. (AlreadyExists)");
+ case KErrPathNotFound:
+ PUT_ERROR("In the context of file operations, the path was "
+ "not found. (PathNotFound)");
+ case KErrDied:
+ PUT_ERROR("A handle refers to a thread which has died (Died)");
+ case KErrInUse:
+ PUT_ERROR("A requested resource is already in use. (InUse)");
+ case KErrServerTerminated:
+ PUT_ERROR("A client/server operation cannot execute, because the "
+ "server has terminated. (ServerTerminated)");
+ case KErrServerBusy:
+ PUT_ERROR("A client/server operation cannot execute, because the server "
+ "is busy. (ServerBusy)");
+ case KErrNotReady:
+ PUT_ERROR("Resource not ready. Not initialized, or has no power. "
+ "(NotReady)");
+ case KErrUnknown:
+ PUT_ERROR("A device is of unknown type. (Unknown)");
+ case KErrCorrupt:
+ PUT_ERROR("Corrupted. (Corrupt)");
+ case KErrAccessDenied:
+ PUT_ERROR("Access denied. (AccessDenied)");
+ case KErrLocked:
+ PUT_ERROR("The operation cannot be performed, because the resource "
+ "is locked. (Locked)");
+ case KErrWrite:
+ PUT_ERROR("During a file write operation, not all the data could "
+ "be written. (Write)");
+ case KErrDisMounted:
+ PUT_ERROR("A volume which was to be used for a file system operation "
+ "has been dismounted. (DisMounted)");
+ case KErrEof:
+ PUT_ERROR("End of file has been reached. (Eof)");
+ case KErrDiskFull:
+ PUT_ERROR("A write operation could not complete, because the disk "
+ "was full. (DiskFull)");
+ case KErrBadDriver:
+ PUT_ERROR("A driver DLL was of the wrong type. (BadDriver)");
+ case KErrBadName:
+ PUT_ERROR("Name did not conform with the required syntax. (BadName)");
+ case KErrCommsLineFail:
+ PUT_ERROR("The communication line failed. (CommsLineFail)");
+ case KErrCommsFrame:
+ PUT_ERROR("A frame error occurred in a communications operation. "
+ "(CommsFrame)");
+ case KErrCommsOverrun:
+ PUT_ERROR("An overrun was detected by a communications driver. "
+ "(CommsOverrun)");
+ case KErrCommsParity:
+ PUT_ERROR("A parity error occurred in communications. (CommsParity)");
+ case KErrTimedOut:
+ PUT_ERROR("An operation timed out. (TimedOut)");
+ case KErrCouldNotConnect:
+ PUT_ERROR("A session could not connect. (CouldNotConnect)");
+ case KErrCouldNotDisconnect:
+ PUT_ERROR("A session could not disconnect. (CouldNotDisconnect)");
+ case KErrDisconnected:
+ PUT_ERROR("The required session was disconnected. (Disconnected)");
+ case KErrBadLibraryEntryPoint:
+ PUT_ERROR("A library entry point was not of the required type. "
+ "(BadLibraryEntryPoint)");
+ case KErrBadDescriptor:
+ PUT_ERROR("A non-descriptor parameter was passed. (BadDescriptor)");
+ case KErrAbort:
+ PUT_ERROR("An operation was aborted (Abort)");
+ case KErrTooBig:
+ PUT_ERROR("A number was too big (TooBig)");
+ case KErrDivideByZero:
+ PUT_ERROR("A divide-by-zero operation was attempted. (DivideByZero)");
+ case KErrBadPower:
+ PUT_ERROR("Insufficient power was available to complete an operation. "
+ "(BadPower)");
+ case KErrWouldBlock:
+ PUT_ERROR("Network error: Resource temporarily unavailable (WouldBlock)");
+ case KErrNetUnreach:
+ PUT_ERROR("Network unreachable. (NetUnreach)");
+ case KErrHostUnreach:
+ PUT_ERROR("Host unreachable. (HostUnreach)");
+ case KErrNoProtocolOpt:
+ PUT_ERROR("No such protocol option. (NoProtocolOpt)");
+ case KErrUrgentData:
+ PUT_ERROR("Urgent data arrived. (UrgentData)");
+ case KInvalSocket:
+ PUT_ERROR("Got NULL sokcet.");
+ }
+
+ return FALSE;
+}
--- /dev/null
+/*
+
+ silcepocthread.cpp
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 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.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+
+#ifdef SILC_THREADS
+
+/* Thread structure for EPOC */
+typedef struct {
+ RThread *thread;
+ SilcThreadStart start_func;
+ void *context;
+ bool waitable;
+} *SilcEpocThread;
+
+/* The actual thread function */
+
+TInt silc_thread_epoc_start(TAny *context)
+{
+ SilcEpocThread thread = (SilcEpocThread)context;
+
+ thread->start_func(thread->context);
+ silc_thread_exit(NULL);
+
+ return 0;
+}
+
+SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
+ bool waitable)
+{
+#ifdef SILC_THREADS
+ SilcEpocThread thread;
+ TInt ret;
+
+ SILC_LOG_DEBUG(("Creating new thread"));
+
+ thread = silc_calloc(1, sizeof(*thread));
+ thread->start_func = start_func;
+ thread->context = context;
+ thread->waitable = waitable;
+
+ /* Create the thread */
+ /* XXX Unique name should be given for the thread */
+ thread->thread = new RThread();
+ ret = thread->thread->Create(NULL, silc_thread_epoc_start, 0, 0, 0,
+ (TAny *)thread, EOwnerProcess);
+ if (ret != KErrNone) {
+ SILC_LOG_ERROR(("Could not create new thread"));
+ delete thread->thread;
+ silc_free(thread);
+ return NULL;
+ }
+
+ return (SilcThread)thread;
+#else
+ /* Call thread callback immediately */
+ (*start_func)(context);
+ return NULL;
+#endif
+}
+
+void silc_thread_exit(void *exit_value)
+{
+#ifdef SILC_THREADS
+ /* XXX */
+#endif
+}
+
+SilcThread silc_thread_self(void)
+{
+#ifdef SILC_THREADS
+ /* XXX */
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+bool silc_thread_wait(SilcThread thread, void **exit_value)
+{
+#ifdef SILC_THREADS
+ /* XXX */
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
--- /dev/null
+/*
+
+ silcepocutil.cpp
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 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.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+
+/* XXX TODO or use GNU regex if it compiles */
+char *silc_string_regexify(const char *string)
+{
+ return strdup(string);
+}
+
+char *silc_string_regex_combine(const char *string1, const char *string2)
+{
+ return strdup(string1);
+}
+
+int silc_string_regex_match(const char *regex, const char *string)
+{
+ return TRUE;
+}
+
+int silc_string_match(const char *string1, const char *string2)
+{
+ return TRUE;
+}
+
+/* Return current time to struct timeval. */
+
+int silc_gettimeofday(struct timeval *p)
+{
+ return gettimeofday(p, NULL);
+}
+++ /dev/null
-/*
-
- silcsymbiannet.cpp
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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 "silcsymbiansocketstream.h"
-
-/****************************** TCP Listener ********************************/
-
-class SilcSymbianTCPListener;
-
-/* Deliver new stream to upper layer */
-
-static void silc_net_accept_stream(SilcSocketStreamStatus status,
- SilcStream stream, void *context)
-{
- SilcNetListener listener = (SilcNetListener)context;
-
- /* In case of error, the socket has been destroyed already */
- if (status != SILC_SOCKET_OK)
- return;
-
- listener->callback(SILC_NET_OK, stream, listener->context);
-}
-
-/* TCP Listener class */
-
-class SilcSymbianTCPListener : public CActive {
-public:
- /* Constructor */
- SilcSymbianTCPListener() : CActive(CActive::EPriorityStandard)
- {
- CActiveScheduler::Add(this);
- }
-
- /* Destructor */
- ~SilcSymbianTCPListener()
- {
- Cancel();
- }
-
- /* Listen for connection */
- void Listen()
- {
- new_conn = new RSocket;
- if (!new_conn)
- return;
- if (new_conn->Open(ss) != KErrNone) {
- Listen();
- return;
- }
-
- /* Start listenning */
- sock.Accept(*new_conn, iStatus);
- SetActive();
- }
-
- /* Listener callback */
- virtual void RunL()
- {
- if (iStatus != KErrNone) {
- if (new_conn)
- delete new_conn;
- new_conn = NULL;
- Listen();
- return;
- }
-
- /* Set socket options */
- new_conn->SetOpt(KSoReuseAddr, KSolInetIp, 1);
-
- /* Create socket stream */
- silc_socket_tcp_stream_create(
- (SilcSocket)silc_create_symbian_socket(new_conn, NULL),
- listener->lookup, listener->require_fqdn,
- listener->schedule, silc_net_accept_stream,
- (void *)listener);
- new_conn = NULL;
-
- /* Continue listenning */
- Listen();
- }
-
- /* Cancel */
- virtual void DoCancel()
- {
- sock.CancelAll();
- ss.Close();
- if (new_conn)
- delete new_conn;
- }
-
- RSocket *new_conn;
- RSocket sock;
- RSocketServ ss;
- SilcNetListener listener;
-};
-
-/* Create TCP listener */
-
-SilcNetListener
-silc_net_tcp_create_listener(const char **local_ip_addr,
- SilcUInt32 local_ip_count, int port,
- SilcBool lookup, SilcBool require_fqdn,
- SilcSchedule schedule,
- SilcNetCallback callback, void *context)
-{
- SilcNetListener listener = NULL;
- SilcSymbianTCPListener *l = NULL;
- TInetAddr server;
- TInt ret;
- TBuf<64> tmp;
- int i;
-
- SILC_LOG_DEBUG(("Creating TCP listener"));
-
- if (port < 0 || !schedule || !callback)
- goto err;
-
- listener = (SilcNetListener)silc_calloc(1, sizeof(*listener));
- if (!listener) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
- listener->schedule = schedule;
- listener->callback = callback;
- listener->context = context;
- listener->require_fqdn = require_fqdn;
- listener->lookup = lookup;
-
- if (local_ip_count > 0) {
- listener->socks = (SilcSocket *)silc_calloc(local_ip_count,
- sizeof(*listener->socks));
- if (!listener->socks) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
- } else {
- listener->socks = (SilcSocket *)silc_calloc(1, sizeof(*listener->socks));
- if (!listener->socks) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
-
- local_ip_count = 1;
- }
-
- /* Bind to local addresses */
- for (i = 0; i < local_ip_count; i++) {
- SILC_LOG_DEBUG(("Binding to local address %s",
- local_ip_addr ? local_ip_addr[i] : "0.0.0.0"));
-
- l = new SilcSymbianTCPListener;
- if (!l)
- goto err;
-
- /* Connect to socket server */
- ret = l->ss.Connect();
- if (ret != KErrNone)
- goto err;
-
- /* Set listener address */
- if (local_ip_addr) {
- server = TInetAddr(port);
- tmp = (TText *)local_ip_addr[i];
- ret = server.Input(tmp);
- if (ret != KErrNone)
- goto err;
- } else {
- server = TInetAddr(KInetAddrAny, port);
- }
-
- /* Create the socket */
- ret = l->sock.Open(l->ss, KAfInet, KSockStream, KProtocolInetTcp);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Cannot create socket"));
- goto err;
- }
-
- /* Set the socket options */
- ret = l->sock.SetOpt(KSoReuseAddr, KSolInetIp, 1);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Cannot set socket options"));
- goto err;
- }
-
- /* Bind the listener socket */
- ret = l->sock.Bind(server);
- if (ret != KErrNone) {
- SILC_LOG_DEBUG(("Cannot bind socket"));
- goto err;
- }
-
- /* Specify that we are listenning */
- ret = l->sock.Listen(5);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Cannot set socket listenning"));
- goto err;
- }
- l->Listen();
-
- l->listener = listener;
- listener->socks[i] = (SilcSocket)l;
- listener->socks_count++;
- }
-
- SILC_LOG_DEBUG(("TCP listener created"));
-
- return listener;
-
- err:
- if (l)
- delete l;
- if (callback)
- callback(SILC_NET_ERROR, NULL, context);
- if (listener)
- silc_net_close_listener(listener);
- return NULL;
-}
-
-/* Close network listener */
-
-void silc_net_close_listener(SilcNetListener listener)
-{
- int i;
-
- SILC_LOG_DEBUG(("Closing network listener"));
-
- for (i = 0; i < listener->socks_count; i++) {
- SilcSymbianTCPListener *l = (SilcSymbianTCPListener *)listener->socks[i];
- l->sock.CancelAll();
- l->sock.Close();
- l->ss.Close();
- if (l->new_conn)
- delete l->new_conn;
- delete l;
- }
-
- silc_free(listener->socks);
- silc_free(listener);
-}
-
-/**************************** TCP/IP connecting *****************************/
-
-static void silc_net_connect_stream(SilcSocketStreamStatus status,
- SilcStream stream, void *context);
-
-/* TCP connecting class */
-
-class SilcSymbianTCPConnect : public CActive {
-public:
- /* Constructor */
- SilcSymbianTCPConnect() : CActive(CActive::EPriorityStandard)
- {
- CActiveScheduler::Add(this);
- }
-
- /* Destructor */
- ~SilcSymbianTCPConnect()
- {
- silc_free(remote);
- if (op)
- silc_async_free(op);
- Cancel();
- }
-
- /* Connect to remote host */
- void Connect(TSockAddr &addr)
- {
- sock->Connect(addr, iStatus);
- SetActive();
- }
-
- /* Connection callback */
- virtual void RunL()
- {
- if (iStatus != KErrNone) {
- if (callback)
- callback(SILC_NET_ERROR, NULL, context);
- sock->CancelConnect();
- delete sock;
- ss->Close();
- delete ss;
- sock = NULL;
- ss = NULL;
- delete this;
- return;
- }
-
- /* Create stream */
- if (callback) {
- silc_socket_tcp_stream_create(
- (SilcSocket)silc_create_symbian_socket(sock, ss),
- FALSE, FALSE, schedule, silc_net_connect_stream,
- (void *)this);
- } else {
- sock->Close();
- delete sock;
- ss->Close();
- delete ss;
- sock = NULL;
- ss = NULL;
- }
-
- delete this;
- }
-
- /* Cancel */
- virtual void DoCancel()
- {
- if (ss) {
- ss->Close();
- delete ss;
- }
- if (sock) {
- sock->CancelConnect();
- delete sock;
- }
- }
-
- RSocket *sock;
- RSocketServ *ss;
- char *remote;
- char remote_ip[64];
- int port;
- SilcAsyncOperation op;
- SilcSchedule schedule;
- SilcNetCallback callback;
- void *context;
-};
-
-/* Stream creation callback */
-
-static void silc_net_connect_stream(SilcSocketStreamStatus status,
- SilcStream stream, void *context)
-{
- SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context;
- SilcNetStatus net_status = SILC_NET_OK;
-
- if (status != SILC_SOCKET_OK) {
- /* In case of error, the socket has been destroyed already */
- if (status == SILC_SOCKET_UNKNOWN_IP)
- net_status = SILC_NET_UNKNOWN_IP;
- else if (status == SILC_SOCKET_UNKNOWN_HOST)
- net_status = SILC_NET_UNKNOWN_HOST;
- else
- net_status = SILC_NET_ERROR;
- }
-
- /* Set stream information */
- if (stream && conn->callback)
- silc_socket_stream_set_info(stream,
- !silc_net_is_ip(conn->remote) ? conn->remote :
- conn->remote_ip, conn->remote_ip, conn->port);
-
- /* Call connection callback */
- if (conn->callback)
- conn->callback(net_status, stream, conn->context);
- else if (stream)
- silc_stream_destroy(stream);
-
- delete conn;
-}
-
-/* Connecting abort callback */
-
-static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
-{
- SilcSymbianTCPConnect *conn = (SilcSymbianTCPConnect *)context;
-
- /* Abort */
- conn->callback = NULL;
- conn->op = NULL;
- if (conn->sock)
- sock->CancelConnect();
-}
-
-/* Create TCP/IP connection */
-
-SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
- const char *remote_ip_addr,
- int remote_port,
- SilcSchedule schedule,
- SilcNetCallback callback,
- void *context)
-{
- SilcSymbianTCPConnect *conn;
- TInetAddr local, remote;
- SilcNetStatus status;
- TBuf<64> tmp;
- TInt ret;
-
- if (!remote_ip_addr || remote_port < 1 || !schedule || !callback)
- return NULL;
-
- SILC_LOG_DEBUG(("Creating connection to host %s port %d",
- remote_ip_addr, remote_port));
-
- conn = new SilcSymbianTCPConnect;
- if (!conn) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
- conn->schedule = schedule;
- conn->callback = callback;
- conn->context = context;
- conn->port = remote_port;
- conn->remote = strdup(remote_ip_addr);
- if (!conn->remote) {
- status = SILC_NET_NO_MEMORY;
- goto err;
- }
-
- /* Allocate socket */
- conn->sock = new RSocket;
- if (!conn->sock) {
- status = SILC_NET_NO_MEMORY;
- goto err;
- }
-
- /* Allocate socket server */
- conn->ss = new RSocketServ;
- if (!conn->ss) {
- status = SILC_NET_NO_MEMORY;
- goto err;
- }
-
- /* Connect to socket server */
- ret = conn->ss->Connect();
- if (ret != KErrNone) {
- status = SILC_NET_ERROR;
- goto err;
- }
-
- /* Start async operation */
- conn->op = silc_async_alloc(silc_net_connect_abort, NULL, (void *)conn);
- if (!conn->op) {
- status = SILC_NET_NO_MEMORY;
- goto err;
- }
-
- /* Do host lookup */
- if (!silc_net_is_ip(remote_ip_addr)) {
- if (!silc_net_gethostbyname(remote_ip_addr, FALSE, conn->remote_ip,
- sizeof(conn->remote_ip))) {
- SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
- "host", conn->remote));
- status = SILC_NET_HOST_UNREACHABLE;
- goto err;
- }
- } else {
- strcpy(conn->remote_ip, remote_ip_addr);
- }
-
- /* Create the connection socket */
- ret = conn->sock->Open(*conn->ss, KAfInet, KSockStream, KProtocolInetTcp);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Cannot create socket"));
- status = SILC_NET_ERROR;
- goto err;
- }
-
- /* Set appropriate options */
- conn->sock->SetOpt(KSoTcpNoDelay, KSolInetTcp, 1);
- conn->sock->SetOpt(KSoTcpKeepAlive, KSolInetTcp, 1);
-
- /* Bind to the local address if provided */
- if (local_ip_addr) {
- local = TInetAddr(0);
- tmp = (TText *)local_ip_addr;
- ret = local.Input(tmp);
- if (ret == KErrNone)
- ret = conn->sock->Bind(local);
- }
-
- /* Connect to the host */
- remote = TInetAddr(remote_port);
- tmp = (TText *)conn->remote_ip;
- ret = remote.Input(tmp);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Cannot connect (cannot set address)"));
- status = SILC_NET_ERROR;
- goto err;
- }
- conn->Connect(remote);
-
- SILC_LOG_DEBUG(("Connection operation in progress"));
-
- return conn->op;
-
- err:
- if (conn->ss) {
- conn->ss->Close();
- delete conn->ss;
- }
- if (conn->sock)
- delete conn->sock;
- if (conn->remote)
- silc_free(conn->remote);
- if (conn->op)
- silc_async_free(conn->op);
- callback(status, NULL, context);
- delete conn;
- return NULL;
-}
-
-/****************************** UDP routines ********************************/
-
-/* Create UDP/IP connection */
-
-SilcStream silc_net_udp_connect(const char *local_ip_addr, int local_port,
- const char *remote_ip_addr, int remote_port,
- SilcSchedule schedule)
-{
- SilcSymbianSocket *s;
- SilcStream stream;
- TInetAddr local, remote;
- TRequestStatus status;
- RSocket *sock = NULL;
- RSocketServ *ss = NULL;
- TBuf<64> tmp;
- TInt ret;
-
- SILC_LOG_DEBUG(("Creating UDP stream"));
-
- if (!schedule)
- goto err;
-
- SILC_LOG_DEBUG(("Binding to local address %s",
- local_ip_addr ? local_ip_addr : "0.0.0.0"));
-
- sock = new RSocket;
- if (!sock)
- goto err;
-
- ss = new RSocketServ;
- if (!ss)
- goto err;
-
- /* Open socket server */
- ret = ss->Connect();
- if (ret != KErrNone)
- goto err;
-
- /* Get local bind address */
- if (local_ip_addr) {
- local = TInetAddr(local_port);
- tmp = (TText *)local_ip_addr;
- ret = local.Input(tmp);
- if (ret != KErrNone)
- goto err;
- } else {
- local = TInetAddr(KInetAddrAny, local_port);
- }
-
- /* Create the socket */
- ret = sock->Open(*ss, KAfInet, KSockDatagram, KProtocolInetUdp);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Cannot create socket"));
- goto err;
- }
-
- /* Set the socket options */
- sock->SetOpt(KSoReuseAddr, KSolInetIp, 1);
-
- /* Bind the listener socket */
- ret = sock->Bind(local);
- if (ret != KErrNone) {
- SILC_LOG_DEBUG(("Cannot bind socket"));
- goto err;
- }
-
- /* Set to connected state if remote address is provided. */
- if (remote_ip_addr && remote_port) {
- remote = TInetAddr(remote_port);
- tmp = (TText *)remote_ip_addr;
- ret = remote.Input(tmp);
- if (ret != KErrNone)
- goto err;
-
- sock->Connect(remote, status);
- if (status != KErrNone) {
- SILC_LOG_DEBUG(("Cannot connect UDP stream"));
- goto err;
- }
- }
-
- /* Encapsulate into socket stream */
- s = silc_create_symbian_socket(sock, ss);
- if (!s)
- goto err;
- stream =
- silc_socket_udp_stream_create((SilcSocket)s, local_ip_addr ?
- silc_net_is_ip6(local_ip_addr) : FALSE,
- remote_ip_addr ? TRUE : FALSE, schedule);
- if (!stream)
- goto err;
-
- SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
- return stream;
-
- err:
- if (sock)
- delete sock;
- if (ss) {
- ss->Close();
- delete ss;
- }
- return NULL;
-}
-
-/* Sets socket to non-blocking mode */
-
-int silc_net_set_socket_nonblock(SilcSocket sock)
-{
- /* Nothing to do in Symbian where blocking socket mode is asynchronous
- already (ie. non-blocking). */
- return 0;
-}
-
-/* Converts the IP number string from numbers-and-dots notation to
- binary form. */
-
-SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
-{
- int ret = 0;
-
- struct in_addr tmp;
- ret = inet_aton(addr, &tmp);
- if (bin_len < 4)
- return FALSE;
-
- memcpy(bin, (unsigned char *)&tmp.s_addr, 4);
-
- return ret != 0;
-}
-
-/* Get remote host and IP from socket */
-
-SilcBool silc_net_check_host_by_sock(SilcSocket sock, char **hostname,
- char **ip)
-{
- SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
- TInetAddr addr;
- char host[256];
- TBuf<64> tmp;
-
- if (hostname)
- *hostname = NULL;
- *ip = NULL;
-
- s->sock->RemoteName(addr);
- addr.Output(tmp);
-
- *ip = (char *)silc_memdup(tmp.Ptr(), tmp.Length());
- if (*ip == NULL)
- return FALSE;
-
- /* Do reverse lookup if we want hostname too. */
- if (hostname) {
- /* Get host by address */
- if (!silc_net_gethostbyaddr(*ip, host, sizeof(host)))
- return FALSE;
-
- *hostname = (char *)silc_memdup(host, strlen(host));
- SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));
-
- /* Reverse */
- if (!silc_net_gethostbyname(*hostname, TRUE, host, sizeof(host)))
- return FALSE;
-
- if (strcmp(*ip, host))
- return FALSE;
- }
-
- SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
- return TRUE;
-}
-
-/* Get local host and IP from socket */
-
-SilcBool silc_net_check_local_by_sock(SilcSocket sock, char **hostname,
- char **ip)
-{
- SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
- TInetAddr addr;
- char host[256];
- TBuf<64> tmp;
-
- if (hostname)
- *hostname = NULL;
- *ip = NULL;
-
- s->sock->LocalName(addr);
- addr.Output(tmp);
-
- *ip = (char *)silc_memdup(tmp.Ptr(), tmp.Length());
- if (*ip == NULL)
- return FALSE;
-
- /* Do reverse lookup if we want hostname too. */
- if (hostname) {
- /* Get host by address */
- if (!silc_net_gethostbyaddr(*ip, host, sizeof(host)))
- return FALSE;
-
- *hostname = (char *)silc_memdup(host, strlen(host));
- SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));
-
- /* Reverse */
- if (!silc_net_gethostbyname(*hostname, TRUE, host, sizeof(host)))
- return FALSE;
-
- if (strcmp(*ip, host))
- return FALSE;
- }
-
- SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
- return TRUE;
-}
-
-/* Get remote port from socket */
-
-SilcUInt16 silc_net_get_remote_port(SilcSocket sock)
-{
- SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
- TInetAddr addr;
-
- s->sock->RemoteName(addr);
- return (SilcUInt16)addr.Port();
-}
-
-/* Get local port from socket */
-
-SilcUInt16 silc_net_get_local_port(SilcSocket sock)
-{
- SilcSymbianSocket *s = (SilcSymbianSocket *)sock;
- TInetAddr addr;
-
- s->sock->LocalName(addr);
- return (SilcUInt16)addr.Port();
-}
+++ /dev/null
-/*\r
-\r
- silcsymbianschduler.cpp\r
-\r
- Author: Pekka Riikonen <priikone@silcnet.org>\r
-\r
- Copyright (C) 1998 - 2007 Pekka Riikonen\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; version 2 of the License.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
-*/\r
-\r
-/* On symbian the SILC Scheduler doesn't do anything. All timeout tasks\r
- are dispatched by the generic scheduler implementation. Sockets and\r
- file descriptors are dispatched automatically in their class\r
- implementation, so adding FD Tasks on Symbian doesn't do anything.\r
-\r
- This also means that on Symbian the SILC Scheduler always returns\r
- immediately. Because FD tasks use the Symbian scheduler the performance\r
- is as good as it can be. For timeout tasks the performance is not an\r
- issue. */\r
-\r
-#include "silc.h"\r
-\r
-int silc_poll(SilcSchedule schedule, void *context)\r
-{\r
- /* Return immediately, timeout. */\r
- return 0;\r
-}\r
-\r
-SilcBool silc_schedule_internal_schedule_fd(SilcSchedule schedule,\r
- void *context,\r
- SilcTaskFd task,\r
- SilcTaskEvent event_mask)\r
-{\r
- /* Nothing to do */\r
- return TRUE;\r
-}\r
-\r
-void *silc_schedule_internal_init(SilcSchedule schedule,\r
- void *app_context)\r
-{\r
- /* Nothing to do */\r
- return (void *)1;\r
-}\r
-\r
-\r
-void silc_schedule_internal_uninit(SilcSchedule schedule, void *context)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-void silc_schedule_internal_signal_register(SilcSchedule schedule,\r
- void *context,\r
- SilcUInt32 sig,\r
- SilcTaskCallback callback,\r
- void *callback_context)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-void silc_schedule_internal_signal_unregister(SilcSchedule schedule,\r
- void *context,\r
- SilcUInt32 sig)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-void silc_schedule_internal_signals_block(SilcSchedule schedule, void *context)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-void silc_schedule_internal_signals_unblock(SilcSchedule schedule,\r
- void *context)\r
-{\r
- /* Nothing to do */\r
-}\r
-\r
-const SilcScheduleOps schedule_ops =\r
-{\r
- silc_schedule_internal_init,\r
- silc_schedule_internal_uninit,\r
- silc_poll,\r
- silc_schedule_internal_schedule_fd,\r
- silc_schedule_internal_wakeup,\r
- silc_schedule_internal_signal_register,\r
- silc_schedule_internal_signal_unregister,\r
- silc_schedule_internal_signals_call,\r
- silc_schedule_internal_signals_block,\r
- silc_schedule_internal_signals_unblock,\r
-};\r
+++ /dev/null
-/*
-
- silcsymbiansocketstream.cpp
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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.
-
-*/
-
-/* In this implementation the sockets are in blocking mode, except that
- on Symbian the blocking mode is actually asynchronous, which semantically
- translates into non-blocking mode. The non-blocking mode just is not
- explicitly set because it would require us also to explicitly poll for the
- socket, which is done automatically by the Active Scheduler in blocking
- mode. */
-
-#include "silc.h"
-#include "silcsymbiansocketstream.h"
-
-/***************************** Socket Classes *******************************/
-
-/* Socket stream sender */
-
-class SilcSymbianSocketSend : public CActive {
-public:
- /* Constructor */
- SilcSymbianSocketSend() : CActive(CActive::EPriorityStandard)
- {
- CActiveScheduler::Add(this);
- }
-
- /* Destructor */
- ~SilcSymbianSocketSend()
- {
- Cancel();
- }
-
- /* Send data */
- void Send(const TDesC8& buf, TSockXfrLength& ret_len)
- {
- s->sock->Send(buf, 0, iStatus, ret_len);
- SetActive();
- }
-
- /* Send data */
- void Send(const TDesC8& buf, TSockXfrLength& ret_len,
- const char *remote_ip, int remote_port)
- {
- TInetAddr remote;
- TBuf<64> tmp;
-
- remote = TInetAddr(remote_port);
- tmp = (TText *)remote_ip;
- if (remote.Input(tmp) == KErrNone) {
- s->sock->SendTo(buf, remote, 0, iStatus, ret_len);
- SetActive();
- }
- }
-
- /* Sending callback */
- virtual void RunL()
- {
- if (iStatus != KErrNone) {
- if (iStatus == KErrEof)
- s->eof = 1;
- else
- s->error = 1;
- return;
- }
-
- /* Call stream callback */
- if (s->stream && s->stream->notifier)
- s->stream->notifier(s->stream, SILC_STREAM_CAN_WRITE,
- s->stream->notifier_context);
- }
-
- /* Cancel */
- virtual void DoCancel()
- {
- s->sock->CancelWrite();
- }
-
- SilcSymbianSocket *s;
-};
-
-/* Socket stream receiver */
-
-class SilcSymbianSocketReceive : public CActive {
-public:
- /* Constructor */
- SilcSymbianSocketReceive() : CActive(CActive::EPriorityStandard)
- {
- CActiveScheduler::Add(this);
- }
-
- /* Destructor */
- ~SilcSymbianSocketReceive()
- {
- Cancel();
- }
-
- /* Read data */
- void Read()
- {
- if (!s->stream || s->stream->connected)
- s->sock->RecvOneOrMore(inbuf, 0, iStatus, inbuf_len);
- else
- s->sock->RecvFrom(inbuf, remote, 0, iStatus);
- SetActive();
- }
-
- /* Reading callback */
- virtual void RunL()
- {
- if (iStatus != KErrNone) {
- if (iStatus == KErrEof)
- s->eof = 1;
- else
- s->error = 1;
- return;
- }
-
- if (!inbuf_ptr)
- inbuf_ptr = inbuf.Ptr();
- inbuf_len = inbuf.Length();
-
- /* Call stream callback */
- if (s->stream && s->stream->notifier)
- s->stream->notifier(s->stream, SILC_STREAM_CAN_READ,
- s->stream->notifier_context);
-
- /* Read more */
- Read();
- }
-
- /* Cancel */
- virtual void DoCancel()
- {
- s->sock->CancelRecv();
- }
-
- TBuf8<8192> inbuf;
- const unsigned char *inbuf_ptr;
- TSockXfrLength inbuf_len;
- SilcSymbianSocket *s;
- TInetAddr remote;
-};
-
-/* Creates symbian socket stream context */
-
-SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,
- RSocketServ *ss)
-{
- SilcSymbianSocket *stream;
-
- stream = (SilcSymbianSocket *)silc_calloc(1, sizeof(*stream));
- if (!stream)
- return NULL;
- stream->sock = sock;
- stream->ss = ss;
-
- stream->send = new SilcSymbianSocketSend;
- if (!stream->send) {
- silc_free(stream);
- return NULL;
- }
-
- stream->receive = new SilcSymbianSocketReceive;
- if (!stream->receive) {
- delete stream->send;
- silc_free(stream);
- return NULL;
- }
-
- return stream;
-}
-
-/***************************** SILC Stream API ******************************/
-
-/* Stream read operation */
-
-int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
- SilcSymbianSocketReceive *recv = s->receive;
- int len;
-
- if (s->error || !s->stream)
- return -2;
- if (s->eof)
- return 0;
- if (!recv->inbuf_len() || !recv->inbuf_ptr)
- return -1;
-
- len = recv->inbuf_len();
- if (buf_len < len)
- len = buf_len;
-
- /* Copy the read data */
- memcpy(buf, recv->inbuf_ptr, len);
-
- recv->inbuf_ptr = NULL;
- if (len < recv->inbuf_len())
- recv->inbuf_ptr += len;
-
- return len;
-}
-
-/* Stream write operation */
-
-int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
- SilcSymbianSocketSend *send = s->send;
- TSockXfrLength ret_len;
- TPtrC8 write_buf(data, data_len);
-
- if (s->would_block)
- return -1;
- if (s->error || !s->stream)
- return -2;
- if (s->eof)
- return 0;
-
- /* Send data */
- send->Send(write_buf, ret_len);
- if (send->iStatus.Int() != KErrNone) {
- if (send->iStatus.Int() == KErrEof)
- return 0;
- return -2;
- }
-
- if (!ret_len())
- return -1;
-
- s->would_block = 0;
- if (ret_len() < data_len)
- s->would_block = 1;
-
- return ret_len();
-}
-
-/* Receive UDP packet, connected socket. */
-
-int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
-}
-
-/* Send UDP packet, connected socket. */
-
-int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcSocketStream sock = (SilcSocketStream)stream;
-
- /* In connectionless state check if remote IP and port is provided */
- if (!sock->connected && sock->ip && sock->port)
- return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
-
- /* In connected state use normal writing to socket. */
- return silc_socket_stream_write(stream, data, data_len);
-}
-
-/* Receive UDP packet, connectionless socket */
-
-int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
- SilcUInt32 remote_ip_addr_size, int *remote_port,
- unsigned char *buf, SilcUInt32 buf_len)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
- SilcSymbianSocketReceive *recv = s->receive;
- int len;
-
- if (s->eof)
- return 0;
- if (!recv->inbuf_len() || !recv->inbuf_ptr)
- return -1;
-
- len = recv->inbuf_len();
- if (buf_len < len)
- len = buf_len;
-
- /* Copy the read data */
- memcpy(buf, recv->inbuf_ptr, len);
-
- recv->inbuf_ptr = NULL;
- if (len < recv->inbuf_len())
- recv->inbuf_ptr += len;
-
- if (remote_ip_addr && remote_ip_addr_size && remote_port) {
- TBuf<64> ip;
- recv->remote.Output(ip);
- silc_strncat(remote_ip_addr, remote_ip_addr_size, (const char *)ip.Ptr(),
- ip.Length());
- *remote_port = recv->remote.Port();
- }
-
- return len;
-}
-
-/* Send UDP packet, connectionless socket */
-
-int silc_net_udp_send(SilcStream stream,
- const char *remote_ip_addr, int remote_port,
- const unsigned char *data, SilcUInt32 data_len)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
- SilcSymbianSocketSend *send = s->send;
- TSockXfrLength ret_len;
- TPtrC8 write_buf(data, data_len);
-
- if (s->would_block)
- return -1;
- if (s->eof)
- return 0;
-
- /* Send data */
- send->Send(write_buf, ret_len, remote_ip_addr, remote_port);
- if (send->iStatus.Int() != KErrNone) {
- if (send->iStatus.Int() == KErrEof)
- return 0;
- return -2;
- }
-
- if (!ret_len())
- return -1;
-
- s->would_block = 0;
- if (ret_len() < data_len)
- s->would_block = 1;
-
- return ret_len();
-}
-
-/* Closes socket */
-
-SilcBool silc_socket_stream_close(SilcStream stream)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
- s->sock->Close();
-
- return TRUE;
-}
-
-/* Destroys the stream */
-
-void silc_socket_stream_destroy(SilcStream stream)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
-
- silc_socket_stream_close(stream);
- silc_free(socket_stream->ip);
- silc_free(socket_stream->hostname);
- silc_free(socket_stream);
- delete s->send;
- delete s->receive;
- delete s->sock;
- if (s->ss) {
- s->ss->Close();
- delete s->ss;
- }
- silc_free(s);
-}
-
-/* Sets stream notification callback for the stream */
-
-SilcBool silc_socket_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
-{
- SilcSocketStream socket_stream = (SilcSocketStream)stream;
- SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
-
- if (callback)
- s->stream = socket_stream;
- else
- s->stream = NULL;
-
- socket_stream->notifier = callback;
- socket_stream->notifier_context = context;
- socket_stream->schedule = schedule;
-
- return TRUE;
-}
+++ /dev/null
-/*\r
-\r
- silcsymbiansocketstream.h\r
-\r
- Author: Pekka Riikonen <priikone@silcnet.org>\r
-\r
- Copyright (C) 2006 Pekka Riikonen\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; version 2 of the License.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
-*/\r
-\r
-#ifndef SILCSYMBIANSOCKETSTREAM_H\r
-#define SILCSYMBIANSOCKETSTREAM_H\r
-\r
-#include <e32std.h>\r
-#include <es_sock.h>\r
-#include <in_sock.h>\r
-\r
-class SilcSymbianSocketSend;\r
-class SilcSymbianSocketReceive;\r
-\r
-/* Symbian Socket context */\r
-typedef struct {\r
- SilcSymbianSocketSend *send;\r
- SilcSymbianSocketReceive *receive;\r
- RSocket *sock;\r
- RSocketServ *ss;\r
- SilcSocketStream stream;\r
- unsigned int eof : 1;\r
- unsigned int error : 1;\r
- unsigned int would_block : 1;\r
-} SilcSymbianSocket;\r
-\r
-/* Creates symbian socket context. This will steal the `sock' and `ss'. */\r
-SilcSymbianSocket *silc_create_symbian_socket(RSocket *sock,\r
- RSocketServ *ss);\r
-\r
-#endif /* SILCSYMBIANSOCKETSTREAM_H */\r
+++ /dev/null
-/*
-
- silcsymbianthread.cpp
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2006 - 2007 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 <e32std.h>
-
-/**************************** SILC Thread API *******************************/
-
-/* Thread structure for Symbian */
-typedef struct {
-#ifdef SILC_THREADS
- SilcThreadStart start_func;
- void *context;
- SilcBool waitable;
-#else
- void *tmp;
-#endif
-} *SilcSymbianThread;
-
-/* The actual thread function */
-
-static TInt silc_thread_start(TAny *context)
-{
-#ifdef SILC_THREADS
- SilcSymbianThread tc = (SilcSymbianThread)context;
- SilcThreadStart start_func = tc->start_func;
- void *context = tc->context;
- SilcBool waitable = tc->waitable;
-
- silc_free(tc);
-
- /* Call the thread function */
- if (waitable)
- silc_thread_exit(start_func(context));
- else
- start_func(context);
-
-#endif
- return KErrNone;
-}
-
-/* Executed new thread */
-
-SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- bool waitable)
-{
-#ifdef SILC_THREADS
- SilcSymbianThread tc;
- RThread *thread;
- TInt ret;
- TBuf<32> name;
-
- SILC_LOG_DEBUG(("Creating new thread"));
-
- tc = (SilcSymbianThread)silc_calloc(1, sizeof(*thread));
- if (!tc)
- return NULL;
- tc->start_func = start_func;
- tc->context = context;
- tc->waitable = waitable;
-
- /* Allocate thread */
- thread = new RThread();
- if (!thread) {
- silc_free(tc);
- return NULL;
- }
-
- /* Create the thread */
- name = (TText *)silc_time_string(0);
- ret = thread->Create(name, silc_thread_start, 8192, 4096, 1024 * 1024,
- (TAny *)tc);
- if (ret != KErrNone) {
- SILC_LOG_ERROR(("Could not create new thread"));
- delete thread;
- silc_free(tc);
- return NULL;
- }
-
- /* Start the thread */
- thread->Resume();
-
- /* Close our instance to the thread */
- thread->Close();
-
- return (SilcThread)thread;
-#else
- /* Call thread callback immediately */
- (*start_func)(context);
- return NULL;
-#endif
-}
-
-/* Exits current thread */
-
-void silc_thread_exit(void *exit_value)
-{
-#ifdef SILC_THREADS
- RThread().Kill((Tint)exit_value);
-#endif
-}
-
-/* Returns current thread context */
-
-SilcThread silc_thread_self(void)
-{
-#ifdef SILC_THREADS
- return (SilcThread)&RThread();
-#else
- return NULL;
-#endif
-}
-
-/* Blocks calling thread to wait for `thread' to finish. */
-
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
-{
-#ifdef SILC_THREADS
- TRequestStatus req;
- RThread *t = (RThread *)thread;
- t->Logon(req);
- User::WaitForAnyRequest();
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-/***************************** SILC Mutex API *******************************/
-
-/* SILC Mutex structure */
-struct SilcMutexStruct {
-#ifdef SILC_THREADS
- RMutex *mutex;
-#endif /* SILC_THREADS */
- unsigned int locked : 1;
-};
-
-SilcBool silc_mutex_alloc(SilcMutex *mutex)
-{
-#ifdef SILC_THREADS
- *mutex = (SilcMutex)silc_calloc(1, sizeof(**mutex));
- if (*mutex == NULL)
- return FALSE;
- (*mutex)->mutex = new RMutex();
- if (!(*mutex)->mutex) {
- silc_free(*mutex);
- return FALSE;
- }
- if ((*mutex)->mutex->CreateLocal() != KErrNone) {
- delete (*mutex)->mutex;
- silc_free(*mutex);
- return FALSE;
- }
- (*mutex)->locked = FALSE;
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_free(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- mutex->mutex->Close();
- delete mutex->mutex;
- silc_free(mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_lock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- mutex->mutex->Wait();
- mutex->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_unlock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- mutex->mutex->Signal();
- mutex->locked = FALSE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_assert_locked(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex)
- SILC_ASSERT(mutex->locked);
-#endif /* SILC_THREADS */
-}
-
-/***************************** SILC Rwlock API *****************************/
-
-/* SILC read/write lock structure */
-struct SilcRwLockStruct {
-#ifdef SILC_THREADS
- SilcMutex mutex;
- SilcCond cond;
-#endif /* SILC_THREADS */
- unsigned int readers : 31;
- unsigned int locked : 1;
-};
-
-SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
-{
-#ifdef SILC_THREADS
- *rwlock = (SilcRwLock)silc_calloc(1, sizeof(**rwlock));
- if (!(*rwlock))
- return FALSE;
- if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
- silc_free(*rwlock);
- return FALSE;
- }
- if (!silc_cond_alloc(&(*rwlock)->cond)) {
- silc_mutex_free((*rwlock)->mutex);
- silc_free(*rwlock);
- return FALSE;
- }
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_free(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- silc_mutex_free(rwlock->mutex);
- silc_cond_free(rwlock->cond);
- silc_free(rwlock);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_rdlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_lock(rwlock->mutex);
- rwlock->readers++;
- silc_mutex_unlock(rwlock->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_wrlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_lock(rwlock->mutex);
- while (rwlock->readers > 0)
- silc_cond_wait(rwlock->cond, rwlock->mutex);
- rwlock->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_unlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- if (rwlock->locked) {
- /* Unlock writer */
- rwlock->locked = FALSE;
- silc_mutex_unlock(rwlock->mutex);
- return;
- }
-
- /* Unlock reader */
- silc_mutex_lock(rwlock->mutex);
- rwlock->readers--;
- silc_cond_broadcast(rwlock->cond);
- silc_mutex_unlock(rwlock->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-/****************************** SILC Cond API *******************************/
-
-/* SILC Conditional Variable context */
-struct SilcCondStruct {
-#ifdef SILC_THREADS
- RCondVar *cond;
-#else
- void *tmp;
-#endif /* SILC_THREADS*/
-};
-
-SilcBool silc_cond_alloc(SilcCond *cond)
-{
-#ifdef SILC_THREADS
- *cond = (SilcCond)silc_calloc(1, sizeof(**cond));
- if (*cond == NULL)
- return FALSE;
- (*cond)->cond = new RCondVar();
- if (!(*cond)->cond) {
- silc_free(*cond);
- return FALSE;
- }
- if ((*cond)->cond->CreateLocal() != KErrNone) {
- delete (*cond)->cond;
- silc_free(*cond);
- return FALSE;
- }
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_free(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->cond->Close();
- delete cond->cond;
- silc_free(cond);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_signal(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->cond->Signal();
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_broadcast(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->cond->Broadcast();
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_wait(SilcCond cond, SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- cond->cond->Wait(*mutex->mutex);
-#endif /* SILC_THREADS*/
-}
-
-SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
- int timeout)
-{
-#ifdef SILC_THREADS
- if (timeout)
- return (cond->cond->TimedWait(*mutex->mutex, (TInt)timeout * 1000) ==
- KErrNone);
- return (cond->cond->Wait(*mutex->mutex) == KErrNone);
-#else
- return FALSE;
-#endif /* SILC_THREADS*/
-}
+++ /dev/null
-/*\r
-\r
- silcsymbianutil.cpp\r
-\r
- Author: Pekka Riikonen <priikone@silcnet.org>\r
-\r
- Copyright (C) 2006 Pekka Riikonen\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; version 2 of the License.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
-*/\r
-\r
-#include "silc.h"\r
-\r
-/* Returns the username of the user. */\r
-\r
-char *silc_get_username()\r
-{\r
- char *logname = NULL;\r
-\r
- logname = getlogin();\r
- if (!logname) {\r
- struct passwd *pw;\r
-\r
- pw = getpwuid(getuid());\r
- if (!pw)\r
- return strdup("User");\r
-\r
- logname = pw->pw_name;\r
- }\r
-\r
- return strdup(logname);\r
-}\r
-\r
-/* Returns the real name of ther user. */\r
-\r
-char *silc_get_real_name()\r
-{\r
- char *realname = NULL;\r
- struct passwd *pw;\r
-\r
- pw = getpwuid(getuid());\r
- if (!pw)\r
- return strdup("No Name");\r
-\r
- if (strchr(pw->pw_gecos, ','))\r
- *strchr(pw->pw_gecos, ',') = 0;\r
-\r
- if (!strlen(pw->pw_gecos))\r
- return strdup("No Name");\r
-\r
- realname = strdup(pw->pw_gecos);\r
-\r
- return realname;\r
-}\r
-\r
-/* Return current time to struct timeval. */\r
-\r
-int silc_gettimeofday(struct timeval *p)\r
-{\r
- return gettimeofday(p, NULL);\r
-}\r
-\r
-int silc_file_set_nonblock(int fd)\r
-{\r
- return 0;\r
-}\r
AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
bin_PROGRAMS = test_silcstrutil test_silcstringprep test_silchashtable \
- test_silclist test_silcfsm test_silcasync test_silcschedule \
- test_silcnet test_silcstack test_silcmime test_silcfdstream \
- test_silcatomic test_silcmutex test_silctime
+ test_silclist test_silcmime
test_silcstrutil_SOURCES = test_silcstrutil.c
test_silcstringprep_SOURCES = test_silcstringprep.c
test_silchashtable_SOURCES = test_silchashtable.c
test_silclist_SOURCES = test_silclist.c
test_silcmime_SOURCES = test_silcmime.c
-test_silcfsm_SOURCES = test_silcfsm.c
-test_silcasync_SOURCES = test_silcasync.c
-test_silcschedule_SOURCES = test_silcschedule.c
-test_silcnet_SOURCES = test_silcnet.c
-test_silcstack_SOURCES = test_silcstack.c
-test_silcfdstream_SOURCES = test_silcfdstream.c
-test_silcatomic_SOURCES = test_silcatomic.c
-test_silcmutex_SOURCES = test_silcmutex.c
-test_silctime_SOURCES = test_silctime.c
LIBS = $(SILC_COMMON_LIBS)
LDADD = -L.. -L../.. -lsilc
+++ /dev/null
-/* SilcAsyncOperation tests */
-
-#include "silc.h"
-#include "silcfsm.h"
-#include "silcasync.h"
-
-typedef void (*Callback)(void *context);
-
-SilcSchedule schedule;
-
-typedef struct {
- SilcFSM fsm;
- SilcFSMEventStruct sema;
- SilcAsyncOperation op;
- Callback cb;
- void *cb_context;
- SilcBool aborted;
-} *Foo;
-
-SILC_FSM_STATE(test_st_start);
-SILC_FSM_STATE(test_st_second);
-SILC_FSM_STATE(test_st_finish);
-
-SILC_TASK_CALLBACK(async_call_timeout)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("******Async call cb, continuing FSM"));
- silc_async_free(f->op);
- f->cb(f->cb_context);
-}
-
-static void async_abort(SilcAsyncOperation op, void *context)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("Async operation aborted"));
- silc_schedule_task_del_by_context(schedule, f);
- silc_schedule_task_del_by_callback(schedule, async_call_timeout);
- f->aborted = TRUE;
-}
-
-static SilcAsyncOperation async_call(Callback cb, void *context)
-{
- Foo f = context;
-
- SILC_LOG_DEBUG(("Async call"));
-
- f->cb = cb;
- f->cb_context = context;
- f->op = silc_async_alloc(async_abort, NULL, f);
-
- silc_schedule_task_add(schedule, 0, async_call_timeout, f, 2, 1,
- SILC_TASK_TIMEOUT);
-
- return f->op;
-}
-
-static void async_call_cb(void *context)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("*******Callback, signal and continue to next state"));
- f->op = NULL;
- SILC_FSM_EVENT_SIGNAL(&f->sema);
- SILC_FSM_CALL_CONTINUE(f->fsm);
-}
-
-SILC_FSM_STATE(test_st_start)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_st_start"));
-
- silc_fsm_event_init(&f->sema, fsm);
-
- /** Wait async callback */
- SILC_LOG_DEBUG(("Call async call"));
- silc_fsm_next_later(fsm, test_st_second, 1, 0);
- SILC_FSM_CALL((f->op = async_call(async_call_cb, f)));
-}
-
-SILC_FSM_STATE(test_st_second)
-{
- Foo f = fsm_context;
- SilcBool timedout;
-
- SILC_LOG_DEBUG(("test_st_second"));
-
- SILC_FSM_EVENT_TIMEDWAIT(&f->sema, 0, 1, &timedout);
-
- 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);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(test_st_finish)
-{
- SILC_LOG_DEBUG(("test_st_finish"));
-
- SILC_LOG_DEBUG(("Finish machine"));
- return SILC_FSM_FINISH;
-}
-
-static void destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
-{
- SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
- silc_fsm_free(fsm);
- silc_schedule_stop(schedule);
-}
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcFSM fsm;
- Foo f;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*async*");
- }
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(0, NULL);
-
- f = silc_calloc(1, sizeof(*f));
- if (!f)
- goto err;
-
- SILC_LOG_DEBUG(("Allocating FSM context"));
- fsm = silc_fsm_alloc(f, destructor, NULL, schedule);
- if (!fsm)
- goto err;
- silc_fsm_start(fsm, test_st_start);
- f->fsm = fsm;
-
- SILC_LOG_DEBUG(("Running scheduler"));
- silc_schedule(schedule);
-
- if (!f->aborted)
- goto err;
-
- silc_schedule_uninit(schedule);
- silc_free(f);
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
+++ /dev/null
-/* atomic operation tests */
-
-#include "silc.h"
-#include "silcatomic.h"
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcAtomic32 ref32;
- SilcAtomic16 ref16;
- SilcAtomic8 ref8;
- SilcAtomicPointer refptr;
- SilcUInt8 ret8;
- SilcUInt16 ret16;
- SilcUInt32 ret32;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*atomic*");
- }
-
- silc_atomic_init8(&ref8, 1);
- silc_atomic_init16(&ref16, 1);
- silc_atomic_init32(&ref32, 1);
- silc_atomic_init_pointer(&refptr, SILC_32_TO_PTR(0xdeadbeef));
-
- ret8 = silc_atomic_add_int8(&ref8, 7);
- SILC_LOG_DEBUG(("ref8: 1 + 7 = %d (8)", ret8));
- ret8 = silc_atomic_add_int8(&ref8, 3);
- SILC_LOG_DEBUG(("ref8: 8 + 3 = %d (11)", ret8));
- ret8 = silc_atomic_sub_int8(&ref8, 10);
- SILC_LOG_DEBUG(("ref8: 11 - 10 = %d (1)", ret8));
-
- ret16 = silc_atomic_add_int16(&ref16, 1);
- SILC_LOG_DEBUG(("ref16: 1 + 1 = %d (2)", ret16));
- ret16 = silc_atomic_add_int16(&ref16, 31020);
- SILC_LOG_DEBUG(("ref16: 2 + 31020 = %d (31022)", ret16));
- ret16 = silc_atomic_add_int16(&ref16, 34000);
- SILC_LOG_DEBUG(("ref16: 31022 + 34000 = %d (65022)", ret16));
- ret16 = silc_atomic_sub_int16(&ref16, 0);
- SILC_LOG_DEBUG(("ref16: 65022 - 0 = %d (65022)", ret16));
- ret16 = silc_atomic_sub_int16(&ref16, (SilcInt16)0xffff);
- SILC_LOG_DEBUG(("ref16: 65022 - 0xffff = %d (65023) (underflow)", ret16));
-
- SILC_LOG_DEBUG(("Current value: %d (-513)",
- (SilcInt16)silc_atomic_get_int16(&ref16)));
-
- SILC_LOG_DEBUG(("Swapping -513 with 57392"));
- if (!silc_atomic_cas16(&ref16, silc_atomic_get_int16(&ref16), 57392))
- goto err;
- SILC_LOG_DEBUG(("Current value: %d (57392)",
- silc_atomic_get_int16(&ref16)));
- SILC_LOG_DEBUG(("Swapping 57392 with -500"));
- if (!silc_atomic_cas16(&ref16, silc_atomic_get_int16(&ref16), -500))
- goto err;
- SILC_LOG_DEBUG(("Current value: %d (-500)",
- (SilcInt16)silc_atomic_get_int16(&ref16)));
-
- ret32 = silc_atomic_add_int32(&ref32, 1);
- SILC_LOG_DEBUG(("ref32: 1 + 1 = %d (2)", ret32));
- ret32 = silc_atomic_add_int32(&ref32, 310200);
- SILC_LOG_DEBUG(("ref32: 2 + 310200 = %d (310202)", ret32));
- ret32 = silc_atomic_add_int32(&ref32, 34000000);
- SILC_LOG_DEBUG(("ref32: 310202 + 34000000 = %d (34310202)", ret32));
- ret32 = silc_atomic_sub_int32(&ref32, 0);
- SILC_LOG_DEBUG(("ref32: 34310202 - 0 = %d (34310202)", ret32));
- ret32 = silc_atomic_sub_int32(&ref32, 0xfffffff);
- SILC_LOG_DEBUG(("ref32: 34310202 - 0xfffffff = %d (-234125253) "
- "(underflow)", ret32));
-
- SILC_LOG_DEBUG(("Current value: %d (-234125253)",
- silc_atomic_get_int32(&ref32)));
-
- SILC_LOG_DEBUG(("Swapping -234125253 with 76327681"));
- if (!silc_atomic_cas32(&ref32, silc_atomic_get_int32(&ref32), 76327681))
- goto err;
- SILC_LOG_DEBUG(("Current value: %d (76327681)",
- silc_atomic_get_int32(&ref32)));
-
- SILC_LOG_DEBUG(("Current ptr: %p (0xdeadbeef)",
- silc_atomic_get_pointer(&refptr)));
- SILC_LOG_DEBUG(("Swapping %p with NULL", silc_atomic_get_pointer(&refptr)));
- if (!silc_atomic_cas_pointer(&refptr,
- silc_atomic_get_pointer(&refptr), NULL))
- goto err;
- SILC_LOG_DEBUG(("Current ptr: %p (NULL)",
- silc_atomic_get_pointer(&refptr)));
-
- SILC_LOG_DEBUG(("Setting val 34322111 (32-bit)"));
- silc_atomic_set_int32(&ref32, 34322111);
- if (silc_atomic_get_int32(&ref32) != 34322111)
- goto err;
- SILC_LOG_DEBUG(("Setting val 1432211119 (32-bit)"));
- silc_atomic_set_int32(&ref32, 1432211119);
- if (silc_atomic_get_int32(&ref32) != 1432211119)
- goto err;
- SILC_LOG_DEBUG(("Setting val 23422 (16-bit)"));
- silc_atomic_set_int16(&ref16, 23422);
- if (silc_atomic_get_int16(&ref16) != 23422)
- goto err;
- SILC_LOG_DEBUG(("Setting val 124 (8-bit)"));
- silc_atomic_set_int8(&ref8, 124);
- if (silc_atomic_get_int8(&ref8) != 124)
- goto err;
-
- silc_atomic_uninit8(&ref8);
- silc_atomic_uninit16(&ref16);
- silc_atomic_uninit32(&ref32);
- silc_atomic_uninit_pointer(&refptr);
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
+++ /dev/null
-/* SILC FD Stream tests */
-
-#include "silc.h"
-
-SilcBool success = FALSE;
-SilcSchedule schedule;
-SilcStream stream;
-char buf1[10240];
-int buf1_len = sizeof(buf1);
-
-static void stream_notifier(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SILC_LOG_DEBUG(("Notifier"));
-
- /* XXX we probably never get here with this test program */
-
- silc_fsm_continue(context);
-}
-
-static void stream_notifier2(SilcStream stream, SilcStreamStatus status,
- void *context)
-{
- SILC_LOG_DEBUG(("Notifier"));
-
- /* XXX we probably never get here with this test program */
-
- silc_fsm_continue(context);
-}
-
-SILC_FSM_STATE(st_end)
-{
- unlink("/tmp/test_silcfdstream");
- unlink("/tmp/test_silcfdstream_copy");
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(st_readwrite)
-{
- int ret, i, k, fd1, fd2;
- char *cp;
-
- SILC_LOG_DEBUG(("Opening two files, one for reading, one for writing"));
-
- SILC_LOG_DEBUG(("Open file /tmp/test_silcfdstream for reading"));
- fd1 = silc_file_open("/tmp/test_silcfdstream", O_RDONLY);
- if (fd1 < 0) {
- SILC_LOG_DEBUG(("Error opening file"));
- goto err;
- }
-
- SILC_LOG_DEBUG(("Open file /tmp/test_silcfdstream_copy for writing"));
- unlink("/tmp/test_silcfdstream_copy");
- fd2 = silc_file_open("/tmp/test_silcfdstream_copy", O_CREAT | O_WRONLY);
- if (fd2 < 0) {
- SILC_LOG_DEBUG(("Error opening file"));
- goto err;
- }
-
- SILC_LOG_DEBUG(("Creating FD stream (two fds)"));
- stream = silc_fd_stream_create2(fd1, fd2);
- if (!stream) {
- SILC_LOG_DEBUG(("Error creating stream"));
- goto err;
- }
-
- silc_stream_set_notifier(stream, schedule, stream_notifier2, fsm);
-
- /* Stream between the fiels */
- SILC_LOG_DEBUG(("Read/write 3 bytes at a time"));
- memset(buf1, 0, sizeof(buf1));
- while ((ret = silc_stream_read(stream, buf1, 3)) > 0) {
- k = ret;
- cp = buf1;
- while (k > 0) {
- i = silc_stream_write(stream, cp, k);
-
- if (i == 0) {
- SILC_LOG_DEBUG(("EOF"));
- goto err;
- }
-
- if (i == -1) {
- SILC_LOG_DEBUG(("Would block, write later"));
- silc_fsm_next(fsm, st_end);
- return SILC_FSM_WAIT;
- }
-
- if (i == -2) {
- SILC_LOG_DEBUG(("Error: %s", strerror(silc_fd_stream_get_error(stream))));
- goto err;
- }
-
- k -= i;
- cp += i;
- }
- }
-
- if (ret == -1) {
- SILC_LOG_DEBUG(("Would block, read later"));
- silc_fsm_next(fsm, st_end);
- return SILC_FSM_WAIT;
- }
-
- if (ret == -2) {
- SILC_LOG_DEBUG(("Error: %s", strerror(silc_fd_stream_get_error(stream))));
- goto err;
- }
-
- if (ret == 0) {
- SILC_LOG_DEBUG(("EOF, ok"));
- success = TRUE;
- SILC_LOG_DEBUG(("Closing stream"));
- silc_stream_close(stream);
- SILC_LOG_DEBUG(("Destroying stream"));
- silc_stream_destroy(stream);
- }
-
- silc_fsm_next(fsm, st_end);
- return SILC_FSM_CONTINUE;
-
- err:
- silc_fsm_next(fsm, st_end);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(st_write)
-{
- int ret, i, k;
- char *cp;
-
- /* Simple writing example */
- SILC_LOG_DEBUG(("Open file /tmp/test_silcfdstream for writing"));
- SILC_LOG_DEBUG(("Creating FD stream"));
- 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, schedule, stream_notifier, fsm);
-
- memset(buf1, 0, sizeof(buf1));
- for (i = 0; i < sizeof(buf1); i++)
- buf1[i] = i;
-
- SILC_LOG_DEBUG(("Writing data"));
- k = buf1_len;
- cp = buf1;
- while (k > 0) {
- ret = silc_stream_write(stream, cp, k);
-
- if (ret == 0) {
- SILC_LOG_DEBUG(("EOF"));
- goto err;
- }
-
- if (ret == -1) {
- SILC_LOG_DEBUG(("Would block, write later"));
- silc_fsm_next(fsm, st_readwrite);
- return SILC_FSM_WAIT;
- }
-
- if (ret == -2) {
- SILC_LOG_DEBUG(("Error: %s", strerror(silc_fd_stream_get_error(stream))));
- goto err;
- }
-
- k -= ret;
- cp += ret;
- }
-
- SILC_LOG_DEBUG(("Closing stream"));
- silc_stream_close(stream);
-
- SILC_LOG_DEBUG(("Destroying stream"));
- silc_stream_destroy(stream);
-
- SILC_LOG_DEBUG(("Continue to next state"));
- silc_fsm_next(fsm, st_readwrite);
- return SILC_FSM_CONTINUE;
-
- err:
- silc_fsm_next(fsm, st_end);
- return SILC_FSM_CONTINUE;
-}
-
-static void fsm_dest(SilcFSM fsm, void *fsm_context, void *context)
-{
- silc_fsm_free(fsm);
- silc_schedule_stop(schedule);
-}
-
-int main(int argc, char **argv)
-{
- SilcFSM fsm;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*fdstream*");
- }
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(0, NULL);
- if (!schedule)
- goto err;
-
- SILC_LOG_DEBUG(("Allocating FSM"));
- fsm = silc_fsm_alloc(NULL, fsm_dest, NULL, schedule);
- if (!fsm)
- goto err;
-
- silc_fsm_start(fsm, st_write);
-
- SILC_LOG_DEBUG(("Running scheduler"));
- silc_schedule(schedule);
-
- if (!success)
- goto err;
-
- 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;
-}
+++ /dev/null
-/* SILC FSM tests */
-
-#include "silc.h"
-#include "silcfsm.h"
-
-typedef void (*Callback)(void *context);
-
-#define NUM_THREADS 200
-
-typedef struct FooStruct *Foo;
-
-typedef struct {
- SilcFSMThreadStruct thread;
- SilcFSMEventStruct sema;
- SilcBool finished;
- int rounds;
- Foo f;
-} T;
-
-struct FooStruct {
- SilcBool error;
- SilcFSM fsm;
- SilcFSMThreadStruct thread;
- int timeout;
- SilcFSMEventStruct sema;
- SilcFSMEventStruct wait2;
- SilcSchedule schedule;
- Callback cb;
- void *cb_context;
- T threads[NUM_THREADS];
- T threads2[NUM_THREADS];
- int c;
- int got_wait1 : 1;
- int got_wait2 : 1;
-};
-
-SILC_FSM_STATE(test_st_start);
-SILC_FSM_STATE(test_st_second);
-SILC_FSM_STATE(test_st_second_timeout);
-SILC_FSM_STATE(test_st_third);
-SILC_FSM_STATE(test_st_fourth);
-SILC_FSM_STATE(test_st_fifth);
-SILC_FSM_STATE(test_st_sixth);
-SILC_FSM_STATE(test_st_seventh);
-SILC_FSM_STATE(test_st_eighth);
-SILC_FSM_STATE(test_st_ninth);
-SILC_FSM_STATE(test_st_tenth);
-SILC_FSM_STATE(test_st_finish);
-
-SILC_FSM_STATE(test_st_wait1);
-SILC_FSM_STATE(test_st_wait2);
-SILC_FSM_STATE(test_st_signal1);
-SILC_FSM_STATE(test_st_signal1_check);
-
-SILC_FSM_STATE(test_thread_st_start);
-SILC_FSM_STATE(test_thread_st_finish);
-SILC_FSM_STATE(test_thread2_st_start);
-SILC_FSM_STATE(test_thread2_st_finish);
-SILC_FSM_STATE(test_thread3_st_start);
-SILC_FSM_STATE(test_thread4_st_start);
-
-static void test_fsm_destr(SilcFSMThread thread, void *thread_context,
- void *user_context)
-{
- silc_fsm_free(thread);
-}
-
-SILC_TASK_CALLBACK(async_call_timeout)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("Async call cb, continuing FSM"));
- f->cb(f->cb_context);
-}
-
-static void async_call(Callback cb, void *context)
-{
- Foo f = context;
- f->cb = cb;
- f->cb_context = context;
- SILC_LOG_DEBUG(("Async call"));
- silc_schedule_task_add(f->schedule, 0, async_call_timeout, f, 0, 200000,
- SILC_TASK_TIMEOUT);
-}
-
-SILC_FSM_STATE(test_st_start)
-{
- SILC_LOG_DEBUG(("test_st_start"));
-
- /** Move to second state */
- SILC_LOG_DEBUG(("Move to next state"));
- silc_fsm_next(fsm, test_st_second);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_st_second)
-{
- SILC_LOG_DEBUG(("test_st_second"));
-
- /** Move to second timeout state, timeout */
- SILC_LOG_DEBUG(("Move to next state with 2 second timeout"));
- silc_fsm_next_later(fsm, test_st_second_timeout, 2, 0);
- return SILC_FSM_WAIT;
-}
-
-SILC_TASK_CALLBACK(test_second_timeout)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("test_second_timeout"));
-
- SILC_LOG_DEBUG(("Interrupt 3 second wait and continue immediately"));
- f->c++;
- silc_fsm_next(f->fsm, test_st_third);
- silc_fsm_continue(f->fsm);
-}
-
-SILC_FSM_STATE(test_st_second_timeout)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_st_second_timeout"));
-
- /** Move to third state, timeout */
- SILC_LOG_DEBUG(("Move to next state with 3 second timeout"));
- SILC_LOG_DEBUG(("The timeout will be interrupted with silc_fsm_continue"));
- silc_fsm_next_later(fsm, test_st_third, 3, 0);
- silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
- test_second_timeout, f, 2, 500000);
- return SILC_FSM_WAIT;
-}
-
-static void async_call_cb(void *context)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("Callback, continue to next state"));
- SILC_FSM_CALL_CONTINUE(f->fsm);
-}
-
-SILC_FSM_STATE(test_st_third)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_st_third"));
-
- f->c++;
- assert(f->c == 2);
-
- f->fsm = fsm;
-
- /** Wait async callback*/
- SILC_LOG_DEBUG(("Call async call"));
- silc_fsm_next(fsm, test_st_fourth);
- SILC_FSM_CALL(async_call(async_call_cb, f));
-}
-
-SILC_FSM_STATE(test_st_fourth)
-{
- Foo f = fsm_context;
- SilcFSMThread t;
-
- SILC_LOG_DEBUG(("test_st_fourth"));
-
- f->timeout = 1;
-
- SILC_LOG_DEBUG(("Creating FSM thread"));
- 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);
-
- SILC_LOG_DEBUG(("Creating two waiting threads"));
- silc_fsm_event_init(&f->wait2, fsm);
- t = silc_fsm_thread_alloc(fsm, f, test_fsm_destr, NULL, FALSE);
- silc_fsm_start(t, test_st_wait1);
- t = silc_fsm_thread_alloc(fsm, f, test_fsm_destr, NULL, FALSE);
- silc_fsm_start(t, test_st_wait2);
-
- SILC_LOG_DEBUG(("Create signaller thread"));
- t = silc_fsm_thread_alloc(fsm, f, test_fsm_destr, NULL, FALSE);
- silc_fsm_start(t, test_st_signal1);
-
- /** Waiting thread to terminate */
- SILC_LOG_DEBUG(("Waiting for thread to terminate"));
- silc_fsm_next(fsm, test_st_fifth);
- SILC_FSM_THREAD_WAIT(&f->thread);
-}
-
-SILC_FSM_STATE(test_st_wait1)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("Waiter 1"));
- SILC_FSM_EVENT_WAIT(&f->wait2);
- SILC_LOG_DEBUG(("Waiter 1 signalled"));
- f->got_wait1 = 1;
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(test_st_wait2)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("Waiter 2"));
- SILC_FSM_EVENT_WAIT(&f->wait2);
- SILC_LOG_DEBUG(("Waiter 2 signalled"));
- f->got_wait2 = 1;
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(test_st_signal1)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("Signaller 1"));
- SILC_FSM_EVENT_SIGNAL(&f->wait2);
- silc_fsm_next_later(fsm, test_st_signal1_check, 0, 500000);
- return SILC_FSM_WAIT;;
-}
-
-SILC_FSM_STATE(test_st_signal1_check)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("Signal check"));
- assert(f->got_wait1 && f->got_wait2);
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(test_thread_st_start)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_thread_st_start"));
-
- /** Move to final state, timeout */
- SILC_LOG_DEBUG(("Move to final state with %d second timeout", f->timeout));
- silc_fsm_next_later(fsm, test_thread_st_finish, f->timeout, 0);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(test_thread_st_finish)
-{
- SILC_LOG_DEBUG(("test_thread_st_finish"));
-
- SILC_LOG_DEBUG(("Finishing the thread"));
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(test_st_fifth)
-{
- Foo f = fsm_context;
- SILC_LOG_DEBUG(("test_st_fifth"));
-
- SILC_LOG_DEBUG(("Thread terminated, start new real thread"));
-
- f->timeout = 7;
-
- SILC_LOG_DEBUG(("Creating FSM event"));
- silc_fsm_event_init(&f->sema, fsm);
-
- SILC_LOG_DEBUG(("Creating FSM thread"));
- 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_EVENT_TIMEDWAIT(&f->sema, 5, 0, NULL);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_thread2_st_start)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_thread2_st_start"));
-
- /** Move to final state, timeout */
- SILC_LOG_DEBUG(("Move to final state with %d second timeout", f->timeout));
- silc_fsm_next_later(fsm, test_thread2_st_finish, f->timeout, 0);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(test_thread2_st_finish)
-{
- Foo f = fsm_context;
- SILC_LOG_DEBUG(("test_thread2_st_finish"));
-
- SILC_LOG_DEBUG(("Post semaphore"));
- SILC_FSM_EVENT_SIGNAL(&f->sema);
-
- SILC_LOG_DEBUG(("Finishing the thread"));
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(test_st_sixth)
-{
- SILC_LOG_DEBUG(("test_st_sixth"));
-
- SILC_LOG_DEBUG(("Thread wait timedout, OK"));
-
- /** Move to next state, timeout */
- SILC_LOG_DEBUG(("Continue to next state with 4 second timeout"));
- silc_fsm_next_later(fsm, test_st_seventh, 4, 0);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(test_thread3_st_start)
-{
- T *t = fsm_context;
-
- if (t->rounds == 0) {
- SILC_FSM_EVENT_SIGNAL(&t->sema);
- return SILC_FSM_FINISH;
- }
-
- t->rounds--;
-
- /** Call in recursive */
- silc_fsm_next(fsm, test_thread3_st_start);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_st_seventh)
-{
- Foo f = fsm_context;
- int i;
-
- SILC_LOG_DEBUG(("test_st_seventh"));
-
-
- SILC_LOG_DEBUG(("Creating %d FSM threads", NUM_THREADS));
- for (i = 0; i < NUM_THREADS; i++) {
- f->threads[i].rounds = 10;
- f->threads[i].f = f;
- silc_fsm_event_init(&f->threads[i].sema, fsm);
- 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);
- }
-
- /** Move to wait threads */
- silc_fsm_next(fsm, test_st_eighth);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_st_eighth)
-{
- Foo f = fsm_context;
- int i;
-
- for (i = 0; i < NUM_THREADS; i++) {
- if (f->threads[i].finished == FALSE) {
- SILC_FSM_EVENT_WAIT(&f->threads[i].sema);
- f->threads[i].finished = TRUE;
- }
- }
-
- SILC_LOG_DEBUG(("All %d threads terminated", NUM_THREADS));
-
- /** Move to next thread */
- silc_fsm_next(fsm, test_st_ninth);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_thread4_st_start)
-{
- T *t = fsm_context;
-
- if (t->rounds == 0) {
- SILC_FSM_EVENT_SIGNAL(&t->sema);
- return SILC_FSM_FINISH;
- }
-
- t->rounds--;
-
- /** Call in recursive */
- silc_fsm_next(fsm, test_thread4_st_start);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_st_ninth)
-{
- Foo f = fsm_context;
- int i;
-
- SILC_LOG_DEBUG(("test_st_ninth"));
-
- SILC_LOG_DEBUG(("Creating FSM event"));
- silc_fsm_event_init(&f->sema, fsm);
-
- SILC_LOG_DEBUG(("Creating %d real FSM threads", NUM_THREADS));
- for (i = 0; i < NUM_THREADS; i++) {
- f->threads2[i].rounds = 10;
- f->threads2[i].f = f;
- silc_fsm_event_init(&f->threads2[i].sema, fsm);
- 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);
- }
-
- /** Move to wait threads */
- silc_fsm_next(fsm, test_st_tenth);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_st_tenth)
-{
- Foo f = fsm_context;
- int i;
-
- for (i = 0; i < NUM_THREADS; i++)
- if (f->threads2[i].finished == FALSE) {
- SILC_FSM_EVENT_WAIT(&f->threads2[i].sema);
- f->threads2[i].finished = TRUE;
- }
-
- SILC_LOG_DEBUG(("All %d real threads terminated", NUM_THREADS));
-
- /** Finished successfully */
- silc_fsm_next_later(fsm, test_st_finish, 2, 0);
- return SILC_FSM_WAIT;
-}
-
-SILC_FSM_STATE(test_st_finish)
-{
- SILC_LOG_DEBUG(("test_st_finish"));
-
- SILC_LOG_DEBUG(("Finish machine"));
- return SILC_FSM_FINISH;
-}
-
-static void destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
-{
- Foo f = destructor_context;
- SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
- silc_fsm_free(fsm);
- silc_schedule_stop(f->schedule);
-}
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcSchedule schedule;
- SilcFSM fsm;
- Foo f;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_quick(TRUE);
- silc_log_set_debug_string("*fsm*,*async*");
- }
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(0, NULL);
-
- f = silc_calloc(1, sizeof(*f));
- if (!f)
- goto err;
- f->schedule = schedule;
-
- SILC_LOG_DEBUG(("Allocating FSM context"));
- f->fsm = fsm = silc_fsm_alloc(f, destructor, f, schedule);
- if (!fsm)
- goto err;
- silc_fsm_start(fsm, test_st_start);
-
- SILC_LOG_DEBUG(("Running scheduler"));
- silc_schedule(schedule);
-
- if (f->error)
- goto err;
-
- silc_schedule_uninit(schedule);
- silc_free(f);
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
/* Hash table tests */
-#include "silc.h"
+#include "silcincludes.h"
typedef struct entry_struct {
char name[8];
int val;
} *entry;
-SilcBool dump = FALSE;
-SilcBool auto_rehash = TRUE;
+bool dump = FALSE;
+bool auto_rehash = TRUE;
int count = 2000;
SilcHashTable t = NULL;
return e->val + silc_hash_string(e->name, NULL);
}
-SilcBool hash_compare(void *key1, void *key2, void *user_context)
+bool hash_compare(void *key1, void *key2, void *user_context)
{
entry e = key1;
entry e2 = key2;
silc_free(e);
}
-SilcBool add_entries()
+bool add_entries()
{
entry e;
int i;
e = silc_calloc(1, sizeof(*e));
if (!e)
return FALSE;
- silc_snprintf(e->name, sizeof(e->name), "%d", i);
+ snprintf(e->name, sizeof(e->name), "%d", i);
e->val = i;
silc_hash_table_add(t, (void *)e, (void *)e->name);
return TRUE;
}
-SilcBool del_entries_with_list()
+bool del_entries_with_list()
{
SilcHashTableList htl;
entry e;
silc_hash_table_del(t, key);
}
-SilcBool del_n_entries_foreach()
+bool del_n_entries_foreach()
{
struct entry_struct f;
int i;
for (i = 0; i < count; i++) {
memset(&f, 0, sizeof(f));
- silc_snprintf(f.name, sizeof(f.name), "%d", i);
+ snprintf(f.name, sizeof(f.name), "%d", i);
f.val = i;
silc_hash_table_find_foreach(t, &f, del_foreach, NULL);
return TRUE;
}
-SilcBool del_entries_foreach()
+bool del_entries_foreach()
{
SILC_LOG_DEBUG(("Deleting all entries with foreach"));
silc_hash_table_foreach(t, del_foreach, NULL);
return TRUE;
}
-SilcBool alloc_table()
+bool alloc_table()
{
SILC_LOG_DEBUG(("Allocating hash table with %d entries (%s)",
count, auto_rehash ? "auto rehash" : "no auto rehash"));
return TRUE;
}
-SilcBool delete_table_with_list()
+bool delete_table_with_list()
{
SILC_LOG_DEBUG(("Deleting entries with SilcHashTableList"));
return TRUE;
}
-SilcBool find_entries()
+bool find_entries()
{
struct entry_struct f;
entry e;
for (i = 0; i < count; i++) {
memset(&f, 0, sizeof(f));
- silc_snprintf(f.name, sizeof(f.name), "%d", i);
+ snprintf(f.name, sizeof(f.name), "%d", i);
f.val = i;
/* Find */
return TRUE;
}
-SilcBool dump_table()
+bool dump_table()
{
SilcHashTableList htl;
entry e;
char *name;
- SilcBool dumpped = FALSE;
+ bool dumpped = FALSE;
SILC_LOG_DEBUG(("Dumping hash table entries"));
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
int i;
if (argc > 1 && !strcmp(argv[1], "-d")) {
silc_log_debug(TRUE);
silc_log_debug_hexdump(TRUE);
- silc_log_quick(TRUE);
silc_log_set_debug_string("*table*");
}
auto_rehash = TRUE;
if (!alloc_table())
goto err;
- count = 17999;
+ count = 3999;
if (!add_entries())
goto err;
SILC_LOG_DEBUG(("rehash"));
/* SilcList tests */
-#include "silc.h"
+#include "silcincludes.h"
struct foo {
int i;
struct foo *next;
- struct foo *prev;
};
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
SilcList list;
- struct foo *f, *f1, *f2, *f3, *f4;
+ struct foo *f, *f1, *f2, *f3;
if (argc > 1 && !strcmp(argv[1], "-d")) {
silc_log_debug(TRUE);
silc_log_set_debug_string("*list*");
}
- silc_list_init_prev(list, struct foo, next, prev);
+ silc_list_init(list, struct foo, next);
f1 = silc_calloc(1, sizeof(*f1));
if (!f1)
goto err;
if (!f3)
goto err;
f3->i = 3;
- f4 = silc_calloc(1, sizeof(*f4));
- if (!f4)
- goto err;
- f4->i = 4;
- SILC_LOG_DEBUG(("Add one entry"));
- silc_list_add(list, f1);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
- }
- SILC_LOG_DEBUG(("Delete the entry"));
- silc_list_del(list, f1);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END)
- goto err;
- SILC_LOG_DEBUG(("head=%p", list.head));
- SILC_LOG_DEBUG(("Re-add the entry"));
- silc_list_add(list, f1);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
- }
- SILC_LOG_DEBUG(("Delete the entry"));
- silc_list_del(list, f1);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END)
- goto err;
-
- SILC_LOG_DEBUG(("insert f4=%p at head"));
- silc_list_insert(list, NULL, f4);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
- }
-
- SILC_LOG_DEBUG(("Deleting f4=%p", f4));
- silc_list_del(list, f4);
-
- SILC_LOG_DEBUG(("Add f1, f2, f3"));
silc_list_add(list, f1);
silc_list_add(list, f2);
silc_list_add(list, f3);
silc_list_start(list);
while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
- }
-
- SILC_LOG_DEBUG(("insert f4=%p between f1=%p and f2=%p", f4, f1, f2));
- silc_list_insert(list, f1, f4);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
- }
-
- SILC_LOG_DEBUG(("Deleting f4=%p", f4));
- silc_list_del(list, f4);
-
- SILC_LOG_DEBUG(("insert f4=%p between f3=%p and tail", f4, f3));
- silc_list_insert(list, f3, f4);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
- }
-
- SILC_LOG_DEBUG(("Deleting f4=%p", f4));
- silc_list_del(list, f4);
-
- SILC_LOG_DEBUG(("insert f4=%p at head"));
- silc_list_insert(list, NULL, f4);
- silc_list_start(list);
- while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
+ SILC_LOG_DEBUG(("entry %d, %p, next=%p", f->i, f, f->next));
}
silc_list_start(list);
silc_list_del(list, f1);
while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
+ SILC_LOG_DEBUG(("entry %d, %p, next=%p", f->i, f, f->next));
}
silc_list_del(list, f3);
while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
+ SILC_LOG_DEBUG(("entry %d, %p, next=%p", f->i, f, f->next));
}
silc_list_del(list, f2);
while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
+ SILC_LOG_DEBUG(("entry %d, %p, next=%p", f->i, f, f->next));
}
silc_list_add(list, f1);
silc_list_start(list);
while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
+ SILC_LOG_DEBUG(("entry %d, %p, next=%p", f->i, f, f->next));
}
silc_list_del(list, f2);
silc_list_start(list);
while ((f = silc_list_get(list)) != SILC_LIST_END) {
- SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
- f->prev));
+ SILC_LOG_DEBUG(("entry %d, %p, next=%p", f->i, f, f->next));
}
success = TRUE;
/* SilcMime tests */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcmime.h"
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
SilcMime mime, part, part2;
SilcMimeAssembler ass;
int i;
silc_log_set_debug_string("*mime*");
}
- /*
- * Simple MIME test
- */
+ /* Simple MIME test */
SILC_LOG_DEBUG(("Allocating MIME message context"));
mime = silc_mime_alloc();
if (!mime)
SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
silc_mime_free(mime);
SILC_LOG_DEBUG(("Decoding MIME message"));
- mime = silc_mime_decode(NULL, enc, enc_len);
+ mime = silc_mime_decode(enc, enc_len);
if (!mime)
goto err;
SILC_LOG_DEBUG(("Re-encoding MIME context"));
silc_free(enc);
silc_mime_free(mime);
- /*
- * Empty data area, only headers present
- */
- SILC_LOG_DEBUG(("Allocating MIME message context"));
- mime = silc_mime_alloc();
- if (!mime)
- goto err;
- SILC_LOG_DEBUG(("Adding Content-Transfer-Encoding: binary"));
- silc_mime_add_field(mime, "Content-Transfer-Encoding", "binary");
- SILC_LOG_DEBUG(("No data area, only header present"));
- SILC_LOG_DEBUG(("Encoding MIME context"));
- enc = silc_mime_encode(mime, &enc_len);
- if (!enc)
- goto err;
- SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
- silc_mime_free(mime);
- SILC_LOG_DEBUG(("Decoding MIME message"));
- mime = silc_mime_decode(NULL, enc, enc_len);
- if (!mime)
- goto err;
- SILC_LOG_DEBUG(("Re-encoding MIME context"));
- silc_free(enc);
- enc = silc_mime_encode(mime, &enc_len);
- if (!enc)
- goto err;
- SILC_LOG_HEXDUMP(("Re-encoded MIME message:"), enc, enc_len);
- silc_free(enc);
- silc_mime_free(mime);
-
- /*
- * Multipart test, with nesting
- */
+ /* Multipart test, with nesting */
SILC_LOG_DEBUG(("Allocating MIME message context"));
mime = silc_mime_alloc();
if (!mime)
part = silc_mime_alloc();
if (!part)
goto err;
- SILC_LOG_DEBUG(("Adding MIME data (NO HEADERS), 10 A's + 1 B"));
+ SILC_LOG_DEBUG(("Adding MIME data, 10 A's + 1 B"));
for (i = 0; i < 10; i++)
tmp[i] = 'A';
tmp[10] = 'B';
goto err;
SILC_LOG_DEBUG(("Allocating part"));
part = silc_mime_alloc();
- if (!part)
- goto err;
- SILC_LOG_DEBUG(("Adding Content-Type: image/foobar"));
- SILC_LOG_DEBUG(("No data area, only header"));
- silc_mime_add_field(part, "Content-Type", "image/foobar");
- SILC_LOG_DEBUG(("Adding part to MIME message"));
- if (!silc_mime_add_multipart(mime, part))
- goto err;
- SILC_LOG_DEBUG(("Allocating part"));
- part = silc_mime_alloc();
if (!part)
goto err;
SILC_LOG_DEBUG(("Adding part to MIME message"));
SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
silc_mime_free(mime);
SILC_LOG_DEBUG(("Decoding MIME message"));
- mime = silc_mime_decode(NULL, enc, enc_len);
+ mime = silc_mime_decode(enc, enc_len);
if (!mime)
goto err;
SILC_LOG_DEBUG(("Re-encoding MIME context"));
}
silc_mime_free(mime);
- /*
- * Fragmentation test
- */
+ /* Fragmentation test */
SILC_LOG_DEBUG(("Allocating MIME assembler"));
ass = silc_mime_assembler_alloc();
if (!ass)
goto err;
silc_dlist_start(frag);
while ((buf = silc_dlist_get(frag)) != SILC_LIST_END)
- SILC_LOG_DEBUG(("Fragment \n%s", buf->data, silc_buffer_len(buf)));
+ SILC_LOG_DEBUG(("Fragment \n%s", buf->data, buf->len));
SILC_LOG_DEBUG(("Defragment"));
silc_dlist_start(frag);
while ((buf = silc_dlist_get(frag)) != SILC_LIST_END) {
- part = silc_mime_decode(NULL, buf->data, silc_buffer_len(buf));
+ part = silc_mime_decode(buf->data, buf->len);
if (!silc_mime_is_partial(part))
goto err;
part = silc_mime_assemble(ass, part);
+++ /dev/null
-/* Locking performance tests. Gives locsk&unlocks/second. */
-/* Version 1.0 */
-
-#include "silc.h"
-
-typedef struct {
- SilcThread thread;
- SilcInt64 time;
-} Context;
-
-#define MAX_ROUND 8
-#define MAX_MUL 4
-#define MAX_THREADS 4
-#define MAX_LOCKS 471234567
-
-SilcMutex mutex;
-SilcUInt64 cpu_freq = 0;
-int max_locks, max_locks2;
-
-/* RDTSC */
-#ifdef SILC_I486
-static __inline__ unsigned long long rdtsc(void)
-{
- unsigned long long int x;
- __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
- return x;
-}
-
-#elif SILC_X86_64
-typedef unsigned long long int unsigned long long;
-static __inline__ unsigned long long rdtsc(void)
-{
- unsigned hi, lo;
- __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
- return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
-}
-
-#elif SILC_POWERPC
-typedef unsigned long long int unsigned long long;
-static __inline__ unsigned long long rdtsc(void)
-{
- unsigned long long int result = 0;
- unsigned long int upper, lower,tmp;
- __asm__ volatile(
- "0: \n"
- "\tmftbu %0 \n"
- "\tmftb %1 \n"
- "\tmftbu %2 \n"
- "\tcmpw %2,%0 \n"
- "\tbne 0b \n"
- : "=r"(upper),"=r"(lower),"=r"(tmp)
- );
- result = upper;
- result = result << 32;
- result = result | lower;
-
- return result;
-}
-#endif
-
-void *mutex_thread(void *context)
-{
- Context *c = context;
- SilcInt64 s;
- register int i;
-
- s = rdtsc();
- for (i = 0; i < max_locks; i++) {
- silc_mutex_lock(mutex);
- silc_mutex_unlock(mutex);
- }
- c->time = rdtsc() - s;
- c->time /= cpu_freq;
-
- return NULL;
-}
-
-SilcUInt64 hval;
-SilcUInt64 hval2;
-SilcUInt64 hval3;
-
-void *mutex_thread_hold(void *context)
-{
- Context *c = context;
- SilcInt64 s;
- register int i;
-
- s = rdtsc();
- for (i = 0; i < max_locks / 4; i++) {
- silc_mutex_lock(mutex);
- hval2 = i;
- hval3 = 0;
- hval++;
- hval3 = hval2 + i;
- hval += hval2;
- hval3 += hval;
- if (silc_unlikely(hval3 != hval2 + i + hval)) {
- fprintf(stderr, "MUTEX CORRUPT 1\n");
- exit(1);
- }
- if (silc_unlikely(hval2 != i)) {
- fprintf(stderr, "MUTEX CORRUPT 2 (%llu != %d)\n", hval2, i);
- exit(1);
- }
- silc_mutex_unlock(mutex);
- }
- c->time = rdtsc() - s;
- c->time /= cpu_freq;
-
- return NULL;
-}
-
-int main(int argc, char **argv)
-{
- Context c[MAX_THREADS * MAX_MUL];
- SilcInt64 val;
- int k, i, j, o = 0;
- SilcBool success;
-
- if (argc <= 1) {
- fprintf(stderr, "Usage: ./test_silcmutex <cpu_freq_mhz>\n");
- fprintf(stderr, "Example: ./test_silcmutex 3000\n");
- exit(1);
- }
- cpu_freq = (SilcUInt64)atoi(argv[1]);
- cpu_freq *= 1000; /* Will give us milliseconds */
-
- max_locks = MAX_LOCKS;
-
- fprintf(stderr, "lock/unlock per second\n");
-
- for (j = 0; j < MAX_ROUND; j++) {
- for (i = 0; i < 1; i++)
- c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
-
- val = 0;
- for (i = 0; i < 1; i++) {
- silc_thread_wait(c[i].thread, NULL);
- val += c[i].time;
- }
- fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
- (1000LL * max_locks * 1) / val, 1);
-
- if (o == 0) {
- /* If MAX_LOCKS is too large for this CPU, optimize. We don't want to
- wait a whole day for this test. */
- if ((SilcInt64)(max_locks / 10) >
- (SilcInt64)((1000LL * max_locks) / val))
- max_locks /= 10;
- o = 1;
- }
- }
- puts("");
-
- max_locks2 = max_locks;
- for (k = 0; k < MAX_MUL; k++) {
- sleep(16);
- max_locks = max_locks2 / (k + 1);
- for (j = 0; j < MAX_ROUND; j++) {
- for (i = 0; i < MAX_THREADS * (k + 1); i++)
- c[i].thread = silc_thread_create(mutex_thread, &c[i], TRUE);
-
- val = 0;
- for (i = 0; i < MAX_THREADS * (k + 1); i++) {
- silc_thread_wait(c[i].thread, NULL);
- val += c[i].time;
- }
- fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
- (1000LL * max_locks * (MAX_THREADS * (k + 1))) / val,
- MAX_THREADS * (k + 1));
- }
- puts("");
- }
- max_locks = max_locks2;
-
- fprintf(stderr, "Spinning/holding lock, lock/unlock per second\n");
-
- max_locks /= 2;
- sleep(5);
- for (j = 0; j < MAX_ROUND / 2; j++) {
- for (i = 0; i < 1; i++)
- c[i].thread = silc_thread_create(mutex_thread_hold, &c[i], TRUE);
-
- val = 0;
- for (i = 0; i < 1; i++) {
- silc_thread_wait(c[i].thread, NULL);
- val += c[i].time;
- }
- fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
- (1000LL * (max_locks / 4) * 1) / val, 1);
- }
- puts("");
-
- max_locks2 = max_locks;
- max_locks2 /= 2;
- for (k = 0; k < MAX_MUL; k++) {
- sleep(2);
- max_locks = max_locks2 / (k + 1);
- for (j = 0; j < MAX_ROUND / 2; j++) {
- hval = hval2 = 1;
- for (i = 0; i < MAX_THREADS * (k + 1); i++)
- c[i].thread = silc_thread_create(mutex_thread_hold, &c[i], TRUE);
-
- val = 0;
- for (i = 0; i < MAX_THREADS * (k + 1); i++) {
- silc_thread_wait(c[i].thread, NULL);
- val += c[i].time;
- }
- fprintf(stderr, "%llu mutex lock/unlock per second (%d threads)\n",
- (1000LL * (max_locks / 4) *
- (MAX_THREADS * (k + 1))) / val,
- MAX_THREADS * (k + 1));
- }
- puts("");
- }
-
- success = TRUE;
-
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
+++ /dev/null
-/* SILC Net API tests */
-
-#include "silc.h"
-
-SilcSchedule schedule;
-
-typedef struct {
- SilcFSM fsm;
- SilcFSMEventStruct sema;
- SilcFSMThreadStruct thread;
- SilcNetListener server;
- SilcStream client_stream;
- SilcNetStatus client_status;
- SilcStream server_stream;
- SilcNetStatus server_status;
- SilcBool success;
-} *Foo;
-
-SILC_FSM_STATE(test_st_start);
-SILC_FSM_STATE(test_st_second);
-SILC_FSM_STATE(test_st_finish);
-
-SILC_FSM_STATE(test_st_connect);
-SILC_FSM_STATE(test_st_connected);
-
-static void test_accept_connection(SilcNetStatus status, SilcStream stream,
- void *context)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("Accepted new connection"));
- f->client_status = status;
- f->client_stream = stream;
- SILC_FSM_EVENT_SIGNAL(&f->sema);
-}
-
-static void test_connected(SilcNetStatus status, SilcStream stream,
- void *context)
-{
- Foo f = context;
- SILC_LOG_DEBUG(("Connected to server"));
- f->server_status = status;
- f->server_stream = stream;
- SILC_FSM_CALL_CONTINUE(&f->thread);
-}
-
-SILC_FSM_STATE(test_st_connect)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_st_connect"));
- SILC_LOG_DEBUG(("Connecting to server"));
-
- silc_fsm_next(fsm, test_st_connected);
- SILC_FSM_CALL(silc_net_tcp_connect(NULL, "localhost", 5000,
- silc_fsm_get_schedule(fsm),
- test_connected, f));
-}
-
-SILC_FSM_STATE(test_st_connected)
-{
- Foo f = fsm_context;
- const char *host, *ip;
- SilcUInt16 port;
-
- SILC_LOG_DEBUG(("test_st_connected"));
-
- if (f->server_status != SILC_NET_OK) {
- SILC_LOG_DEBUG(("Creating connection failed"));
- return SILC_FSM_FINISH;
- }
-
- silc_socket_stream_get_info(f->server_stream, NULL, &host, &ip, &port);
- SILC_LOG_DEBUG(("Connected to server %s, %s:%d", host, ip, port));
-
- return SILC_FSM_FINISH;
-}
-
-SILC_FSM_STATE(test_st_start)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_st_start"));
-
- SILC_LOG_DEBUG(("Creating network listener"));
- f->server = silc_net_tcp_create_listener(NULL, 0, 5000, TRUE, TRUE,
- silc_fsm_get_schedule(fsm),
- test_accept_connection, f);
- if (!f->server) {
- /** Creating network listener failed */
- SILC_LOG_DEBUG(("Listener creation failed"));
- silc_fsm_next(fsm, test_st_finish);
- 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);
-
- /** Start waiting connection */
- SILC_LOG_DEBUG(("Start waiting for incoming connections"));
- silc_fsm_event_init(&f->sema, fsm);
- silc_fsm_next(fsm, test_st_second);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(test_st_second)
-{
- Foo f = fsm_context;
- const char *ip, *host;
- SilcUInt16 port;
-
- SILC_LOG_DEBUG(("test_st_second"));
-
- SILC_FSM_EVENT_WAIT(&f->sema);
-
- 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);
- return SILC_FSM_CONTINUE;
- }
-
- silc_socket_stream_get_info(f->client_stream, NULL, &host, &ip, &port);
- SILC_LOG_DEBUG(("Accepted new connection %s, %s:%d", host, ip, port));
-
- /** Wait thread to terminate */
- f->success = TRUE;
- silc_fsm_next(fsm, test_st_finish);
- SILC_FSM_THREAD_WAIT(&f->thread);
-}
-
-SILC_FSM_STATE(test_st_finish)
-{
- Foo f = fsm_context;
-
- SILC_LOG_DEBUG(("test_st_finish"));
-
- if (f->server_stream) {
- silc_stream_close(f->server_stream);
- silc_stream_destroy(f->server_stream);
- }
- if (f->client_stream) {
- silc_stream_close(f->client_stream);
- silc_stream_destroy(f->client_stream);
- }
-
- SILC_LOG_DEBUG(("Closing network listener"));
- silc_net_close_listener(f->server);
-
- SILC_LOG_DEBUG(("Finish machine"));
- return SILC_FSM_FINISH;
-}
-
-static void destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
-{
- SILC_LOG_DEBUG(("FSM destructor, stopping scheduler"));
- silc_fsm_free(fsm);
- silc_schedule_stop(schedule);
-}
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcFSM fsm;
- Foo f;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*net*,*stream*");
- }
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(0, NULL);
-
- f = silc_calloc(1, sizeof(*f));
- if (!f)
- goto err;
-
- SILC_LOG_DEBUG(("Allocating FSM context"));
- fsm = silc_fsm_alloc(f, destructor, NULL, schedule);
- if (!fsm)
- goto err;
- silc_fsm_start(fsm, test_st_start);
- f->fsm = fsm;
-
- SILC_LOG_DEBUG(("Running scheduler"));
- silc_schedule(schedule);
-
- if (!f->success)
- goto err;
-
- silc_schedule_uninit(schedule);
- silc_free(f);
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
+++ /dev/null
-/* SilcSchedule tests */
-
-#include "silc.h"
-
-typedef void (*Callback)(void *context);
-
-#define NUM_TTASK 200
-#ifdef FD_SETSIZE
-#define NUM_FTASK FD_SETSIZE
-#else
-#define NUM_FTASK 250
-#endif
-
-SilcSchedule schedule;
-
-SILC_TASK_CALLBACK(foo)
-{
-
-}
-
-SILC_TASK_CALLBACK(timeout)
-{
- int i = (int)context;
- SILC_LOG_DEBUG(("Timeout task %d", i));
-}
-
-SILC_TASK_CALLBACK(cont2)
-{
-#ifdef SILC_DEBUG
- silc_schedule_stats(schedule);
-#endif /* SILC_DEBUG */
-
- 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(cont)
-{
- int i;
-
-#ifdef SILC_DEBUG
- silc_schedule_stats(schedule);
-#endif /* SILC_DEBUG */
-
- SILC_LOG_DEBUG(("Adding %d timeout tasks", NUM_TTASK / 3));
- for (i = 0; i < NUM_TTASK / 3; i++)
- silc_schedule_task_add_timeout(schedule, timeout, (void *)i, 0, 0);
-
- silc_schedule_task_add_timeout(schedule, cont2, (void *)i, 0, 100);
-}
-
-SILC_TASK_CALLBACK(start)
-{
- int i;
-
- 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,
- 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);
-}
-
-SILC_TASK_CALLBACK(interrupt)
-{
- SILC_LOG_DEBUG(("SIGINT signal"));
- silc_schedule_stop(schedule);
-}
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_quick(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*sched*,*hash*");
- }
-
- SILC_LOG_DEBUG(("Allocating scheduler"));
- schedule = silc_schedule_init(NUM_FTASK, NULL);
- if (!schedule)
- goto err;
-
- silc_schedule_task_add_signal(schedule, SIGINT, interrupt, NULL);
-
- silc_schedule_task_add_timeout(schedule, start, NULL, 1, 0);
-
- SILC_LOG_DEBUG(("Running scheduler"));
- silc_schedule(schedule);
-
- 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;
-}
+++ /dev/null
-/* SilcStack tests */
-
-#include "silc.h"
-
-#define NUM_ALLS 300
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcStack stack;
- void *ptr, *ptr2;
- int i;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_quick(TRUE);
- silc_log_set_debug_string("*stack*");
- }
-
- SILC_LOG_DEBUG(("Allocating stack of default size (1024 bytes)"));
- stack = silc_stack_alloc(0);
- if (!stack)
- goto err;
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Allocating 2048 bytes from stack"));
- ptr = silc_smalloc(stack, 2048);
- if (!ptr)
- goto err;
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Freeing the stack"));
- silc_stack_free(stack);
-
- SILC_LOG_DEBUG(("Allocating stack of default size (1024 bytes)"));
- stack = silc_stack_alloc(0);
- if (!stack)
- goto err;
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Pushing and allocating %d times", NUM_ALLS));
- if (!silc_stack_push(stack, NULL))
- goto err;
- for (i = 0; i < NUM_ALLS; i++) {
- ptr2 = silc_smalloc(stack, (i + 1) * 7);
- if (!ptr2)
- goto err;
- }
- silc_stack_stats(stack);
- silc_stack_pop(stack);
- SILC_LOG_DEBUG(("Popping"));
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Pushing and allocating %d times", NUM_ALLS));
- if (!silc_stack_push(stack, NULL))
- goto err;
- for (i = 0; i < NUM_ALLS; i++) {
- ptr2 = silc_smalloc(stack, (i + 1) * 7);
- if (!ptr2)
- goto err;
- }
- silc_stack_stats(stack);
- silc_stack_pop(stack);
- SILC_LOG_DEBUG(("Popping"));
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Pushing %d times", NUM_ALLS / 2));
- for (i = 0; i < NUM_ALLS / 2; i++) {
- if (!silc_stack_push(stack, NULL))
- goto err;
- ptr2 = silc_smalloc(stack, (i + 1) * 7);
- if (!ptr2)
- goto err;
- }
- silc_stack_stats(stack);
- SILC_LOG_DEBUG(("Popping %d times", NUM_ALLS / 2));
- for (i = 0; i < NUM_ALLS / 2; i++)
- silc_stack_pop(stack);
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Pushing and reallocating %d times", NUM_ALLS / 10));
- ptr2 = NULL;
- if (!silc_stack_push(stack, NULL))
- goto err;
- for (i = 0; i < NUM_ALLS / 10; i++) {
- ptr2 = silc_srealloc(stack, (i * 7), ptr2, (i + 1) * 7);
- if (!ptr2)
- goto err;
- }
- silc_stack_stats(stack);
- silc_stack_pop(stack);
- SILC_LOG_DEBUG(("Popping"));
- silc_stack_stats(stack);
-
- SILC_LOG_DEBUG(("Freeing the stack"));
- silc_stack_free(stack);
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
/* Stringprep tests */
-#include "silc.h"
+#include "silcincludes.h"
typedef struct {
const char *comment;
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
int i, enc;
unsigned char *out = NULL;
SilcUInt32 out_len;
if (argc > 1 && !strcmp(argv[1], "-d")) {
silc_log_debug(TRUE);
silc_log_debug_hexdump(TRUE);
- silc_log_quick(TRUE);
silc_log_set_debug_string("*stringprep*,*utf8*");
}
/* UTF-8 decoding tests */
-/* Other string util tests too */
-#include "silc.h"
+#include "silcincludes.h"
#define utf8fail(n, data, len) \
const unsigned char u##n[] = (data); \
int main(int argc, char **argv)
{
- SilcBool success = FALSE;
+ bool success = FALSE;
unsigned char *s1, *s2, *s3, *s4;
int l, opt;
case 'd':
silc_log_debug(TRUE);
silc_log_debug_hexdump(TRUE);
- silc_log_quick(TRUE);
if (optarg)
silc_log_set_debug_string(optarg);
else
silc_free(s3);
silc_free(s4);
- /* Regex test */
- SILC_LOG_DEBUG(("Simple regex test"));
- s1 = "foo,bar,silc,com";
- SILC_LOG_DEBUG(("Find 'silc' from %s", s1));
- if (!silc_string_match(s1, "silc"))
- goto err;
- SILC_LOG_DEBUG(("Regex match"));
- SILC_LOG_DEBUG(("Find 'foobar' from %s", s1));
- if (silc_string_match(s1, "foobar"))
- goto err;
- SILC_LOG_DEBUG(("Regex not found (Ok)"));
-
success = TRUE;
err:
+++ /dev/null
-/* SilcTime tests */
-
-#include "silc.h"
-
-int main(int argc, char **argv)
-{
- SilcBool success = FALSE;
- SilcTimeStruct curtime;
-
- if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_log_debug(TRUE);
- silc_log_quick(TRUE);
- silc_log_debug_hexdump(TRUE);
- silc_log_set_debug_string("*time*");
- }
-
- SILC_LOG_DEBUG(("Get current time"));
- if (!silc_time_value(0, &curtime))
- goto err;
- SILC_LOG_DEBUG(("year : %d", curtime.year));
- SILC_LOG_DEBUG(("month : %d", curtime.month));
- SILC_LOG_DEBUG(("day : %d", curtime.day));
- SILC_LOG_DEBUG(("hour : %d", curtime.hour));
- SILC_LOG_DEBUG(("minute : %d", curtime.minute));
- SILC_LOG_DEBUG(("msecond : %d", curtime.msecond));
- SILC_LOG_DEBUG(("utc_hour : %d", curtime.utc_hour));
- SILC_LOG_DEBUG(("utc_min : %d", curtime.utc_minute));
- SILC_LOG_DEBUG(("utc_east : %d", curtime.utc_east));
- SILC_LOG_DEBUG(("dst : %d", curtime.dst));
-
- success = TRUE;
-
- err:
- SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
- fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
-
- return success;
-}
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2001 - 2006 Pekka Riikonen
+# Copyright (C) 2001 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
silcunixschedule.c \
silcunixnet.c \
silcunixutil.c \
- silcunixsocketstream.c \
+ silcunixsockconn.c \
+ silcunixmutex.c \
silcunixthread.c
include $(top_srcdir)/Makefile.defines.in
--- /dev/null
+/*
+
+ silcunixmutex.c
+
+ 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
+ GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+
+/* SILC Mutex structure */
+struct SilcMutexStruct {
+#ifdef SILC_THREADS
+ pthread_mutex_t mutex;
+ unsigned int locked : 1;
+#else
+ void *tmp;
+#endif /* SILC_THREADS */
+};
+
+bool silc_mutex_alloc(SilcMutex *mutex)
+{
+#ifdef SILC_THREADS
+ *mutex = silc_calloc(1, sizeof(**mutex));
+ if (*mutex == NULL)
+ return FALSE;
+ pthread_mutex_init(&(*mutex)->mutex, NULL);
+#endif /* SILC_THREADS */
+ return TRUE;
+}
+
+void silc_mutex_free(SilcMutex mutex)
+{
+#ifdef SILC_THREADS
+ if (mutex) {
+ pthread_mutex_destroy(&mutex->mutex);
+ silc_free(mutex);
+ }
+#endif /* SILC_THREADS */
+}
+
+void silc_mutex_lock(SilcMutex mutex)
+{
+#ifdef SILC_THREADS
+ if (mutex) {
+ if (pthread_mutex_lock(&mutex->mutex))
+ assert(FALSE);
+ assert(mutex->locked == 0);
+ mutex->locked = 1;
+ }
+#endif /* SILC_THREADS */
+}
+
+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);
+ }
+#endif /* SILC_THREADS */
+}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcnet.h"
#ifdef HAVE_IPV6
#endif
} SilcSockaddr;
-static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
- int port)
+static bool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
+ int port)
{
int len;
if (silc_net_is_ip4(ip_addr)) {
/* IPv4 address */
len = sizeof(addr->sin.sin_addr);
- silc_net_addr2bin(ip_addr,
+ silc_net_addr2bin(ip_addr,
(unsigned char *)&addr->sin.sin_addr.s_addr, len);
addr->sin.sin_family = AF_INET;
addr->sin.sin_port = port ? htons(port) : 0;
#ifdef HAVE_IPV6
/* IPv6 address */
len = sizeof(addr->sin6.sin6_addr);
- silc_net_addr2bin(ip_addr,
+ silc_net_addr2bin(ip_addr,
(unsigned char *)&addr->sin6.sin6_addr, len);
addr->sin6.sin6_family = AF_INET6;
addr->sin6.sin6_port = port ? htons(port) : 0;
return TRUE;
}
-/* Deliver new stream to upper layer */
-
-static void silc_net_accept_stream(SilcSocketStreamStatus status,
- SilcStream stream, void *context)
-{
- SilcNetListener listener = context;
-
- if (status != SILC_SOCKET_OK)
- return;
-
- listener->callback(SILC_NET_OK, stream, listener->context);
-}
-
-/* Accept incoming connection and notify upper layer */
-
-SILC_TASK_CALLBACK(silc_net_accept)
-{
- SilcNetListener listener = context;
- int sock;
-
- SILC_LOG_DEBUG(("Accepting new connection"));
-
- sock = silc_net_accept_connection(fd);
- if (sock < 0)
- return;
-
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* Create socket stream */
- silc_socket_tcp_stream_create(sock, listener->lookup,
- listener->require_fqdn, schedule,
- silc_net_accept_stream, listener);
-}
-
-/* Create TCP network listener */
-
-SilcNetListener
-silc_net_tcp_create_listener(const char **local_ip_addr,
- SilcUInt32 local_ip_count, int port,
- SilcBool lookup, SilcBool require_fqdn,
- SilcSchedule schedule,
- SilcNetCallback callback, void *context)
-{
- SilcNetListener listener = NULL;
- SilcSockaddr server;
- int i, sock, rval;
- const char *ipany = "0.0.0.0";
-
- SILC_LOG_DEBUG(("Creating TCP listener"));
-
- if (port < 0 || !schedule || !callback)
- goto err;
-
- listener = silc_calloc(1, sizeof(*listener));
- if (!listener) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
- listener->schedule = schedule;
- listener->callback = callback;
- listener->context = context;
- listener->require_fqdn = require_fqdn;
- listener->lookup = lookup;
-
- if (local_ip_count > 0) {
- listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
- if (!listener->socks) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
- } else {
- listener->socks = silc_calloc(1, sizeof(*listener->socks));
- if (!listener->socks) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
-
- local_ip_count = 1;
- }
-
- /* Bind to local addresses */
- for (i = 0; i < local_ip_count; i++) {
- SILC_LOG_DEBUG(("Binding to local address %s",
- local_ip_addr ? local_ip_addr[i] : ipany));
-
- /* Set sockaddr for server */
- if (!silc_net_set_sockaddr(&server,
- local_ip_addr ? local_ip_addr[i] : ipany,
- port))
- goto err;
-
- /* Create the socket */
- sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
- if (sock < 0) {
- SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
- goto err;
- }
-
- /* Set the socket options */
- rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
- if (rval < 0) {
- SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
- goto err;
- }
-
- /* Bind the listener socket */
- rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
- if (rval < 0) {
- SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
- goto err;
- }
-
- /* Specify that we are listenning */
- rval = listen(sock, 64);
- if (rval < 0) {
- SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
- goto err;
- }
-
- /* Set the server socket to non-blocking mode */
- silc_net_set_socket_nonblock(sock);
-
- /* Schedule for incoming connections */
- silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
-
- SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
- listener->socks[i] = sock;
- listener->socks_count++;
- }
-
- return listener;
-
- err:
- if (callback)
- callback(SILC_NET_ERROR, NULL, context);
- if (listener)
- silc_net_close_listener(listener);
- return NULL;
-}
-
-/* Close network listener */
-
-void silc_net_close_listener(SilcNetListener listener)
-{
- int i;
-
- SILC_LOG_DEBUG(("Closing network listener"));
-
- for (i = 0; i < listener->socks_count; i++) {
- silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]);
- shutdown(listener->socks[i], 2);
- close(listener->socks[i]);
- }
-
- silc_free(listener->socks);
- silc_free(listener);
-}
-
-/* Create UDP stream */
+/* This function creates server or daemon or listener or what ever. This
+ does not fork a new process, it must be done by the caller if caller
+ wants to create a child process. This is used by the SILC server.
+ If argument `ip_addr' is NULL `any' address will be used. Returns
+ the created socket or -1 on error. */
-SilcStream
-silc_net_udp_connect(const char *local_ip_addr, int local_port,
- const char *remote_ip_addr, int remote_port,
- SilcSchedule schedule)
+int silc_net_create_server(int port, const char *ip_addr)
{
- SilcStream stream;
+ int sock, rval;
SilcSockaddr server;
- int sock = -1, rval;
- const char *ipany = "0.0.0.0";
-
- SILC_LOG_DEBUG(("Creating UDP stream"));
- if (!schedule)
- goto err;
-
- /* Bind to local addresses */
- SILC_LOG_DEBUG(("Binding to local address %s",
- local_ip_addr ? local_ip_addr : ipany));
+ SILC_LOG_DEBUG(("Creating a new server listener"));
/* Set sockaddr for server */
- if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany,
- local_port))
- goto err;
+ if (!silc_net_set_sockaddr(&server, ip_addr, port))
+ return -1;
/* Create the socket */
- sock = socket(server.sin.sin_family, SOCK_DGRAM, 0);
+ sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
if (sock < 0) {
SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
- goto err;
+ return -1;
}
/* Set the socket options */
rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
if (rval < 0) {
SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
- goto err;
+ return -1;
}
-#ifdef SO_REUSEPORT
- rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1);
- if (rval < 0) {
- SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
- goto err;
- }
-#endif /* SO_REUSEPORT */
- /* Bind the listener socket */
+ /* Bind the server socket */
rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
if (rval < 0) {
SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
- goto err;
+ return -1;
+ }
+
+ /* Specify that we are listenning */
+ rval = listen(sock, 5);
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
+ return -1;
}
- /* Set socket to non-blocking mode */
+ /* Set the server socket to non-blocking mode */
silc_net_set_socket_nonblock(sock);
- /* Set to connected state if remote address is provided. */
- if (remote_ip_addr && remote_port) {
- if (!silc_net_set_sockaddr(&server, remote_ip_addr, remote_port))
- goto err;
+ SILC_LOG_DEBUG(("Server listener created, fd=%d", sock));
- rval = connect(sock, &server.sa, SIZEOF_SOCKADDR(server));
- if (rval < 0) {
- SILC_LOG_DEBUG(("Cannot connect UDP stream: %s", strerror(errno)));
- goto err;
- }
- }
-
- /* Set send and receive buffer size */
-#ifdef SO_SNDBUF
- rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 65535);
- if (rval < 0) {
- SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
- goto err;
- }
-#endif /* SO_SNDBUF */
-#ifdef SO_RCVBUF
- rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 65535);
- if (rval < 0) {
- SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
- goto err;
- }
-#endif /* SO_RCVBUF */
+ return sock;
+}
- /* Encapsulate into socket stream */
- stream =
- silc_socket_udp_stream_create(sock, local_ip_addr ?
- silc_net_is_ip6(local_ip_addr) : FALSE,
- remote_ip_addr ? TRUE : FALSE, schedule);
- if (!stream)
- goto err;
+/* Closes the server by closing the socket connection. */
- SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
- return stream;
+void silc_net_close_server(int sock)
+{
+ shutdown(sock, 2);
+ close(sock);
- err:
- if (sock != -1)
- close(sock);
- return NULL;
+ SILC_LOG_DEBUG(("Server socket closed"));
}
-/* Receive UDP packet */
+/* Creates a connection (TCP/IP) to a remote host. Returns the connection
+ socket or -1 on error. This blocks the process while trying to create
+ the connection. */
-int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
- SilcUInt32 remote_ip_addr_size, int *remote_port,
- unsigned char *ret_data, SilcUInt32 data_size)
+int silc_net_create_connection(const char *local_ip, int port,
+ const char *host)
{
- SilcSocketStream sock = stream;
- SilcSockaddr s;
- struct sockaddr *from;
- int len, flen;
+ int sock, rval;
+ char ip_addr[64];
+ SilcSockaddr desthost;
+ bool prefer_ipv6 = TRUE;
- SILC_LOG_DEBUG(("Reading data from UDP socket %d", sock->sock));
+ SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port));
- if (remote_ip_addr && remote_port) {
- if (sock->ipv6) {
- from = (struct sockaddr *)&s.sin6;
- flen = sizeof(s.sin6);
- } else {
- from = (struct sockaddr *)&s.sin;
- flen = sizeof(s.sin);
- }
- len = recvfrom(sock->sock, ret_data, data_size, 0, from, &flen);
- } else
- len = recv(sock->sock, ret_data, data_size, 0);
-
- if (len < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ, FALSE);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot read from UDP socket: %d:%s",
- sock->sock, strerror(errno)));
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- sock->sock_error = errno;
- return -2;
+ /* Do host lookup */
+ retry:
+ if (!silc_net_gethostbyname(host, prefer_ipv6, ip_addr, sizeof(ip_addr))) {
+ SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
+ "IP address", host));
+ return -1;
}
- SILC_LOG_DEBUG(("Read %d bytes", len));
-
- if (!len)
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
+ /* Set sockaddr for this connection */
+ if (!silc_net_set_sockaddr(&desthost, ip_addr, port))
+ return -1;
- /* Return remote address */
- if (remote_ip_addr && remote_port) {
- if (sock->ipv6) {
- *remote_port = ntohs(s.sin6.sin6_port);
- inet_ntop(AF_INET6, &s.sin6.sin6_addr, remote_ip_addr,
- remote_ip_addr_size);
- } else {
- *remote_port = ntohs(s.sin.sin_port);
- inet_ntop(AF_INET, &s.sin.sin_addr, remote_ip_addr,
- remote_ip_addr_size);
+ /* Create the connection socket */
+ sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0);
+ if (sock < 0) {
+ /* If address is IPv6, then fallback to IPv4 and see whether we can do
+ better with that on socket creation. */
+ if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) {
+ prefer_ipv6 = FALSE;
+ goto retry;
}
- SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
+ SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+ return -1;
}
- return len;
-}
+ /* Bind to the local address if provided */
+ if (local_ip) {
+ SilcSockaddr local;
-/* Send UDP packet */
+ /* Set sockaddr for local listener, and try to bind it. */
+ if (silc_net_set_sockaddr(&local, local_ip, 0))
+ bind(sock, &local.sa, SIZEOF_SOCKADDR(local));
+ }
-int silc_net_udp_send(SilcStream stream,
- const char *remote_ip_addr, int remote_port,
- const unsigned char *data, SilcUInt32 data_len)
-{
- SilcSocketStream sock = stream;
- SilcSockaddr remote;
- int ret;
-
- SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock));
-
- /* Set sockaddr */
- if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
- return -2;
-
- /* Send */
- ret = sendto(sock->sock, data, data_len, 0, &remote.sa,
- SIZEOF_SOCKADDR(remote));
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not send immediately, will do it later"));
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
- return -1;
+ /* Connect to the host */
+ rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost));
+ if (rval < 0) {
+ /* retry using an IPv4 adress, if IPv6 didn't work */
+ if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) {
+ shutdown(sock, 2);
+ close(sock);
+
+ prefer_ipv6 = FALSE;
+ goto retry;
}
- SILC_LOG_DEBUG(("Cannot send to UDP socket: %s", strerror(errno)));
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- sock->sock_error = errno;
- return -2;
+ SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
+ shutdown(sock, 2);
+ close(sock);
+ return -1;
}
- SILC_LOG_DEBUG(("Sent data %d bytes", ret));
- if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
- SILC_TASK_WRITE)
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ, FALSE);
+ /* Set appropriate options */
+#if defined(TCP_NODELAY)
+ silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+#endif
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
- return ret;
-}
+ SILC_LOG_DEBUG(("Connection created"));
-/* Asynchronous TCP/IP connecting */
-
-typedef struct {
- SilcNetStatus status;
- SilcSocketStreamStatus stream_status;
- SilcStream stream;
- SilcFSMStruct fsm;
- SilcFSMEventStruct event;
- SilcAsyncOperation op;
- SilcAsyncOperation sop;
- char *local_ip;
- char *remote;
- char ip_addr[64];
- int sock;
- SilcNetCallback callback;
- void *context;
- unsigned int port : 24;
- unsigned int retry : 7;
- unsigned int aborted : 1;
-} *SilcNetConnect;
-
-SILC_FSM_STATE(silc_net_connect_st_start);
-SILC_FSM_STATE(silc_net_connect_st_connected);
-SILC_FSM_STATE(silc_net_connect_st_stream);
-SILC_FSM_STATE(silc_net_connect_st_finish);
-
-SILC_TASK_CALLBACK(silc_net_connect_wait)
-{
- SilcNetConnect conn = context;
- SILC_FSM_EVENT_SIGNAL(&conn->event);
+ return sock;
}
-SILC_FSM_STATE(silc_net_connect_st_start)
+/* Creates a connection (TCP/IP) to a remote host. Returns the connection
+ socket or -1 on error. This creates non-blocking socket hence the
+ connection returns directly. To get the result of the connect() one
+ must select() the socket and read the result after it's ready. */
+
+int silc_net_create_connection_async(const char *local_ip, int port,
+ const char *host)
{
- SilcNetConnect conn = fsm_context;
int sock, rval;
+ char ip_addr[64];
SilcSockaddr desthost;
- SilcBool prefer_ipv6 = TRUE;
+ bool prefer_ipv6 = TRUE;
- if (conn->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
- }
+ SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d",
+ host, port));
/* Do host lookup */
retry:
- if (!silc_net_gethostbyname(conn->remote, prefer_ipv6,
- conn->ip_addr, sizeof(conn->ip_addr))) {
+ if (!silc_net_gethostbyname(host, prefer_ipv6, ip_addr, sizeof(ip_addr))) {
SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
- "host", conn->remote));
-
- /** Network unreachable */
- conn->status = SILC_NET_HOST_UNREACHABLE;
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
+ "IP address", host));
+ return -1;
}
/* Set sockaddr for this connection */
- if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port)) {
- /** Sockaddr failed */
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
- }
+ if (!silc_net_set_sockaddr(&desthost, ip_addr, port))
+ return -1;
/* Create the connection socket */
sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0);
if (sock < 0) {
/* If address is IPv6, then fallback to IPv4 and see whether we can do
better with that on socket creation. */
- if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
+ if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) {
prefer_ipv6 = FALSE;
goto retry;
}
- /** Cannot create socket */
SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
+ return -1;
}
/* Bind to the local address if provided */
- if (conn->local_ip) {
+ if (local_ip) {
SilcSockaddr local;
/* Set sockaddr for local listener, and try to bind it. */
- if (silc_net_set_sockaddr(&local, conn->local_ip, 0))
+ if (silc_net_set_sockaddr(&local, local_ip, 0))
bind(sock, &local.sa, SIZEOF_SOCKADDR(local));
}
/* Connect to the host */
rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost));
if (rval < 0) {
- if (errno != EINPROGRESS) {
+ if (errno != EINPROGRESS) {
/* retry using an IPv4 adress, if IPv6 didn't work */
- if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
+ if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) {
shutdown(sock, 2);
close(sock);
goto retry;
}
+ SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
shutdown(sock, 2);
close(sock);
-
- /** Cannot connect to remote host */
- SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
+ return -1;
}
}
SILC_LOG_DEBUG(("Connection operation in progress"));
- conn->sock = sock;
-
- /** Wait for connection */
- silc_fsm_next(fsm, silc_net_connect_st_connected);
- silc_fsm_event_init(&conn->event, fsm);
- silc_schedule_task_add_fd(silc_fsm_get_schedule(fsm), sock,
- silc_net_connect_wait, conn);
- silc_schedule_set_listen_fd(silc_fsm_get_schedule(fsm), sock,
- SILC_TASK_WRITE, FALSE);
- SILC_FSM_EVENT_WAIT(&conn->event);
- return SILC_FSM_CONTINUE;
-}
-
-static void silc_net_connect_wait_stream(SilcSocketStreamStatus status,
- SilcStream stream, void *context)
-{
- SilcNetConnect conn = context;
- conn->stream_status = status;
- conn->stream = stream;
- SILC_FSM_CALL_CONTINUE(&conn->fsm);
-}
-
-SILC_FSM_STATE(silc_net_connect_st_connected)
-{
- SilcNetConnect conn = fsm_context;
- SilcSchedule schedule = silc_fsm_get_schedule(fsm);
- int opt = EINVAL, optlen = sizeof(opt), ret;
-
- if (conn->aborted) {
- /** Aborted */
- silc_schedule_unset_listen_fd(schedule, conn->sock);
- silc_schedule_task_del_by_fd(schedule, conn->sock);
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
- }
-
- ret = silc_net_get_socket_opt(conn->sock, SOL_SOCKET, SO_ERROR,
- &opt, &optlen);
-
- silc_schedule_unset_listen_fd(schedule, conn->sock);
- silc_schedule_task_del_by_fd(schedule, conn->sock);
-
- if (ret != 0 || opt != 0) {
- if (conn->retry) {
- /** Retry connecting */
- SILC_LOG_DEBUG(("Retry connecting"));
- conn->retry--;
- silc_net_close_connection(conn->sock);
- silc_fsm_next(fsm, silc_net_connect_st_start);
- return SILC_FSM_CONTINUE;
- }
-
-#if defined(ECONNREFUSED)
- if (errno == ECONNREFUSED)
- conn->status = SILC_NET_CONNECTION_REFUSED;
-#endif /* ECONNREFUSED */
-#if defined(ETIMEDOUT)
- if (errno == ETIMEDOUT)
- conn->status = SILC_NET_CONNECTION_TIMEOUT;
-#endif /* ETIMEDOUT */
-#if defined(ENETUNREACH)
- if (errno == ENETUNREACH)
- conn->status = SILC_NET_HOST_UNREACHABLE;
-#endif /* ENETUNREACH */
-
- /** Connecting failed */
- SILC_LOG_DEBUG(("Connecting failed"));
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
- }
-
- SILC_LOG_DEBUG(("TCP connection established"));
-
- /** Connection created */
- silc_fsm_next(fsm, silc_net_connect_st_stream);
- SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create(
- conn->sock, FALSE, FALSE,
- schedule,
- silc_net_connect_wait_stream, conn)));
-}
-
-SILC_FSM_STATE(silc_net_connect_st_stream)
-{
- SilcNetConnect conn = fsm_context;
-
- if (conn->aborted) {
- /** Aborted */
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
- }
-
- if (conn->stream_status != SILC_SOCKET_OK) {
- /** Stream creation failed */
- if (conn->stream_status == SILC_SOCKET_UNKNOWN_IP)
- conn->status = SILC_NET_UNKNOWN_IP;
- else if (conn->stream_status == SILC_SOCKET_UNKNOWN_HOST)
- conn->status = SILC_NET_UNKNOWN_HOST;
- else
- conn->status = SILC_NET_ERROR;
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
- }
-
- /* Set stream information */
- silc_socket_stream_set_info(conn->stream,
- !silc_net_is_ip(conn->remote) ? conn->remote :
- conn->ip_addr, conn->ip_addr, conn->port);
-
- /** Stream created successfully */
- SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
- conn->status = SILC_NET_OK;
- silc_fsm_next(fsm, silc_net_connect_st_finish);
- return SILC_FSM_CONTINUE;
-}
-
-SILC_FSM_STATE(silc_net_connect_st_finish)
-{
- SilcNetConnect conn = fsm_context;
-
- /* Deliver error or new stream */
- if (!conn->aborted) {
- conn->callback(conn->status, conn->stream, conn->context);
- if (conn->op)
- silc_async_free(conn->op);
- if (conn->sop)
- silc_async_free(conn->sop);
- }
-
- return SILC_FSM_FINISH;
-}
-
-static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
-{
- SilcNetConnect conn = context;
- conn->aborted = TRUE;
-
- /* Abort underlaying stream creation too */
- if (conn->sop)
- silc_async_abort(conn->op, NULL, NULL);
-}
-
-static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,
- void *destructor_context)
-{
- SilcNetConnect conn = fsm_context;
- silc_free(conn->local_ip);
- silc_free(conn->remote);
- silc_free(conn);
-}
-
-/* Create asynchronous TCP/IP connection. */
-
-SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
- const char *remote_ip_addr,
- int remote_port,
- SilcSchedule schedule,
- SilcNetCallback callback,
- void *context)
-{
- SilcNetConnect conn;
-
- if (!remote_ip_addr || remote_port < 1 || !schedule || !callback)
- return NULL;
-
- SILC_LOG_DEBUG(("Creating connection to host %s port %d",
- remote_ip_addr, remote_port));
-
- conn = silc_calloc(1, sizeof(*conn));
- if (!conn) {
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
-
- /* Start async operation */
- conn->op = silc_async_alloc(silc_net_connect_abort, NULL, conn);
- if (!conn->op) {
- silc_free(conn);
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
-
- if (local_ip_addr)
- conn->local_ip = strdup(local_ip_addr);
- conn->remote = strdup(remote_ip_addr);
- if (!conn->remote) {
- silc_async_free(conn->op);
- silc_free(conn->local_ip);
- silc_free(conn);
- callback(SILC_NET_NO_MEMORY, NULL, context);
- return NULL;
- }
- conn->port = remote_port;
- conn->callback = callback;
- conn->context = context;
- conn->retry = 1;
- conn->status = SILC_NET_ERROR;
-
- silc_fsm_init(&conn->fsm, conn, silc_net_connect_destructor, NULL, schedule);
- silc_fsm_start(&conn->fsm, silc_net_connect_st_start);
-
- return conn->op;
+ return sock;
}
/* Closes the connection by closing the socket connection. */
void silc_net_close_connection(int sock)
{
- SILC_LOG_DEBUG(("Closing sock %d", sock));
close(sock);
}
/* Set's the socket to non-blocking mode. */
-int silc_net_set_socket_nonblock(SilcSocket sock)
+int silc_net_set_socket_nonblock(int sock)
{
- return fcntl((int)sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
+ return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
}
/* Converts the IP number string from numbers-and-dots notation to
binary form. */
-SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
+bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
{
int ret = 0;
ret = inet_aton(addr, &tmp);
if (bin_len < 4)
return FALSE;
-
+
memcpy(bin, (unsigned char *)&tmp.s_addr, 4);
#ifdef HAVE_IPV6
} else {
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1998 - 2007 Pekka Riikonen
+ Copyright (C) 1998 - 2004 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
*/
/* $Id$ */
-#include "silc.h"
-
-#if defined(HAVE_EPOLL_WAIT)
-#include <sys/epoll.h>
-#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
-#include <poll.h>
-#endif
-
-const SilcScheduleOps schedule_ops;
-
-/* Internal context. */
-typedef struct {
-#if defined(HAVE_EPOLL_WAIT)
- struct epoll_event *fds;
- SilcUInt32 fds_count;
- int epfd;
-#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
- struct rlimit nofile;
- struct pollfd *fds;
- SilcUInt32 fds_count;
-#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
- void *app_context;
- int wakeup_pipe[2];
- SilcTask wakeup_task;
- sigset_t signals;
- sigset_t signals_blocked;
-} *SilcUnixScheduler;
-
-typedef struct {
- SilcUInt32 sig;
- SilcTaskCallback callback;
- void *context;
- SilcBool call;
- SilcSchedule schedule;
-} SilcUnixSignal;
-
-#define SIGNAL_COUNT 32
-SilcUnixSignal signal_call[SIGNAL_COUNT];
-
-#if defined(HAVE_EPOLL_WAIT)
-
-/* Linux's fast epoll system (level triggered) */
-
-int silc_epoll(SilcSchedule schedule, void *context)
-{
- SilcUnixScheduler internal = context;
- SilcTaskFd task;
- struct epoll_event *fds = internal->fds;
- SilcUInt32 fds_count = internal->fds_count;
- int ret, i, timeout = -1;
-
- /* Allocate larger fd table if needed */
- i = silc_hash_table_count(schedule->fd_queue);
- if (i > fds_count) {
- fds = silc_realloc(internal->fds, sizeof(*internal->fds) *
- (fds_count + (i / 2)));
- if (silc_likely(fds)) {
- internal->fds = fds;
- internal->fds_count = fds_count = fds_count + (i / 2);
- }
- }
-
- if (schedule->has_timeout)
- timeout = ((schedule->timeout.tv_sec * 1000) +
- (schedule->timeout.tv_usec / 1000));
-
- SILC_SCHEDULE_UNLOCK(schedule);
- ret = epoll_wait(internal->epfd, fds, fds_count, timeout);
- SILC_SCHEDULE_LOCK(schedule);
- if (ret <= 0)
- return ret;
-
- silc_list_init(schedule->fd_dispatch, struct SilcTaskStruct, next);
-
- for (i = 0; i < ret; i++) {
- task = fds[i].data.ptr;
- task->revents = 0;
- if (!task->header.valid || !task->events) {
- epoll_ctl(internal->epfd, EPOLL_CTL_DEL, task->fd, &fds[i]);
- continue;
- }
- if (fds[i].events & (EPOLLIN | EPOLLPRI | EPOLLHUP | EPOLLERR))
- task->revents |= SILC_TASK_READ;
- if (fds[i].events & EPOLLOUT)
- task->revents |= SILC_TASK_WRITE;
- silc_list_add(schedule->fd_dispatch, task);
- }
-
- return ret;
-}
-
-#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
-
-/* Calls normal poll() system call. */
-
-int silc_poll(SilcSchedule schedule, void *context)
-{
- SilcUnixScheduler internal = context;
- SilcHashTableList htl;
- SilcTaskFd task;
- struct pollfd *fds = internal->fds;
- SilcUInt32 fds_count = internal->fds_count;
- int fd, ret, i = 0, timeout = -1;
-
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) {
- if (!task->events)
- continue;
-
- /* Allocate larger fd table if needed */
- if (i >= fds_count) {
- struct rlimit nofile;
-
- fds = silc_realloc(internal->fds, sizeof(*internal->fds) *
- (fds_count + (fds_count / 2)));
- if (silc_unlikely(!fds))
- break;
- internal->fds = fds;
- internal->fds_count = fds_count = fds_count + (fds_count / 2);
- internal->nofile.rlim_cur = fds_count;
- if (fds_count > internal->nofile.rlim_max)
- internal->nofile.rlim_max = fds_count;
- if (setrlimit(RLIMIT_NOFILE, &nofile) < 0)
- break;
- }
-
- fds[i].fd = fd;
- fds[i].events = 0;
- task->revents = fds[i].revents = 0;
-
- if (task->events & SILC_TASK_READ)
- fds[i].events |= (POLLIN | POLLPRI);
- if (task->events & SILC_TASK_WRITE)
- fds[i].events |= POLLOUT;
- i++;
- }
- silc_hash_table_list_reset(&htl);
- silc_list_init(schedule->fd_dispatch, struct SilcTaskStruct, next);
-
- if (schedule->has_timeout)
- timeout = ((schedule->timeout.tv_sec * 1000) +
- (schedule->timeout.tv_usec / 1000));
-
- fds_count = i;
- SILC_SCHEDULE_UNLOCK(schedule);
- ret = poll(fds, fds_count, timeout);
- SILC_SCHEDULE_LOCK(schedule);
- if (ret <= 0)
- return ret;
-
- for (i = 0; i < fds_count; i++) {
- if (!fds[i].revents)
- continue;
- if (!silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fds[i].fd),
- NULL, (void **)&task))
- continue;
- if (!task->header.valid || !task->events)
- continue;
-
- fd = fds[i].revents;
- if (fd & (POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL))
- task->revents |= SILC_TASK_READ;
- if (fd & POLLOUT)
- task->revents |= SILC_TASK_WRITE;
- silc_list_add(schedule->fd_dispatch, task);
- }
-
- return ret;
-}
-
-#else
+#include "silcincludes.h"
+#include "silcschedule_i.h"
/* Calls normal select() system call. */
-int silc_select(SilcSchedule schedule, void *context)
+int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count,
+ struct timeval *timeout)
{
- SilcHashTableList htl;
- SilcTaskFd task;
fd_set in, out;
- int fd, max_fd = 0, ret;
+ int ret, i, max_fd = 0;
FD_ZERO(&in);
FD_ZERO(&out);
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) {
- if (!task->events)
+ for (i = 0; i < fds_count; i++) {
+ if (!fds[i].events)
continue;
#ifdef FD_SETSIZE
- if (fd >= FD_SETSIZE)
+ if (fds[i].fd >= FD_SETSIZE)
break;
#endif /* FD_SETSIZE */
- if (fd > max_fd)
- max_fd = fd;
+ if (fds[i].fd > max_fd)
+ max_fd = fds[i].fd;
- if (task->events & SILC_TASK_READ)
- FD_SET(fd, &in);
- if (task->events & SILC_TASK_WRITE)
- FD_SET(fd, &out);
+ if (fds[i].events & SILC_TASK_READ)
+ FD_SET(fds[i].fd, &in);
+ if (fds[i].events & SILC_TASK_WRITE)
+ FD_SET(fds[i].fd, &out);
- task->revents = 0;
+ fds[i].revents = 0;
}
- silc_hash_table_list_reset(&htl);
- silc_list_init(schedule->fd_dispatch, struct SilcTaskStruct, next);
- SILC_SCHEDULE_UNLOCK(schedule);
- ret = select(max_fd + 1, &in, &out, NULL, (schedule->has_timeout ?
- &schedule->timeout : NULL));
- SILC_SCHEDULE_LOCK(schedule);
+ ret = select(max_fd + 1, &in, &out, NULL, timeout);
if (ret <= 0)
return ret;
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) {
- if (!task->header.valid || !task->events)
+ for (i = 0; i < fds_count; i++) {
+ if (!fds[i].events)
continue;
#ifdef FD_SETSIZE
- if (fd >= FD_SETSIZE)
+ if (fds[i].fd >= FD_SETSIZE)
break;
#endif /* FD_SETSIZE */
- if (FD_ISSET(fd, &in))
- task->revents |= SILC_TASK_READ;
- if (FD_ISSET(fd, &out))
- task->revents |= SILC_TASK_WRITE;
- silc_list_add(schedule->fd_dispatch, task);
+ if (FD_ISSET(fds[i].fd, &in))
+ fds[i].revents |= SILC_TASK_READ;
+ if (FD_ISSET(fds[i].fd, &out))
+ fds[i].revents |= SILC_TASK_WRITE;
}
- silc_hash_table_list_reset(&htl);
return ret;
}
-#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
-
-/* Schedule `task' with events `event_mask'. Zero `event_mask' unschedules. */
-
-SilcBool silc_schedule_internal_schedule_fd(SilcSchedule schedule,
- void *context,
- SilcTaskFd task,
- SilcTaskEvent event_mask)
-{
-#if defined(HAVE_EPOLL_WAIT)
- SilcUnixScheduler internal = (SilcUnixScheduler)context;
- struct epoll_event event;
-
- if (!internal)
- return TRUE;
-
- SILC_LOG_DEBUG(("Scheduling fd %lu, mask %x", task->fd, event_mask));
-
- event.events = 0;
- if (event_mask & SILC_TASK_READ)
- event.events |= (EPOLLIN | EPOLLPRI);
- if (event_mask & SILC_TASK_WRITE)
- event.events |= EPOLLOUT;
-
- /* Zero mask unschedules task */
- if (silc_unlikely(!event.events)) {
- if (epoll_ctl(internal->epfd, EPOLL_CTL_DEL, task->fd, &event)) {
- SILC_LOG_DEBUG(("epoll_ctl (DEL): %s", strerror(errno)));
- return FALSE;
- }
- return TRUE;
- }
+#define SIGNAL_COUNT 32
- /* Schedule the task */
- if (silc_unlikely(!task->scheduled)) {
- event.data.ptr = task;
- if (epoll_ctl(internal->epfd, EPOLL_CTL_ADD, task->fd, &event)) {
- SILC_LOG_DEBUG(("epoll_ctl (ADD): %s", strerror(errno)));
- return FALSE;
- }
- task->scheduled = TRUE;
- return TRUE;
- }
+typedef struct {
+ SilcUInt32 signal;
+ SilcTaskCallback callback;
+ void *context;
+ bool call;
+} SilcUnixSignal;
- /* Schedule for specific mask */
- event.data.ptr = task;
- if (epoll_ctl(internal->epfd, EPOLL_CTL_MOD, task->fd, &event)) {
- SILC_LOG_DEBUG(("epoll_ctl (MOD): %s", strerror(errno)));
- return FALSE;
- }
-#endif /* HAVE_EPOLL_WAIT */
- return TRUE;
-}
+/* Internal context. */
+typedef struct {
+ void *app_context;
+ int wakeup_pipe[2];
+ SilcTask wakeup_task;
+ sigset_t signals;
+ sigset_t signals_blocked;
+ SilcUnixSignal signal_call[SIGNAL_COUNT];
+} *SilcUnixScheduler;
#ifdef SILC_THREADS
SilcUnixScheduler internal = (SilcUnixScheduler)context;
unsigned char c;
- SILC_LOG_DEBUG(("Wokeup"));
-
read(internal->wakeup_pipe[0], &c, 1);
}
void *app_context)
{
SilcUnixScheduler internal;
- int i;
internal = silc_calloc(1, sizeof(*internal));
if (!internal)
return NULL;
-#if defined(HAVE_EPOLL_WAIT)
- internal->epfd = epoll_create(4);
- if (internal->epfd < 0) {
- SILC_LOG_ERROR(("epoll_create() failed: %s", strerror(errno)));
- return NULL;
- }
- internal->fds = silc_calloc(4, sizeof(*internal->fds));
- if (!internal->fds) {
- close(internal->epfd);
- return NULL;
- }
- internal->fds_count = 4;
-#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
- getrlimit(RLIMIT_NOFILE, &internal->nofile);
-
- if (schedule->max_tasks > 0) {
- internal->nofile.rlim_cur = schedule->max_tasks;
- if (schedule->max_tasks > internal->nofile.rlim_max)
- internal->nofile.rlim_max = schedule->max_tasks;
- setrlimit(RLIMIT_NOFILE, &internal->nofile);
- getrlimit(RLIMIT_NOFILE, &internal->nofile);
- schedule->max_tasks = internal->nofile.rlim_max;
- }
-
- internal->fds = silc_calloc(internal->nofile.rlim_cur,
- sizeof(*internal->fds));
- if (!internal->fds)
- return NULL;
- internal->fds_count = internal->nofile.rlim_cur;
-#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
-
sigemptyset(&internal->signals);
#ifdef SILC_THREADS
internal->wakeup_task =
silc_schedule_task_add(schedule, internal->wakeup_pipe[0],
silc_schedule_wakeup_cb, internal,
- 0, 0, SILC_TASK_FD);
+ 0, 0, SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
if (!internal->wakeup_task) {
SILC_LOG_ERROR(("Could not add a wakeup task, threads won't work"));
close(internal->wakeup_pipe[0]);
return NULL;
}
#endif
- silc_schedule_internal_schedule_fd(schedule, internal,
- (SilcTaskFd)internal->wakeup_task,
- SILC_TASK_READ);
internal->app_context = app_context;
- for (i = 0; i < SIGNAL_COUNT; i++) {
- signal_call[i].sig = 0;
- signal_call[i].call = FALSE;
- signal_call[i].schedule = schedule;
- }
-
return (void *)internal;
}
-void silc_schedule_internal_signals_block(SilcSchedule schedule,
- void *context);
-void silc_schedule_internal_signals_unblock(SilcSchedule schedule,
- void *context);
+void silc_schedule_internal_signals_block(void *context);
+void silc_schedule_internal_signals_unblock(void *context);
/* Uninitializes the platform specific scheduler context. */
-void silc_schedule_internal_uninit(SilcSchedule schedule, void *context)
+void silc_schedule_internal_uninit(void *context)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
close(internal->wakeup_pipe[1]);
#endif
-#if defined(HAVE_EPOLL_WAIT)
- close(internal->epfd);
- silc_free(internal->fds);
-#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
- silc_free(internal->fds);
-#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
-
silc_free(internal);
}
/* Wakes up the scheduler */
-void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context)
+void silc_schedule_internal_wakeup(void *context)
{
#ifdef SILC_THREADS
SilcUnixScheduler internal = (SilcUnixScheduler)context;
if (!internal)
return;
- SILC_LOG_DEBUG(("Wakeup"));
-
write(internal->wakeup_pipe[1], "!", 1);
#endif
}
-/* Signal handler */
-
-static void silc_schedule_internal_sighandler(int signal)
+void silc_schedule_internal_signal_register(void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
{
+ SilcUnixScheduler internal = (SilcUnixScheduler)context;
int i;
+ if (!internal)
+ return;
+
+ SILC_LOG_DEBUG(("Registering signal %d", signal));
+
+ silc_schedule_internal_signals_block(context);
+
for (i = 0; i < SIGNAL_COUNT; i++) {
- if (signal_call[i].sig == signal) {
- signal_call[i].call = TRUE;
- signal_call[i].schedule->signal_tasks = TRUE;
- SILC_LOG_DEBUG(("Scheduling signal %d to be called",
- signal_call[i].sig));
+ if (!internal->signal_call[i].signal) {
+ internal->signal_call[i].signal = signal;
+ internal->signal_call[i].callback = callback;
+ internal->signal_call[i].context = callback_context;
+ internal->signal_call[i].call = FALSE;
break;
}
}
+
+ silc_schedule_internal_signals_unblock(context);
+ sigaddset(&internal->signals, signal);
}
-void silc_schedule_internal_signal_register(SilcSchedule schedule,
- void *context,
- SilcUInt32 sig,
- SilcTaskCallback callback,
- void *callback_context)
+void silc_schedule_internal_signal_unregister(void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
int i;
if (!internal)
return;
- SILC_LOG_DEBUG(("Registering signal %d", sig));
+ SILC_LOG_DEBUG(("Unregistering signal %d", signal));
- silc_schedule_internal_signals_block(schedule, context);
+ silc_schedule_internal_signals_block(context);
for (i = 0; i < SIGNAL_COUNT; i++) {
- if (!signal_call[i].sig) {
- signal_call[i].sig = sig;
- signal_call[i].callback = callback;
- signal_call[i].context = callback_context;
- signal_call[i].call = FALSE;
- signal(sig, silc_schedule_internal_sighandler);
- break;
+ if (internal->signal_call[i].signal == signal &&
+ internal->signal_call[i].callback == callback &&
+ internal->signal_call[i].context == callback_context) {
+ internal->signal_call[i].signal = 0;
+ internal->signal_call[i].callback = NULL;
+ internal->signal_call[i].context = NULL;
+ internal->signal_call[i].call = FALSE;
}
}
- silc_schedule_internal_signals_unblock(schedule, context);
- sigaddset(&internal->signals, sig);
+ silc_schedule_internal_signals_unblock(context);
+ sigdelset(&internal->signals, signal);
}
-void silc_schedule_internal_signal_unregister(SilcSchedule schedule,
- void *context,
- SilcUInt32 sig)
+/* Mark signal to be called later. */
+
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
int i;
if (!internal)
return;
- SILC_LOG_DEBUG(("Unregistering signal %d", sig));
-
- silc_schedule_internal_signals_block(schedule, context);
+ silc_schedule_internal_signals_block(context);
for (i = 0; i < SIGNAL_COUNT; i++) {
- if (signal_call[i].sig == sig) {
- signal_call[i].sig = 0;
- signal_call[i].callback = NULL;
- signal_call[i].context = NULL;
- signal_call[i].call = FALSE;
- signal(sig, SIG_DFL);
+ if (internal->signal_call[i].signal == signal) {
+ internal->signal_call[i].call = TRUE;
+ SILC_LOG_DEBUG(("Scheduling signal %d to be called",
+ internal->signal_call[i].signal));
}
}
- silc_schedule_internal_signals_unblock(schedule, context);
- sigdelset(&internal->signals, sig);
+ silc_schedule_internal_signals_unblock(context);
}
/* Call all signals */
-void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context)
+void silc_schedule_internal_signals_call(void *context,
+ SilcSchedule schedule)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
int i;
if (!internal)
return;
- silc_schedule_internal_signals_block(schedule, context);
+ silc_schedule_internal_signals_block(context);
for (i = 0; i < SIGNAL_COUNT; i++) {
- if (signal_call[i].call &&
- signal_call[i].callback) {
+ if (internal->signal_call[i].call &&
+ internal->signal_call[i].callback) {
SILC_LOG_DEBUG(("Calling signal %d callback",
- signal_call[i].sig));
- signal_call[i].callback(schedule, internal->app_context,
- SILC_TASK_INTERRUPT,
- signal_call[i].sig,
- signal_call[i].context);
- signal_call[i].call = FALSE;
+ internal->signal_call[i].signal));
+ internal->signal_call[i].callback(schedule, internal->app_context,
+ SILC_TASK_INTERRUPT,
+ internal->signal_call[i].signal,
+ internal->signal_call[i].context);
+ internal->signal_call[i].call = FALSE;
}
}
- silc_schedule_internal_signals_unblock(schedule, context);
+ silc_schedule_internal_signals_unblock(context);
}
/* Block registered signals in scheduler. */
-void silc_schedule_internal_signals_block(SilcSchedule schedule, void *context)
+void silc_schedule_internal_signals_block(void *context)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
/* Unblock registered signals in schedule. */
-void silc_schedule_internal_signals_unblock(SilcSchedule schedule,
- void *context)
+void silc_schedule_internal_signals_unblock(void *context)
{
SilcUnixScheduler internal = (SilcUnixScheduler)context;
sigprocmask(SIG_SETMASK, &internal->signals_blocked, NULL);
}
-
-const SilcScheduleOps schedule_ops =
-{
- silc_schedule_internal_init,
- silc_schedule_internal_uninit,
-#if defined(HAVE_EPOLL_WAIT)
- silc_epoll,
-#elif defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
- silc_poll,
-#else
- silc_select,
-#endif /* HAVE_POLL && HAVE_SETRLIMIT && RLIMIT_NOFILE */
- silc_schedule_internal_schedule_fd,
- silc_schedule_internal_wakeup,
- silc_schedule_internal_signal_register,
- silc_schedule_internal_signal_unregister,
- silc_schedule_internal_signals_call,
- silc_schedule_internal_signals_block,
- silc_schedule_internal_signals_unblock,
-};
--- /dev/null
+/*
+
+ silcunixsockconn.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 "silcincludes.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.
+ The data is written from the data section of the buffer, not from head
+ or tail section. This automatically pulls the data section towards end
+ after writing the data. */
+
+int silc_socket_write(SilcSocketConnection sock)
+{
+ int ret = 0;
+ int fd = sock->sock;
+ SilcBuffer src = sock->outbuf;
+
+ if (!src)
+ return -1;
+ if (SILC_IS_DISABLED(sock))
+ return -1;
+
+ SILC_LOG_DEBUG(("Writing data to socket %d", fd));
+
+ if (src->len > 0) {
+ ret = write(fd, src->data, src->len);
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
+ return -2;
+ }
+ SILC_LOG_DEBUG(("Cannot write to socket: %s", strerror(errno)));
+ sock->sock_error = errno;
+ return -1;
+ }
+
+ if (ret < src->len) {
+ SILC_LOG_DEBUG(("Wrote data %d of %d bytes, will write rest later",
+ ret, src->len));
+ silc_buffer_pull(src, ret);
+ return -2;
+ }
+
+ silc_buffer_pull(src, ret);
+ }
+
+ SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
+
+ return ret;
+}
+
+/* QoS read handler, this will call the read and write events to indicate
+ that data is available again after a timeout. */
+
+SILC_TASK_CALLBACK(silc_socket_read_qos)
+{
+ SilcSocketConnectionQos qos = context;
+ SilcSocketConnection sock = qos->sock;
+ qos->applied = TRUE;
+ if (sock->users > 1)
+ silc_schedule_set_listen_fd(qos->schedule, sock->sock,
+ (SILC_TASK_READ | SILC_TASK_WRITE), TRUE);
+ else
+ silc_schedule_unset_listen_fd(qos->schedule, sock->sock);
+ qos->applied = FALSE;
+ silc_socket_free(sock);
+}
+
+/* Reads data from the socket connection into the incoming data buffer.
+ It reads as much as possible from the socket connection. This returns
+ amount of bytes read or -1 on error or -2 on case where all of the
+ data could not be read at once. */
+
+int silc_socket_read(SilcSocketConnection sock)
+{
+ int len = 0;
+ unsigned char buf[SILC_SOCKET_READ_SIZE];
+ int fd = sock->sock;
+
+ if (SILC_IS_DISABLED(sock))
+ return -1;
+
+ /* If QoS was applied to socket then return earlier read data but apply
+ QoS to it too, if necessary. */
+ if (sock->qos) {
+ if (sock->qos->applied) {
+ if (sock->qos->data_len) {
+ /* Pull hidden data since we have it from earlier QoS apply */
+ silc_buffer_pull_tail(sock->inbuf, sock->qos->data_len);
+ len = sock->qos->data_len;
+ sock->qos->data_len = 0;
+ }
+
+ if (sock->inbuf->len - len > sock->qos->read_limit_bytes) {
+ /* Seems we need to apply QoS for the remaining data as well */
+ silc_socket_dup(sock);
+ silc_schedule_task_add(sock->qos->schedule, sock->sock,
+ silc_socket_read_qos, sock->qos,
+ sock->qos->limit_sec, sock->qos->limit_usec,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
+
+ /* Hide the rest of the data from the buffer. */
+ sock->qos->data_len = (sock->inbuf->len - len -
+ sock->qos->read_limit_bytes);
+ silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
+ }
+
+ if (sock->inbuf->len)
+ return sock->inbuf->len;
+ }
+
+ /* If we were called and we have active QoS data pending, return
+ with no data */
+ if (sock->qos->data_len) {
+ silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
+ return -2;
+ }
+ }
+
+ SILC_LOG_DEBUG(("Reading data from socket %d", fd));
+
+ /* Read the data from the socket. */
+ len = read(fd, buf, sizeof(buf));
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
+ return -2;
+ }
+ SILC_LOG_DEBUG(("Cannot read from socket: %d:%s", fd, strerror(errno)));
+ sock->sock_error = errno;
+ return -1;
+ }
+
+ if (!len)
+ return 0;
+
+ /* Insert the data to the buffer. */
+
+ if (!sock->inbuf)
+ sock->inbuf = silc_buffer_alloc(SILC_SOCKET_BUF_SIZE);
+
+ /* If the data does not fit to the buffer reallocate it */
+ if ((sock->inbuf->end - sock->inbuf->tail) < len)
+ sock->inbuf = silc_buffer_realloc(sock->inbuf, sock->inbuf->truelen +
+ (len * 2));
+ silc_buffer_put_tail(sock->inbuf, buf, len);
+ silc_buffer_pull_tail(sock->inbuf, len);
+
+ SILC_LOG_DEBUG(("Read %d bytes", len));
+
+ /* Apply QoS to the read data if necessary */
+ if (sock->qos) {
+ struct timeval curtime;
+ silc_gettimeofday(&curtime);
+
+ /* If we have passed the rate time limit, set our new time limit,
+ and zero the rate limit. */
+ if (!silc_compare_timeval(&curtime, &sock->qos->next_limit)) {
+ curtime.tv_sec++;
+ sock->qos->next_limit = curtime;
+ sock->qos->cur_rate = 0;
+ }
+ sock->qos->cur_rate++;
+
+ /* If we are not withing rate limit apply QoS for the read data */
+ if (sock->qos->cur_rate > sock->qos->read_rate) {
+ silc_socket_dup(sock);
+ silc_schedule_task_add(sock->qos->schedule, sock->sock,
+ silc_socket_read_qos, sock->qos,
+ sock->qos->limit_sec, sock->qos->limit_usec,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
+
+ /* Check the byte limit as well, and do not return more than allowed */
+ if (sock->inbuf->len > sock->qos->read_limit_bytes) {
+ /* Hide the rest of the data from the buffer. */
+ sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
+ silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
+ len = sock->inbuf->len;
+ } else {
+ /* Rate limit kicked in, do not return data yet */
+ return -2;
+ }
+ } else {
+ /* Check the byte limit, and do not return more than allowed */
+ if (sock->inbuf->len > sock->qos->read_limit_bytes) {
+ silc_socket_dup(sock);
+ silc_schedule_task_add(sock->qos->schedule, sock->sock,
+ silc_socket_read_qos, sock->qos,
+ sock->qos->limit_sec, sock->qos->limit_usec,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
+
+ /* Hide the rest of the data from the buffer. */
+ sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
+ silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
+ len = sock->inbuf->len;
+ }
+ }
+ }
+
+ return len;
+}
+
+/* Returns human readable socket error message */
+
+bool silc_socket_get_error(SilcSocketConnection sock, char *error,
+ SilcUInt32 error_len)
+{
+ char *err;
+
+ if (!sock->sock_error)
+ return FALSE;
+
+ err = strerror(sock->sock_error);
+ if (strlen(err) > error_len)
+ return FALSE;
+
+ memset(error, 0, error_len);
+ memcpy(error, err, strlen(err));
+ return TRUE;
+}
+++ /dev/null
-/*
-
- silcunixsocketstream.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 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"
-
-/************************ Static utility functions **************************/
-
-/* The IO process callback that calls the notifier callback to upper layer. */
-
-SILC_TASK_CALLBACK(silc_socket_stream_io)
-{
- SilcSocketStream stream = context;
-
- if (silc_unlikely(!stream->notifier))
- return;
-
- switch (type) {
- case SILC_TASK_READ:
- stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context);
- break;
-
- case SILC_TASK_WRITE:
- stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context);
- break;
-
- default:
- break;
- }
-}
-
-/**************************** Stream Operations *****************************/
-
-/* QoS read handler, this will call the read and write events to indicate
- that data is available again after a timeout. */
-
-SILC_TASK_CALLBACK(silc_socket_read_qos)
-{
- SilcSocketQos qos = context;
- qos->applied = TRUE;
- silc_schedule_set_listen_fd(qos->sock->schedule, qos->sock->sock,
- (SILC_TASK_READ | SILC_TASK_WRITE), TRUE);
- qos->applied = FALSE;
- silc_schedule_set_listen_fd(qos->sock->schedule, qos->sock->sock,
- SILC_TASK_READ, FALSE);
-}
-
-/* Stream read operation */
-
-int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- SilcSocketStream sock = stream;
- int len = 0;
- struct timeval curtime;
- unsigned char *qosbuf;
-
- SILC_LOG_DEBUG(("Reading data from socket %d", sock->sock));
-
- /* Handle the simple non-QoS reading. */
- if (!sock->qos) {
- len = read(sock->sock, buf, buf_len);
- if (len < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ, FALSE);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot read from socket: %d:%s",
- sock->sock, strerror(errno)));
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- sock->sock_error = errno;
- return -2;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes", len));
-
- if (!len)
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
-
- return len;
- }
-
- /* We have QoS set, and reading is done via the QoS system. */
- qosbuf = sock->qos->buffer;
-
- /* If QoS was applied, return the data that was pending. */
- if (sock->qos->applied && sock->qos->data_len) {
- memcpy(buf, qosbuf, sock->qos->data_len);
- sock->qos->data_len = 0;
- return sock->qos->data_len;
- }
-
- /* If we have active QoS data pending, return with no data */
- if (sock->qos->data_len) {
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- return -1;
- }
-
- /* Read the data from the socket. Never read more than the max limit. */
- len = (buf_len < sock->qos->read_limit_bytes ? buf_len :
- sock->qos->read_limit_bytes);
- len = read(sock->sock, qosbuf, len);
- if (len < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ, FALSE);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot read from socket: %d:%s",
- sock->sock, strerror(errno)));
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- silc_schedule_task_del_by_context(sock->schedule, sock->qos);
- sock->qos->data_len = 0;
- sock->sock_error = errno;
- return -2;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes", len));
-
- if (!len) {
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- silc_schedule_task_del_by_context(sock->schedule, sock->qos);
- sock->qos->data_len = 0;
- return 0;
- }
-
- /* If we have passed the rate time limit, set our new time limit,
- and zero the rate limit. This limits reads per second. */
- silc_gettimeofday(&curtime);
- if (!silc_compare_timeval(&curtime, &sock->qos->next_limit)) {
- curtime.tv_sec++;
- sock->qos->next_limit = curtime;
- sock->qos->cur_rate = 0;
- }
- sock->qos->cur_rate++;
-
- /* If we are not within rate limit apply QoS for the read data */
- if (sock->qos->cur_rate > sock->qos->read_rate) {
- silc_schedule_task_add_timeout(sock->schedule, silc_socket_read_qos,
- sock->qos, sock->qos->limit_sec,
- sock->qos->limit_usec);
- sock->qos->data_len = len;
-
- /* Rate limit kicked in, do not return data yet */
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- return -1;
- }
-
- /* Return the data from the QoS buffer */
- memcpy(buf, qosbuf, len);
- return len;
-}
-
-/* Stream write operation */
-
-int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcSocketStream sock = stream;
- int ret;
-
- SILC_LOG_DEBUG(("Writing data to socket %d", sock->sock));
-
- ret = write(sock->sock, data, data_len);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot write to socket: %s", strerror(errno)));
- silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
- sock->sock_error = errno;
- return -2;
- }
-
- SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
- if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
- SILC_TASK_WRITE)
- silc_schedule_set_listen_fd(sock->schedule, sock->sock,
- SILC_TASK_READ, FALSE);
-
- return ret;
-}
-
-/* Receive UDP packet. QoS is not supported. */
-
-int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len);
-}
-
-/* Send UDP packet. This always succeeds. */
-
-int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcSocketStream sock = stream;
-
- /* In connectionless state check if remote IP and port is provided */
- if (!sock->connected && sock->ip && sock->port)
- return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len);
-
- /* In connected state use normal writing to socket. */
- return silc_socket_stream_write(stream, data, data_len);
-}
-
-#if 0
-/* Returns human readable socket error message */
-
-SilcBool silc_socket_get_error(SilcStream sock, char *error,
- SilcUInt32 error_len)
-{
- char *err;
-
- if (!sock->sock_error)
- return FALSE;
-
- err = strerror(sock->sock_error);
- if (strlen(err) > error_len)
- return FALSE;
-
- memset(error, 0, error_len);
- memcpy(error, err, strlen(err));
- return TRUE;
-}
-#endif /* 0 */
-
-/* Closes socket */
-
-SilcBool silc_socket_stream_close(SilcStream stream)
-{
- SilcSocketStream socket_stream = stream;
-
- if (socket_stream->schedule) {
- silc_schedule_unset_listen_fd(socket_stream->schedule,
- socket_stream->sock);
- silc_schedule_task_del_by_fd(socket_stream->schedule,
- socket_stream->sock);
- }
- silc_net_close_connection(socket_stream->sock);
-
- return TRUE;
-}
-
-/* Destroys the stream */
-
-void silc_socket_stream_destroy(SilcStream stream)
-{
- SilcSocketStream socket_stream = stream;
-
- silc_socket_stream_close(socket_stream);
- silc_free(socket_stream->ip);
- silc_free(socket_stream->hostname);
- if (socket_stream->schedule)
- 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,
- socket_stream->qos);
- if (socket_stream->qos->buffer) {
- memset(socket_stream->qos->buffer, 0,
- socket_stream->qos->read_limit_bytes);
- silc_free(socket_stream->qos->buffer);
- }
- silc_free(socket_stream->qos);
- }
-
- if (socket_stream->schedule)
- silc_schedule_wakeup(socket_stream->schedule);
-
- silc_free(socket_stream);
-}
-
-/* Sets stream notification callback for the stream */
-
-SilcBool silc_socket_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
-{
- SilcSocketStream socket_stream = stream;
-
- SILC_LOG_DEBUG(("Setting stream notifier callback"));
-
- socket_stream->notifier = callback;
- socket_stream->notifier_context = context;
- socket_stream->schedule = schedule;
-
- if (socket_stream->notifier && socket_stream->schedule) {
- /* Add the socket to scheduler. Safe to call if already added. */
- if (!silc_schedule_task_add_fd(socket_stream->schedule,
- socket_stream->sock,
- silc_socket_stream_io, socket_stream))
- return FALSE;
-
- /* Initially set socket for reading */
- if (!silc_schedule_set_listen_fd(socket_stream->schedule,
- socket_stream->sock,
- SILC_TASK_READ, FALSE))
- return FALSE;
- } else if (socket_stream->schedule) {
- /* 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);
- }
-
- if (socket_stream->schedule)
- silc_schedule_wakeup(socket_stream->schedule);
-
- return TRUE;
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 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
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
*/
/* $Id$ */
-#include "silc.h"
-
-/**************************** SILC Thread API *******************************/
+#include "silcincludes.h"
SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- SilcBool waitable)
+ bool waitable)
{
#ifdef SILC_THREADS
pthread_attr_t attr;
}
if (pthread_attr_setdetachstate(&attr,
- waitable ? PTHREAD_CREATE_JOINABLE :
+ waitable ? PTHREAD_CREATE_JOINABLE :
PTHREAD_CREATE_DETACHED)) {
SILC_LOG_ERROR(("Thread error: %s", strerror(errno)));
pthread_attr_destroy(&attr);
return NULL;
}
- ret = pthread_create(&thread, &attr, (void * (*)(void *))start_func,
+ ret = pthread_create(&thread, &attr, (void * (*)(void *))start_func,
context);
if (ret) {
SILC_LOG_ERROR(("Thread error: %s", strerror(errno)));
#endif
}
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
+bool silc_thread_wait(SilcThread thread, void **exit_value)
{
#ifdef SILC_THREADS
SILC_LOG_DEBUG(("Waiting for thread %p", thread));
return FALSE;
#endif
}
-
-
-/***************************** SILC Mutex API *******************************/
-
-/* SILC Mutex structure */
-struct SilcMutexStruct {
-#ifdef SILC_THREADS
- pthread_mutex_t mutex;
-#endif /* SILC_THREADS */
- unsigned int locked : 1;
-};
-
-SilcBool silc_mutex_alloc(SilcMutex *mutex)
-{
-#ifdef SILC_THREADS
- *mutex = silc_calloc(1, sizeof(**mutex));
- if (*mutex == NULL)
- return FALSE;
- pthread_mutex_init(&(*mutex)->mutex, NULL);
- (*mutex)->locked = FALSE;
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_free(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- pthread_mutex_destroy(&mutex->mutex);
- silc_free(mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_lock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- if (pthread_mutex_lock(&mutex->mutex))
- SILC_ASSERT(FALSE);
- mutex->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_unlock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- if (pthread_mutex_unlock(&mutex->mutex))
- SILC_ASSERT(FALSE);
- mutex->locked = FALSE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_assert_locked(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex)
- SILC_ASSERT(mutex->locked);
-#endif /* SILC_THREADS */
-}
-
-/***************************** SILC Rwlock API ******************************/
-
-/* SILC read/write lock structure */
-struct SilcRwLockStruct {
-#ifdef SILC_THREADS
- pthread_rwlock_t rwlock;
-#else
- void *tmp;
-#endif /* SILC_THREADS */
-};
-
-SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
-{
-#ifdef SILC_THREADS
- *rwlock = silc_calloc(1, sizeof(**rwlock));
- if (*rwlock == NULL)
- return FALSE;
- pthread_rwlock_init(&(*rwlock)->rwlock, NULL);
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_free(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- pthread_rwlock_destroy(&rwlock->rwlock);
- silc_free(rwlock);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_rdlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock)
- pthread_rwlock_rdlock(&rwlock->rwlock);
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_wrlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock)
- pthread_rwlock_wrlock(&rwlock->rwlock);
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_unlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock)
- pthread_rwlock_unlock(&rwlock->rwlock);
-#endif /* SILC_THREADS */
-}
-
-/****************************** SILC Cond API *******************************/
-
-/* SILC Conditional Variable context */
-struct SilcCondStruct {
-#ifdef SILC_THREADS
- pthread_cond_t cond;
-#else
- void *tmp;
-#endif /* SILC_THREADS*/
-};
-
-SilcBool silc_cond_alloc(SilcCond *cond)
-{
-#ifdef SILC_THREADS
- *cond = silc_calloc(1, sizeof(**cond));
- if (*cond == NULL)
- return FALSE;
- pthread_cond_init(&(*cond)->cond, NULL);
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_free(SilcCond cond)
-{
-#ifdef SILC_THREADS
- pthread_cond_destroy(&cond->cond);
- silc_free(cond);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_signal(SilcCond cond)
-{
-#ifdef SILC_THREADS
- pthread_cond_signal(&cond->cond);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_broadcast(SilcCond cond)
-{
-#ifdef SILC_THREADS
- pthread_cond_broadcast(&cond->cond);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_wait(SilcCond cond, SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- pthread_cond_wait(&cond->cond, &mutex->mutex);
-#endif /* SILC_THREADS*/
-}
-
-SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
- int timeout)
-{
-#ifdef SILC_THREADS
- struct timespec t;
- if (timeout) {
- t.tv_sec = timeout / 1000;
- t.tv_nsec = (timeout % 1000) * 1000;
- return pthread_cond_timedwait(&cond->cond, &mutex->mutex, &t) == 0;
- }
-
- return pthread_cond_wait(&cond->cond, &mutex->mutex) == 0;
-#else
- return FALSE;
-#endif /* SILC_THREADS*/
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* XXX lib/contrib/regex.c might cmopile on WIN32 as well */
{
regex_t preg;
int ret = FALSE;
-
+
if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) != 0)
return FALSE;
char *silc_get_username()
{
char *logname = NULL;
-
+
logname = getenv("LOGNAME");
- if (!logname) {
+ if (!logname || !strlen(logname)) {
logname = getlogin();
- if (!logname) {
+ if (!logname || !strlen(logname)) {
struct passwd *pw;
pw = getpwuid(getuid());
- if (!pw)
+ if (!pw || !strlen(pw->pw_name))
return strdup("foo");
logname = pw->pw_name;
}
}
-
+
return strdup(logname);
}
{
char *realname = NULL;
struct passwd *pw;
-
+
pw = getpwuid(getuid());
if (!pw)
- return strdup("No Name");
+ return strdup("Foo T. Bar");
if (strchr(pw->pw_gecos, ','))
*strchr(pw->pw_gecos, ',') = 0;
if (!strlen(pw->pw_gecos))
- return strdup("No Name");
+ return strdup("Foo T. Bar");
realname = strdup(pw->pw_gecos);
{
return gettimeofday(p, NULL);
}
-
-int silc_file_set_nonblock(int fd)
-{
- return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
-}
#
# Author: Pekka Riikonen <priikone@silcnet.org>
#
-# Copyright (C) 2001 - 2006 Pekka Riikonen
+# Copyright (C) 2001 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
silcwin32schedule.c \
silcwin32sockconn.c \
silcwin32util.c \
+ silcwin32mutex.c \
silcwin32thread.c
include $(top_srcdir)/Makefile.defines.in
--- /dev/null
+/*
+
+ silcwin32mutex.c
+
+ 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
+ GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+
+/* SILC Mutex structure */
+struct SilcMutexStruct {
+#ifdef SILC_THREADS
+ CRITICAL_SECTION mutex;
+ BOOL locked;
+#else
+ void *tmp;
+#endif /* SILC_THREADS */
+};
+
+bool silc_mutex_alloc(SilcMutex *mutex)
+{
+#ifdef SILC_THREADS
+ *mutex = silc_calloc(1, sizeof(**mutex));
+ InitializeCriticalSection(&((*mutex)->mutex));
+#endif /* SILC_THREADS */
+ return TRUE;
+}
+
+void silc_mutex_free(SilcMutex mutex)
+{
+#ifdef SILC_THREADS
+ if (mutex) {
+ DeleteCriticalSection(&mutex->mutex);
+ silc_free(mutex);
+ }
+#endif /* SILC_THREADS */
+}
+
+void silc_mutex_lock(SilcMutex mutex)
+{
+#ifdef SILC_THREADS
+ if (mutex) {
+ EnterCriticalSection(&mutex->mutex);
+ assert(mutex->locked == FALSE);
+ mutex->locked = TRUE;
+ }
+#endif /* SILC_THREADS */
+}
+
+void silc_mutex_unlock(SilcMutex mutex)
+{
+#ifdef SILC_THREADS
+ if (mutex) {
+ assert(mutex->locked == TRUE);
+ mutex->locked = FALSE;
+ LeaveCriticalSection(&mutex->mutex);
+ }
+#endif /* SILC_THREADS */
+}
/* XXX IPv6 support missing */
-#include "silc.h"
+#include "silcincludes.h"
#include "silcnet.h"
/* This function creates server or daemon or listener or what ever. This
/* Converts the IP number string from numbers-and-dots notation to
binary form. */
-SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
+bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
{
unsigned long ret;
/* Init Winsock2. */
-SilcBool silc_net_win32_init(void)
+bool silc_net_win32_init(void)
{
int ret, sopt = SO_SYNCHRONOUS_NONALERT;
WSADATA wdata;
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2006 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
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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
+#include "silcschedule_i.h"
/* Our "select()" for WIN32. This mimics the behaviour of select() system
call. It does not call the Winsock's select() though. Its functions
References:
o http://msdn.microsoft.com/library/default.asp?
- url=/library/en-us/winui/hh/winui/messques_77zk.asp
+ url=/library/en-us/winui/hh/winui/messques_77zk.asp
o http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/winsock/hh/winsock/apistart_9g1e.asp
o http://msdn.microsoft.com/library/default.asp?
*/
-int silc_select(SilcSchedule schedule, void *context);
+int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count, struct timeval *timeout)
{
- SilcHashTableList htl;
- SilcTaskFd task;
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
DWORD ready, curtime;
LONG timeo;
+ int nhandles = 0, i;
MSG msg;
- int nhandles = 0, i, fd;
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) {
- if (!task->events)
+ if (fds_count > MAXIMUM_WAIT_OBJECTS)
+ fds_count = MAXIMUM_WAIT_OBJECTS;
+
+ for (i = 0; i < fds_count; i++) {
+ if (!fds[i].events)
continue;
- if (nhandles >= MAXIMUM_WAIT_OBJECTS)
- break;
- if (task->events & SILC_TASK_READ)
- handles[nhandles++] = (HANDLE)fd;
+ if (fds[i].events & SILC_TASK_READ)
+ handles[nhandles++] = (HANDLE)fds[i].fd;
/* If writing then just set the bit and return */
- if (task->events & SILC_TASK_WRITE) {
- task->revents = SILC_TASK_WRITE;
+ if (fds[i].events & SILC_TASK_WRITE) {
+ fds[i].revents = SILC_TASK_WRITE;
return 1;
}
- task->revents = 0;
+ fds[i].revents = 0;
}
- silc_hash_table_list_reset(&htl);
- timeo = (schedule->has_timeout ? ((schedule->timeout.tv_sec * 1000) +
- (schedule->timeout.tv_usec / 1000))
- : INFINITE);
+ timeo = (timeout ? (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000) :
+ INFINITE);
/* If we have nothing to wait and timeout is set then register a timeout
and wait just for windows messages. */
- if (nhandles == 0 && schedule->has_timeout) {
- SILC_SCHEDULE_UNLOCK(schedule);
+ if (nhandles == 0 && timeout) {
UINT timer = SetTimer(NULL, 0, timeo, NULL);
curtime = GetTickCount();
while (timer) {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_TIMER) {
KillTimer(NULL, timer);
- SILC_SCHEDULE_LOCK(schedule);
return 0;
}
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
}
KillTimer(NULL, timer);
}
timer = SetTimer(NULL, 0, timeo, NULL);
}
- SILC_SCHEDULE_LOCK(schedule);
}
- SILC_SCHEDULE_UNLOCK(schedule);
retry:
curtime = GetTickCount();
- ready = MsgWaitForMultipleObjects(nhandles, handles, FALSE, timeo,
+ ready = MsgWaitForMultipleObjects(nhandles, handles, FALSE, timeo,
QS_ALLINPUT);
- SILC_SCHEDULE_LOCK(schedule);
if (ready == WAIT_FAILED) {
/* Wait failed with error */
creates a window then its main loop (and we're assuming that
it is our SILC Scheduler) must handle the Windows messages, so do
it here as the MSDN suggests. */
- SILC_SCHEDULE_UNLOCK(schedule);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
}
/* If timeout is set then we must update the timeout since we won't
/* Go through all fds even though only one was set. This is to avoid
starvation of high numbered fds. */
- nhandles = silc_hash_table_count(schedule->fd_queue);
ready -= WAIT_OBJECT_0;
do {
- i = 0;
- silc_hash_table_list(schedule->fd_queue, &htl);
- while (silc_hash_table_get(&htl, (void **)&fd, (void **)&task)) {
- if (!task->events)
+ for (i = 0; i < fds_count; i++) {
+ if (!fds[i].events)
continue;
-
- if (fd == (int)handles[ready]) {
- i++;
- task->revents |= SILC_TASK_READ;
+
+ if (fds[i].fd == (int)handles[ready]) {
+ fds[i].revents |= SILC_TASK_READ;
break;
}
}
- silc_hash_table_list_reset(&htl);
/* Check the status of the next handle and set its fd to the fd
set if data is available. */
- SILC_SCHEDULE_UNLOCK(schedule);
- while (++ready < nhandles)
+ while (++ready < fds_count)
if (WaitForSingleObject(handles[ready], 0) == WAIT_OBJECT_0)
break;
- SILC_SCHEDULE_LOCK(schedule);
- } while (ready < nhandles);
+ } while (ready < fds_count);
return i + 1;
}
{
#ifdef SILC_THREADS
SilcWin32Wakeup wakeup;
-#endif
- schedule->max_tasks = MAXIMUM_WAIT_OBJECTS;
-
-#ifdef SILC_THREADS
wakeup = silc_calloc(1, sizeof(*wakeup));
- if (!wakeup)
- return NULL;
wakeup->wakeup_sema = CreateSemaphore(NULL, 0, 100, NULL);
if (!wakeup->wakeup_sema) {
return NULL;
}
- wakeup->wakeup_task =
+ wakeup->wakeup_task =
silc_schedule_task_add(schedule, (int)wakeup->wakeup_sema,
silc_schedule_wakeup_cb, wakeup,
- 0, 0, SILC_TASK_FD);
+ 0, 0, SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
if (!wakeup->wakeup_task) {
CloseHandle(wakeup->wakeup_sema);
silc_free(wakeup);
return (void *)wakeup;
#else
- return (void *)1;
+ return NULL;
#endif
}
/* Uninitializes the platform specific scheduler context. */
-void silc_schedule_internal_uninit(SilcSchedule schedule, void *context)
+void silc_schedule_internal_uninit(void *context)
{
#ifdef SILC_THREADS
SilcWin32Wakeup wakeup = (SilcWin32Wakeup)context;
/* Wakes up the scheduler */
-void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context)
+void silc_schedule_internal_wakeup(void *context)
{
#ifdef SILC_THREADS
SilcWin32Wakeup wakeup = (SilcWin32Wakeup)context;
/* Register signal */
-void silc_schedule_internal_signal_register(SilcSchedule schedule,
- void *context,
+void silc_schedule_internal_signal_register(void *context,
SilcUInt32 signal,
SilcTaskCallback callback,
void *callback_context)
/* Unregister signal */
-void silc_schedule_internal_signal_unregister(SilcSchedule schedule,
- void *context,
- SilcUInt32 signal)
+void silc_schedule_internal_signal_unregister(void *context,
+ SilcUInt32 signal,
+ SilcTaskCallback callback,
+ void *callback_context)
+{
+
+}
+
+/* Mark signal to be called later. */
+
+void silc_schedule_internal_signal_call(void *context, SilcUInt32 signal)
{
}
/* Call all signals */
-void silc_schedule_internal_signals_call(SilcSchedule schedule,
- void *context,
+void silc_schedule_internal_signals_call(void *context,
SilcSchedule schedule)
{
/* Block registered signals in scheduler. */
-void silc_schedule_internal_signals_block(SilcSchedule schedule,
- void *context)
+void silc_schedule_internal_signals_block(void *context)
{
}
/* Unblock registered signals in schedule. */
-void silc_schedule_internal_signals_unblock(SilcSchedule schedule,
- void *context)
+void silc_schedule_internal_signals_unblock(void *context)
{
}
-
-const SilcScheduleOps schedule_ops =
-{
- silc_schedule_internal_init,
- silc_schedule_internal_uninit,
- silc_select,
- silc_schedule_internal_wakeup,
- silc_schedule_internal_signal_register,
- silc_schedule_internal_signal_unregister,
- silc_schedule_internal_signals_call,
- silc_schedule_internal_signals_block,
- silc_schedule_internal_signals_unblock,
-};
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.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.
/* Returns human readable socket error message */
-SilcBool silc_socket_get_error(SilcSocketConnection sock, char *error,
+bool silc_socket_get_error(SilcSocketConnection sock, char *error,
SilcUInt32 error_len)
{
/* XXX TODO */
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2007 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
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
*/
/* $Id$ */
-#include "silc.h"
-
-/**************************** SILC Thread API *******************************/
+#include "silcincludes.h"
#ifdef SILC_THREADS
HANDLE thread;
SilcThreadStart start_func;
void *context;
- SilcBool waitable;
+ bool waitable;
} *SilcWin32Thread;
static DWORD silc_thread_tls;
#endif
SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
- SilcBool waitable)
+ bool waitable)
{
#ifdef SILC_THREADS
SilcWin32Thread thread;
{
#ifdef SILC_THREADS
SilcWin32Thread thread = TlsGetValue(silc_thread_tls);
-
+
if (thread) {
/* If the thread is waitable the memory is freed only in silc_thread_wait
by another thread. If not waitable, free it now. */
HANDLE handle = GetCurrentThread ();
HANDLE process = GetCurrentProcess ();
self = silc_calloc(1, sizeof(*self));
- DuplicateHandle(process, handle, process,
- &self->thread, 0, FALSE,
+ DuplicateHandle(process, handle, process,
+ &self->thread, 0, FALSE,
DUPLICATE_SAME_ACCESS);
TlsSetValue(silc_thread_tls, self);
}
#endif
}
-SilcBool silc_thread_wait(SilcThread thread, void **exit_value)
+bool silc_thread_wait(SilcThread thread, void **exit_value)
{
#ifdef SILC_THREADS
SilcWin32Thread self = (SilcWin32Thread)thread;
return FALSE;
#endif
}
-
-
-/***************************** SILC Mutex API *******************************/
-
-/* SILC Mutex structure */
-struct SilcMutexStruct {
-#ifdef SILC_THREADS
- CRITICAL_SECTION mutex;
-#endif /* SILC_THREADS */
- unsigned int locked : 1;
-};
-
-SilcBool silc_mutex_alloc(SilcMutex *mutex)
-{
-#ifdef SILC_THREADS
- *mutex = silc_calloc(1, sizeof(**mutex));
- if (!(*mutex))
- return FALSE;
- InitializeCriticalSection(&((*mutex)->mutex));
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_free(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- DeleteCriticalSection(&mutex->mutex);
- silc_free(mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_lock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- EnterCriticalSection(&mutex->mutex);
- SILC_ASSERT(mutex->locked == FALSE);
- mutex->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_unlock(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- SILC_ASSERT(mutex->locked == TRUE);
- mutex->locked = FALSE;
- LeaveCriticalSection(&mutex->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_mutex_assert_locked(SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- if (mutex)
- SILC_ASSERT(mutex->locked);
-#endif /* SILC_THREADS */
-}
-
-
-/***************************** SILC Rwlock API ******************************/
-
-/* SILC read/write lock structure */
-struct SilcRwLockStruct {
-#ifdef SILC_THREADS
- SilcMutex mutex;
- SilcCond cond;
-#endif /* SILC_THREADS */
- unsigned int readers : 31;
- unsigned int locked : 1;
-};
-
-SilcBool silc_rwlock_alloc(SilcRwLock *rwlock)
-{
-#ifdef SILC_THREADS
- *rwlock = silc_calloc(1, sizeof(**rwlock));
- if (!(*rwlock))
- return FALSE;
- if (!silc_mutex_alloc(&(*rwlock)->mutex)) {
- silc_free(*rwlock);
- return FALSE;
- }
- if (!silc_cond_alloc(&(*rwlock)->cond)) {
- silc_mutex_free((*rwlock)->mutex);
- silc_free(*rwlock);
- return FALSE;
- }
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_free(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (mutex) {
- silc_mutex_free(rwlock->mutex);
- silc_cond_free(rwlock->cond);
- silc_free(rwlock);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_rdlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_lock(rwlock->mutex);
- rwlock->readers++;
- silc_mutex_unlock(rwlock->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_wrlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- silc_mutex_lock(rwlock->mutex);
- while (rwlock->readers > 0)
- silc_cond_wait(rwlock->cond, rwlock->mutex);
- rwlock->locked = TRUE;
- }
-#endif /* SILC_THREADS */
-}
-
-void silc_rwlock_unlock(SilcRwLock rwlock)
-{
-#ifdef SILC_THREADS
- if (rwlock) {
- if (rwlock->locked) {
- /* Unlock writer */
- rwlock->locked = FALSE;
- silc_mutex_unlock(rwlock->mutex);
- return;
- }
-
- /* Unlock reader */
- silc_mutex_lock(rwlock->mutex);
- rwlock->readers--;
- silc_cond_broadcast(rwlock->cond);
- silc_mutex_unlock(rwlock->mutex);
- }
-#endif /* SILC_THREADS */
-}
-
-
-/**************************** SILC Cond API ******************************/
-
-/* SILC Conditional Variable context */
-struct SilcCondStruct {
-#ifdef SILC_THREADS
- HANDLE event;
-#endif /* SILC_THREADS*/
- unsigned int waiters : 23;
- unsigned int signal : 1;
-};
-
-SilcBool silc_cond_alloc(SilcCond *cond)
-{
-#ifdef SILC_THREADS
- *cond = silc_calloc(1, sizeof(**cond));
- if (*cond == NULL)
- return FALSE;
- (*cond)->event = CreateEvent(NULL, TRUE, FALSE, NULL);
- return TRUE;
-#else
- return FALSE;
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_free(SilcCond cond)
-{
-#ifdef SILC_THREADS
- CloseHandle(cond->event);
- silc_free(cond);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_signal(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->signal = TRUE;
- SetEvent(cond->event);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_broadcast(SilcCond cond)
-{
-#ifdef SILC_THREADS
- cond->signal = TRUE;
- SetEvent(cond->event);
-#endif /* SILC_THREADS*/
-}
-
-void silc_cond_wait(SilcCond cond, SilcMutex mutex)
-{
-#ifdef SILC_THREADS
- silc_cond_timedwait(cond, mutex, NULL);
-#endif /* SILC_THREADS*/
-}
-
-SilcBool silc_cond_timedwait(SilcCond cond, SilcMutex mutex,
- int timeout)
-{
-#ifdef SILC_THREADS
- DWORD ret, t = INFINITE;
-
- if (timeout)
- t = timeout;
-
- while (TRUE) {
- cond->waiters++;
- silc_mutex_unlock(mutex);
-
- ret = WaitForSingleObject(cond->event, t);
-
- silc_mutex_lock(mutex);
- cond->waiters--;
-
- if (ret != WAIT_OBJECT_0)
- return FALSE;
-
- if (cond->signal) {
- cond->signal = FALSE;
- ResetEvent(cond->event);
- break;
- }
- }
-#endif /* SILC_THREADS*/
- return TRUE;
-}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2006 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
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
*/
/* $Id$ */
-#include "silc.h"
+#include "silcincludes.h"
/* XXX GNU regex may work on Win32 too!! */
char *silc_string_regexify(const char *string)
const BYTE DWLEN = sizeof(DWORD) * 8;
/* Return current time in struct timeval. Code ripped from some xntp
- implementation. */
+ implementation on http://src.openresources.com. */
int silc_gettimeofday(struct timeval *tv)
{
FILETIME ft;
- __int64 usec;
-
+ __int64 msec;
+
GetSystemTimeAsFileTime(&ft);
- usec = (__int64) ft.dwHighDateTime << DWLEN | ft.dwLowDateTime;
- usec = (usec - FILETIME_1970) / 10;
- tv->tv_sec = (long) (usec / 1000000);
- tv->tv_usec = (long) (usec % 1000000);
+ msec = (__int64) ft.dwHighDateTime << DWLEN | ft.dwLowDateTime;
+ msec = (msec - FILETIME_1970) / 10;
+ tv->tv_sec = (long) (msec / 1000000);
+ tv->tv_usec = (long) (msec % 1000000);
return 0;
}
{
return silc_get_username();
}
-
-int silc_file_set_nonblock(int fd)
-{
- return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
-}
+++ /dev/null
-<!--
-@LIBRARY=SILC VCard Library
-@FILENAME=silcvcardlib.html
-@LINK=silcvcard.html:SILC VCard Interface
--->
-
-<big><b>SILC VCard Library</b></big>
-<br />
-<small>Directory: lib/silcvcard/</small>
-<br />
-<small>Library: libvcard.a, libvcard.lib</small>
-<br /><br />
-<b>Introduction</b>
-
-<br /><br />
-SILC VCard Library provides interface for creating and processing VCards,
-defined in the RFC 2426. The VCard 3.0 standard is implemented by the
-library.
-
-<br /><br />
-@LINKS@
+++ /dev/null
-#
-# Makefile.ad
-#
-# Author: Pekka Riikonen <priikone@silcnet.org>
-#
-# Copyright (C) 2006 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 = libsilcvcard.la
-
-libsilcvcard_la_SOURCES = \
- silcvcard.c
-
-#ifdef SILC_DIST_TOOLKIT
-include_HEADERS = \
- silcvcard.h
-
-#SILC_EXTRA_DIST = tests
-#endif SILC_DIST_TOOLKIT
-
-EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
-
-include $(top_srcdir)/Makefile.defines.in
+++ /dev/null
-#!/bin/sh
-
-files=`find . -type f -name \*\.[ch]`
-
-for i in $files
-do
- cp $i $i.tmp
- sed -e '/bool /s//SilcBool /' -e '/(bool)/s//(SilcBool)/' -e '/(bool *)/s//(SilcBool *)/' $i.tmp >$i
- rm $i.tmp
-done
+++ /dev/null
-# Clean -fprofile-arcs files
-#!/bin/sh
-
-find . -name \*\.gc?? -type f -print | xargs rm -f
+++ /dev/null
-#!/bin/sh
-#
-# 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.
-#
-# Usage: ./fsmgraph file | dot -Tps -o outfile.ps
-#
-# Graphviz dot is required to create the graphs.
-
-##############################################################################
-
-# Get the starts
-starts=`awk '/^SILC_FSM_STATE\(/,/^}/ { next } { print }' $@ | grep "silc_fsm_start" | cut -d, -f2 | cut -d\) -f1`
-
-# Get all states
-states=`grep "^SILC_FSM_STATE(" $@ | grep -v ");" | cut -d\( -f2 | cut -d\) -f1`
-
-# Output the graph
-echo "digraph G {"
-
-# Draw starts
-for i in $starts
-do
- echo "\"start $i\" [shape=plaintext];"
- echo "\"start $i\" -> $i;"
-done
-
-# Draw states and transitions
-for i in $states
-do
- echo "$i;"
-
- # This weird line gets us all state transitions and their optioanl
- # comment lines which be put as labels
- tr=`cat $@ | grep -v "^SILC_FSM_STATE($i);" | awk '/^SILC_FSM_STATE\('$i'\)/,/^}/ { if (/\/\*\* /) print; if (/silc_fsm_next/) print; }' | sed 's/^[ ]*//; s/\\/\\*\\* /L:/; s/\\*\\///; s/silc_fsm_next/T:silc_fsm_next/' | sed '/L:/s/ /\\\\/g; /T:/s/ /\\\\/g; s/T:/T: /; s/L:/L: /'`
-
- # Get thread starts
- threads=`cat $@ | grep -v "^SILC_FSM_STATE($i);" | awk '/^SILC_FSM_STATE\('$i'\)/,/^}/ { if (/\/\*\*\* /) print; if (/silc_fsm_start/) print; }' | sed 's/^[ ]*//; s/\\/\\*\\*\\* /L:/; s/\\*\\///; s/silc_fsm_start/T:silc_fsm_start/' | sed '/L:/s/ /\\\\/g; /T:/s/ /\\\\/g; s/T:/T: /; s/L:/L: /'`
-
- # Get async calls
- asyncs=`cat $@ | grep -v "^SILC_FSM_STATE($i);" | awk '/^SILC_FSM_STATE\('$i'\)/,/^}/ { if (/SILC_FSM_CALL\(/) print; }' | sed 's/SILC_FSM_CALL(//' | cut -d= -f2 | cut -d\( -f1`
-
- trname=""
- label=""
-
- # Draw transitions
- for t in $tr
- do
- if test "$t" = "L:"; then
- label="$t"
- continue
- fi
- if test "$t" = "T:"; then
- trname="$t"
- continue
- fi
- if test "$label" = "L:"; then
- label="$t"
- continue
- fi
- if test "$trname" = "T:"; then
- trname="$t"
- fi
-
- # Unescape
- if test "$label"; then
- label=`echo $label | sed 's/\\\\/ /g'`
- fi
- trname=`echo $trname | sed 's/\\\\/ /g'`
- trname=`echo $trname | cut -d, -f2 | cut -d\) -f1`
-
- echo "$i -> $trname [label=\" $label \"];"
-
- trname=""
- label=""
- done
-
- # Draw thread transitions
- for t in $threads
- do
- if test "$t" = "L:"; then
- label="$t"
- continue
- fi
- if test "$t" = "T:"; then
- trname="$t"
- continue
- fi
- if test "$label" = "L:"; then
- label="$t"
- continue
- fi
- if test "$trname" = "T:"; then
- trname="$t"
- fi
-
- # Unescape
- if test "$label"; then
- label=`echo $label | sed 's/\\\\/ /g'`
- fi
- trname=`echo $trname | sed 's/\\\\/ /g'`
- trname=`echo $trname | cut -d, -f2 | cut -d\) -f1`
-
- echo "$i -> $trname [label=\" $label \"] [style=dotted];"
-
- trname=""
- label=""
- done
-
- # Draw async calls
- for a in $asyncs
- do
- echo "\"$a\" [shape=plaintext];"
- echo "$i -> \"$a\" [style=dotted];"
- done
-done
-
-echo "}"
+++ /dev/null
-/* silcdefs.h. Generated from silcdefs.h.in by configure. */
-/* silcdefs.h.in. Generated from configure.ac by autoheader. */
-
-/* Define to 1 if you have the <arpa/inet.h> header file. */
-#define HAVE_ARPA_INET_H 1
-
-/* Define to 1 if you have the <assert.h> header file. */
-#define HAVE_ASSERT_H 1
-
-/* Define to 1 if you have the `bind' function. */
-#define HAVE_BIND 1
-
-/* Define to 1 if you have the `chmod' function. */
-#define HAVE_CHMOD 1
-
-/* Define to 1 if you have the `close' function. */
-#define HAVE_CLOSE 1
-
-/* Define to 1 if you have the `connect' function. */
-#define HAVE_CONNECT 1
-
-/* Define to 1 if you have the `ctime' function. */
-#define HAVE_CTIME 1
-
-/* Define to 1 if you have the <ctype.h> header file. */
-#define HAVE_CTYPE_H 1
-
-/* Define to 1 if you have the <errno.h> header file. */
-#define HAVE_ERRNO_H 1
-
-/* Define to 1 if you have the `fcntl' function. */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `fstat' function. */
-#define HAVE_FSTAT 1
-
-/* Define to 1 if you have the `getenv' function. */
-#define HAVE_GETENV 1
-
-/* Define to 1 if you have the `getgid' function. */
-#define HAVE_GETGID 1
-
-/* Define to 1 if you have the `gethostbyaddr' function. */
-#define HAVE_GETHOSTBYADDR 1
-
-/* Define to 1 if you have the `gethostname' function. */
-#define HAVE_GETHOSTNAME 1
-
-/* Define to 1 if you have the `getpgid' function. */
-#define HAVE_GETPGID 1
-
-/* Define to 1 if you have the `getpgrp' function. */
-#define HAVE_GETPGRP 1
-
-/* Define to 1 if you have the `getpid' function. */
-#define HAVE_GETPID 1
-
-/* Define to 1 if you have the `getservbyname' function. */
-#define HAVE_GETSERVBYNAME 1
-
-/* Define to 1 if you have the `getservbyport' function. */
-#define HAVE_GETSERVBYPORT 1
-
-/* Define to 1 if you have the `getsid' function. */
-#define HAVE_GETSID 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#define HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the `getuid' function. */
-#define HAVE_GETUID 1
-
-/* Define to 1 if you have the `initgroups' function. */
-#define HAVE_INITGROUPS 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
-
-/* Define to 1 if you have the `listen' function. */
-#define HAVE_LISTEN 1
-
-/* Define to 1 if you have the <locale.h> header file. */
-#define HAVE_LOCALE_H 1
-
-/* Define to 1 if you have the `memcpy' function. */
-#define HAVE_MEMCPY 1
-
-/* Define to 1 if you have the `memmove' function. */
-#define HAVE_MEMMOVE 1
-
-/* Define to 1 if you have the `memset' function. */
-#define HAVE_MEMSET 1
-
-/* Define to 1 if you have the <netdb.h> header file. */
-#define HAVE_NETDB_H 1
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-#define HAVE_NETINET_IN_H 1
-
-/* Define to 1 if you have the `nl_langinfo' function. */
-#define HAVE_NL_LANGINFO 1
-
-/* Define to 1 if you have the <paths.h> header file. */
-#define HAVE_PATHS_H 1
-
-/* Define to 1 if you have the `poll' function. */
-#define HAVE_POLL 1
-
-/* Define to 1 if you have the `putenv' function. */
-#define HAVE_PUTENV 1
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define to 1 if you have the `select' function. */
-#define HAVE_SELECT 1
-
-/* Define to 1 if you have the `setgroups' function. */
-#define HAVE_SETGROUPS 1
-
-/* Define to 1 if you have the `setrlimit' function. */
-#define HAVE_SETRLIMIT 1
-
-/* Define to 1 if you have the `setsockopt' function. */
-#define HAVE_SETSOCKOPT 1
-
-/* Define to 1 if you have the <signal.h> header file. */
-#define HAVE_SIGNAL_H 1
-
-/* Define to 1 if you have the `stat' function. */
-#define HAVE_STAT 1
-
-/* Define to 1 if you have the <stddef.h> header file. */
-#define HAVE_STDDEF_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the `strchr' function. */
-#define HAVE_STRCHR 1
-
-/* Define to 1 if you have the `strcpy' function. */
-#define HAVE_STRCPY 1
-
-/* Define to 1 if you have the `strerror' function. */
-#define HAVE_STRERROR 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strncpy' function. */
-#define HAVE_STRNCPY 1
-
-/* Define to 1 if you have the `strstr' function. */
-#define HAVE_STRSTR 1
-
-/* Define to 1 if you have the <sys/resource.h> header file. */
-#define HAVE_SYS_RESOURCE_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the `time' function. */
-#define HAVE_TIME 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* HAVE_VA_COPY */
-//#define HAVE_VA_COPY
-#define HAVE_VA_COPY_AARRAY
-
-/* Name of package */
-#define PACKAGE "silc-toolkit"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "Toolkit"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "Toolkit 1.1"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "toolkit"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.1"
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#define RETSIGTYPE void
-
-/* SILC_DOCDIR */
-#define SILC_DOCDIR "/usr/local/silc/doc"
-
-/* SILC_ETCDIR */
-#define SILC_ETCDIR "/usr/local/silc/etc"
-
-/* SILC_HELPDIR */
-#define SILC_HELPDIR "/usr/local/silc/help"
-
-/* SILC_I386 */
-/* #undef SILC_I386 */
-
-/* SILC_I486 */
-/* #undef SILC_I486 */
-
-/* SILC_IA64 */
-/* #undef SILC_IA64 */
-
-/* SILC_MODULESDIR */
-#define SILC_MODULESDIR "/usr/local/silc/modules"
-
-/* GMP */
-/* #undef SILC_MP_GMP */
-
-/* SILCMATH */
-#define SILC_MP_SILCMATH
-
-/* SILC_NO_ASM */
-/* #undef SILC_NO_ASM */
-
-/* SILC_POWERPC */
-/* #undef SILC_POWERPC */
-
-/* SILC_STACKTRACE */
-/* #undef SILC_STACKTRACE */
-
-/* HAVE_THREAD */
-#define SILC_THREADS
-
-/* SILC_VA_COPY_ARRAY */
-/* #undef SILC_VA_COPY_ARRAY */
-
-/* SILC_WIN32 */
-/* #undef SILC_WIN32 */
-
-/* SILC_X86_64 */
-/* #undef SILC_X86_64 */
-
-/* The size of `char', as computed by sizeof. */
-#define SIZEOF_CHAR 1
-
-/* The size of `int', as computed by sizeof. */
-#define SIZEOF_INT 4
-
-/* The size of `long', as computed by sizeof. */
-#define SIZEOF_LONG 4
-
-/* The size of `long long', as computed by sizeof. */
-#define SIZEOF_LONG_LONG 8
-
-/* The size of `short', as computed by sizeof. */
-#define SIZEOF_SHORT 2
-
-/* The size of `void *', as computed by sizeof. */
-#define SIZEOF_VOID_P 4
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define VERSION "1.1"
-
-/* Define to 1 if your processor stores words with the most significant byte
- first (like Motorola and SPARC, unlike Intel and VAX). */
-/* #undef WORDS_BIGENDIAN */
*/
-#include "silc.h" /* Mandatory include for SILC applications */
+#include "silcincludes.h" /* Mandatory include for SILC applications */
#include "silcclient.h" /* SILC Client Library API */
SilcClientOperations ops;
silc_identifier_verify @ 925 ;\r
silc_channel_name_check @ 926 ;\r
silc_channel_name_verify @ 927 ;\r
+ silc_mime_alloc @ 928;\r
+ silc_mime_free @ 929;\r
+ silc_mime_assembler_alloc @ 930;\r
+ silc_mime_assembler_free @ 931;\r
+ silc_mime_decode @ 932;\r
+ silc_mime_encode @ 933;\r
+ silc_mime_assemble @ 934;\r
+ silc_mime_encode_partial @ 935;\r
+ silc_mime_partial_free @ 936;\r
+ silc_mime_add_field @ 937;\r
+ silc_mime_get_field @ 938;\r
+ silc_mime_add_data @ 939;\r
+ silc_mime_get_data @ 940;\r
+ silc_mime_is_partial @ 941;\r
+ silc_mime_set_multipart @ 942;\r
+ silc_mime_is_multipart @ 943;\r
+ silc_mime_add_multipart @ 944;\r
+ silc_mime_get_multiparts @ 945;\r
+ silc_sha256_context_len @ 946 ;\r
+ silc_sha256_final @ 947 ;\r
+ silc_sha256_init @ 948 ;\r
+ silc_sha256_transform @ 949 ;\r
+ silc_sha256_update @ 950 ;\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silcutil\silcmime.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silcutil\silcnet.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silccrypt\sha256.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silccrypt\silccipher.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silcutil\silcmime.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silcutil\silcmutex.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silccrypt\sha256.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\sha256_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silccrypt\silccipher.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silcutil\silcmime.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silcutil\silcnet.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silccrypt\sha256.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silccrypt\silccipher.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silcutil\silcmime.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silcutil\silcmutex.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\lib\silccrypt\sha256.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\sha256_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\..\lib\silccrypt\silccipher.h\r
# End Source File\r
# Begin Source File\r