283 Commits

Author SHA1 Message Date
Dmitry Podgorny
a4b05cf156 Release libstrophe-0.9.2 2018-02-23 14:19:15 +02:00
Dmitry Podgorny
06da6d5125 autotools: remove -Werror
We need it only in development versions. Let releases build with
warnings.
2018-02-23 14:19:15 +02:00
Dmitry Podgorny
1bcf77608d crypto: fix typos in comments 2018-02-23 14:05:56 +02:00
Dmitry Podgorny
aab0cc3e3e parser/libxml2: clear parser->stanza properly
- Release stanza in parser_free()
 - Clear parser->stanza even if xmlCreatePushParserCtxt() fails
2018-02-18 14:51:16 +02:00
Dmitry Podgorny
822f95071a sasl: fix memory leak in DIGEST-MD5 implementation
Don't add "qop" two times to hash table, otherwise, an entry is lost
without freeing memory.
2018-02-18 14:02:17 +02:00
Dmitry Podgorny
27f613bc84 stanza: small fixes in xmpp_error_new()
- Receive const text
 - Move variable declaration to the beginning of the block
2018-02-18 13:18:43 +02:00
Dmitry Podgorny
af1ef3855b resolver: suppress warning in windows code 2018-02-18 13:08:16 +02:00
Dmitry Podgorny
7ede9c6d03 tls/openssl: suppress error in special case in tls_stop()
When peer closes connection instead of proper shutdown SSL_shutdown()
fails in bidirectional mode. Handle this case and suppress the error.
2018-02-18 12:03:11 +02:00
Dmitry Podgorny
20c6f225b9 ChangeLog: add missed changes 2018-02-18 10:42:21 +02:00
Scott M Anderson
5b204b0938 fix strtok_r test on MSW 2018-02-18 09:55:33 +02:00
Dmitry Podgorny
6e6093ee7b stanza: fix xmpp_error_new() in #115
* Don't set text to a tag stanza. It returns XMPP_INVOP.
 * Don't use stanza after releasing own reference.
2017-09-12 17:45:11 +03:00
Dmitry Podgorny
f12d43989f stanza: removed tabs and trailing spaces 2017-09-12 17:36:28 +03:00
Ilya Orlov
032e8ec89d Added new stanza for error responce, libstrophe now will be responce <stream:error> if parser failed 2017-09-04 11:46:09 +03:00
Dmitry Podgorny
d0644c5e95 tls/openssl: print errno on unrecoverable error 2017-08-23 09:23:51 +03:00
Dmitry Podgorny
b1b827cde6 conn: clear features support on connection reset
Features may be changed when client reconnects.
2017-07-15 21:32:55 +03:00
Dmitry Podgorny
e73b577e0b auth: use xmpp_iq_new() for iq stanzas 2017-07-15 20:35:16 +03:00
Dmitry Podgorny
8d2d59e914 tls/openssl: add OpenSSL-1.1.0 support (#109)
OpenSSL-1.1.0 marks cleanup functions as deprecated and changes
initialization function. It implements implicit de-initialization.

Reported by @zygmund2000.
2017-07-12 02:07:14 +03:00
Dmitry Podgorny
212f3ea760 snprintf: fix compilation with GCC 7 (#108)
GCC 7 enables -Wimplicit-fallthrough=3 with -Wextra. Add comments to
suppress these warning explicitly.

Reported by @akoww
2017-07-11 03:21:31 +03:00
Dmitry Podgorny
4aa7ea7e5b parser/expat: update #47
@curse666 suggested solution for #46 which reduces memory usage in expat
module. Current patch fixes few issues:
  - Inner text is lost for depth 1 stanzas
  - Incorrect handling of mixed xml <x>text<y/></x>
  - Reduced number of realloc() calls
2017-07-06 22:32:20 +03:00
curse666
5f9c0399c3 Update parser_expat.c
solution for #46.
2017-07-06 19:25:20 +03:00
Dmitry Podgorny
b83347b464 examples: use xmpp_iq_new() 2017-07-06 15:47:19 +03:00
Dmitry Podgorny
d8a86a54d5 event: set socket to wfds when sending queue is not empty
Don't sleep in select(2) when system is ready to send data.
2017-07-05 20:36:34 +03:00
Dmitry Podgorny
49289a9c05 event: reduce copy-paste 2017-07-05 20:34:38 +03:00
Dmitry Podgorny
456083d878 stanza: fix memory leaks
Free attribute "to" before replacing it in xmpp_stanza_reply().
Free value on insertion error in xmpp_stanza_set_attribute().
Don't copy attributes manually. Use xmpp_stanza_set_attribute() instead.
2017-07-05 20:20:45 +03:00
Dmitry Podgorny
15e7032f0d examples/bot: handle quit message 2017-07-05 19:40:25 +03:00
Dmitry Podgorny
cd2cf6eb23 ctx: set default event loop timeout to 1 second
Default timeout was 1 millisecond and it consumed CPU by running the
loop in xmpp_run(). The CPU usage was unacceptable and thus xmpp_run()
was not used by users. Also user can set the timeout by
xmpp_ctx_set_timeout() now.

Event loop already handles the situation when there is a timed handler
which needs to be run before the timeout is reached. Also system awakes
event loop when data arrives to socket.

The only drawback is when timed handler sends data it will be actually
sent after select(2) returns. But this situation can be handled easily by
adding socket to wfds when xmpp_conn_t contains data in sending queue.
2017-07-05 15:47:13 +03:00
Dmitry Podgorny
666995531a ChangeLog: mention recent changes
- Certificate verification is enabled for all openssl versions by
   default
 - xmpp_ctx_set_timeout()
 - Move xmpp_ctx_set_timeout() to event loop section in strophe.h
2017-07-04 19:22:26 +03:00
Dmitry Podgorny
9269d6b0d5 conn: add flag XMPP_CONN_FLAG_TRUST_TLS
TLS modules accept invalid server's certificates when the flag is set.
2017-07-04 17:20:33 +03:00
Dmitry Podgorny
c319ee6583 handler: fix memory leak and use-after-free errors
The errors are related to newly added handler_system_delete_all().
2017-07-01 16:24:30 +03:00
Dmitry Podgorny
cc53012cfa tls/openssl: enable cert verification for openssl older then 1.0.2
TODO: add flag to trust certificate even if verification fails.
2017-07-01 15:51:49 +03:00
Dmitry Podgorny
cc297eff45 handler: shut compiler up
Fixes the next warning:
    src/handler.c:683:25: error: ‘key2’ may be used uninitialized in
    this function [-Werror=uninitialized]

In fact key2 initialised and used under the same condition.
2017-06-29 20:43:03 +03:00
Dmitry Podgorny
e151096834 handler: don't call time_stamp() twice in handler_fire_timed() 2017-06-29 20:22:55 +03:00
Dmitry Podgorny
82040403bf tests/hash: enable the test 2017-06-29 20:22:55 +03:00
Dmitry Podgorny
a845c7ec3d hash: avoid allocation when replace value in hash_add()
Memory allocation may fail. We don't need to allocate new entry when we
already have one.
2017-06-29 20:22:55 +03:00
Dmitry Podgorny
5ecb0c5d0c conn: clear system handlers on reconnect
xmpp_conn_t object can be reused with saving user's handlers.
However, saving system handlers can lead to a fail during connection
process. This is because old object may contain timed handlers for
missed features or other handlers that would handle incoming stanzas
incorrectly.
2017-06-29 20:22:55 +03:00
Dmitry Podgorny
da8dc2d3cb auth: don't delete stream:error handler
Instead, keep the same handler until connection is disconnected. Stream
is opened 3 times during usual workflow. Deleting/restoring the handler
every time brings more places for possible mistakes.
2017-06-29 20:13:16 +03:00
Dmitry Podgorny
182695d1ca resolver: fix type mismatch in windows part
Backported from NetXMS project.
2017-06-29 20:00:25 +03:00
Dmitry Podgorny
0d039f7192 parser/libxml2: fix missed {} for multi-line block 2017-06-29 19:33:26 +03:00
Dmitry Podgorny
ebe97e8f2a travis-ci: don't use custom CFLAGS
Makefile.am provides -Wall and -Werror now.
2017-06-29 19:00:54 +03:00
Dmitry Podgorny
9505cace5e ctx: don't check whether log level is less than XMPP_LEVEL_DEBUG
XMPP_LEVEL_DEBUG is always 0.
2017-06-29 18:49:54 +03:00
Dmitry Podgorny
8ef027c54a ctx: fix indentation in xmpp_ctx_set_timeout() 2017-06-29 18:49:54 +03:00
Dmitry Podgorny
0bdb5f1d5b examples/vcard: fix warn_unused_result related to fwrite() 2017-06-29 18:49:54 +03:00
Steffen Jaeckel
49e7572059 fix function-pointer storage
the C standard says that you're not allowed to cast a function pointer to
something else

 6.3.2.3 §8:

A pointer to a function of one type may be converted to a pointer
to a function of another type and back again
2017-06-29 16:58:11 +02:00
Steffen Jaeckel
c074a6166c enable some warnings & fix 'em 2017-06-29 16:58:11 +02:00
Steffen Jaeckel
4c504ee42b add xmpp_ctx_set_timeout() 2017-06-29 16:58:11 +02:00
Steffen Jaeckel
f226891520 fix openssl memory leaks 2017-06-29 16:54:41 +02:00
Dmitry Podgorny
43a68479ad ChangeLog: mention about disabled insecure SSL/TLS
See f47609c1f0
2017-06-26 01:09:24 +03:00
Dmitry Podgorny
1e422a70dd crypto: add public function xmpp_sha1_digest()
For example, XEP-0115 requires binary digest to be base64-encoded.
Add short function to simplify such a digest computation for a single
buffer. This function doesn't allocate memory. Therefore, it can't
fail and doesn't require strophe context (xmpp_ctx_t).
2017-06-26 00:56:03 +03:00
Dmitry Podgorny
2a474bd809 tls/schannel: fix memory leak
Assume InitializeSecurityContext() doesn't change pszTargetName.
Reported by @youzpp in metajack/libstrophe#35.
2017-06-25 22:12:16 +03:00
Dmitry Podgorny
704c157d24 hash: don't use signed types during index calculation
Reported by @ITikhonov in pasis/libcouplet#10
2017-06-25 21:59:27 +03:00
Dmitry Podgorny
d8528b597c parser/libxml2: shorten parser_feed() 2017-06-25 21:19:15 +03:00
Dmitry Podgorny
c149caa32a examples: add vcard example
New exmaple shows how to request vCard and handle result. See XEP-0054
for details.
PHOTO element is stored to an image file.
2017-06-23 22:09:28 +03:00
Dmitry Podgorny
fa63aac731 auth: delete error handler before re-opening stream 2017-06-23 21:51:44 +03:00
Dmitry Podgorny
ba40bf1040 handler: fix possible corruption of handler lists
User's handler may delete other handlers. If deleted handler is the next
or the previous to the running one it leads to a list corruption.
Don't cache previous/next items when we walk through a handler's list.
2017-06-23 21:47:10 +03:00
Alexander Krotov
2f9bcfe145 Test xmpp_jid_bare 2017-06-23 20:00:41 +03:00
Alexander Krotov
b957213fdc Simplify xmpp_jid_{bare,domain,resource} 2017-06-23 19:55:12 +03:00
Alexander Krotov
f51b01a5b3 Remove unused mutex wrappers 2017-06-23 17:58:42 +03:00
Dmitry Podgorny
d2efc85ce3 Makefile.am: refactoring
Put filenames to separated lines to simplify adding/removing new files.
Add missed files to EXTRA_DIST.
2017-06-23 17:00:26 +03:00
Dmitry Podgorny
940d76e9e2 rpm: update dependencies 2017-06-23 16:57:27 +03:00
Dmitry Podgorny
59eb8d67ed ChangeLog: mention significant changes since 0.9.1 2017-06-23 16:55:31 +03:00
Dmitry Podgorny
78592650e5 tls/schannel: reflect changes of the tls interface
tls_new() accepts xmpp_conn_t object now.
2017-06-23 15:37:09 +03:00
Alexander Krotov
92d006a41b Disable hostname verification for pre-1.0.2 OpenSSL 2017-06-23 13:45:24 +03:00
Alexander Krotov
0741820711 Verify certificate hostname when using OpenSSL (fixes #100) 2017-06-23 03:00:26 +03:00
Alexander Krotov
c9ddc2b7ef Make tls_new accept xmpp_conn_t 2017-06-23 02:59:05 +03:00
Alexander Krotov
f776b34d8c Fix tls_openssl.c indentation 2017-06-22 19:44:41 +03:00
Alexander Krotov
f47609c1f0 Disable insecure SSL/TLS versions 2017-06-20 22:44:39 +03:00
Alexander Krotov
443b4d3116 Use more variables in bot.c message_handler()
to avoid calling the same function twice.
2017-06-20 01:38:53 +03:00
Steffen Jaeckel
4cf7a0cb79 split travis build into multiple jobs 2017-04-04 18:25:27 +02:00
Dmitry Podgorny
9a5fe8b96d handler: allow to add same handler callback with different userdata
According to #97. A single callback can distinguish different cases
using the userdata. Current implementation doesn't allow to delete a
particular couple (handler, userdata), but rather deletes all handlers
regardless of the userdata.
2017-03-24 22:38:16 +02:00
Dmitry Podgorny
80a7ea0b7c Fix spacing in handler.c 2016-12-02 16:56:45 +02:00
Dmitry Podgorny
1092447edf Fix spacing in c++ files 2016-09-27 15:40:08 +03:00
Dmitry Podgorny
d2c1daf4d5 Fix spacing in ctx.c and common.h 2016-09-27 15:14:38 +03:00
Dariusz Dwornikowski
d1a41c9d7d Fixed occurred spelling error fixes: #96 2016-09-23 08:31:31 +02:00
Dmitry Podgorny
9931ad4fa2 Updated ChangeLog
- Fixed bug #95 (DNS lookup failing on Cygwin)
- Removed dependency on the check package
2016-09-16 01:10:25 +03:00
Dmitry Podgorny
5a1f282292 README: remove mention of the check dependency 2016-09-16 01:07:21 +03:00
Dmitry Podgorny
b360316b8b tests/resolver: added test case with pointers 2016-09-16 01:01:43 +03:00
Dmitry Podgorny
c6aaa96dcb resolver: fixed few bugs
Fixed a bug which caused resolver to return a wrong target name with a
missed ".". The bug was in the part of message_name_get() where a pointer
is handled.
Added checks for buffer overflow.
Added 2 test cases to check a corner case and error handling.
2016-09-15 19:26:10 +03:00
Dmitry Podgorny
f0706f56c4 tests: remove dependency on check package
Only check_parser depends on the check. Convert it. All tests will be
rewritten at once when new testsuite is implemented.
2016-09-15 12:46:11 +03:00
James Booth
4ef2740c36 Update version to 0.9.1 2016-09-14 19:53:25 +01:00
Dmitry Podgorny
5e0330f0ad libstrophe 0.9.0
See ChangeLog for significant changes or follow the link to see all the
changes:
  https://github.com/strophe/libstrophe/compare/0.8.8...strophe:0.9.0
2016-09-14 18:55:48 +03:00
Dmitry Podgorny
717a19859f doc: describe parameters to suppress doxygen warnings 2016-09-14 18:54:40 +03:00
Dmitry Podgorny
209f21905e Update Doxyfile
Updated Doxyfile with doxygen -u. Removed DOT_FONTNAME. Changed version
to 0.9.
2016-09-14 18:52:20 +03:00
Dmitry Podgorny
38aa05624d Add warning about disabled TLS in build-android.sh
OpenSSL or BoringSSL will be added to build-android.sh in the future.
But for now users need to build libstrophe with openssl manually if
they use ndk-build system.
2016-09-14 18:12:47 +03:00
Dmitry Podgorny
136055024e conn: update documentation for xmpp_connect_raw() 2016-09-14 17:49:10 +03:00
Michael Vetter
8d3f3d837a Remove trailing dots from changelog
Without the trailing dots it looks more coherent to me.
2016-09-14 14:21:18 +02:00
Dmitry Podgorny
151debf7ee stanza: remove inline keyword from _render_update()
Let compiler make decisions about static funcions. Also we don't need to
support workarounds for specific compilers.
2016-09-08 15:04:34 +03:00
Dmitry Podgorny
d8da993a73 Don't write outside a buffer boundary
When xmpp_vsnprintf() received count == 0 it still performs write to the
buffer. This leads to a write outside allocated memory, when
xmpp_stanza_to_text() parses a specific stanza. Because of error in
_render_update() writing exactly buflen+1 with xmpp_snprintf() is counted
as valid operation and next xmpp_snprintf will be performed to a buffer
with zero length. This leads to wrong rendering of 1024-length stanzas
and invalid write for specific larger stanzas:

==22436== Invalid write of size 1
==22436==    at 0x4E4B3A1: xmpp_vsnprintf (snprintf.c:709)
==22436==    by 0x4E4B479: xmpp_snprintf (snprintf.c:722)
==22436==    by 0x4E4C011: _render_stanza_recursive (stanza.c:328)
==22436==    by 0x4E4C3B3: _render_stanza_recursive (stanza.c:384)
==22436==    by 0x4E4C3B3: _render_stanza_recursive (stanza.c:384)
==22436==    by 0x4E4C3B3: _render_stanza_recursive (stanza.c:384)
==22436==    by 0x4E4C3B3: _render_stanza_recursive (stanza.c:384)
==22436==    by 0x4E4C3B3: _render_stanza_recursive (stanza.c:384)
==22436==    by 0x4E4C4E5: xmpp_stanza_to_text (stanza.c:435)
==22436==    by 0x4E407A8: _handle_stream_stanza (conn.c:1157)
==22436==    by 0x4E4EF2B: _end_element (parser_expat.c:157)
==22436==    by 0x571005A: doContent (in /usr/lib64/libexpat.so.1.6.2)
==22436==  Address 0x63b95b0 is 0 bytes after a block of size 1,024 alloc'd
==22436==    at 0x4C2BFE0: malloc (vg_replace_malloc.c:299)
==22436==    by 0x4E41947: _malloc (ctx.c:116)
==22436==    by 0x4E41A54: xmpp_alloc (ctx.c:204)
==22436==    by 0x4E4C4A3: xmpp_stanza_to_text (stanza.c:428)
==22436==    by 0x4E407A8: _handle_stream_stanza (conn.c:1157)
==22436==    by 0x4E4EF2B: _end_element (parser_expat.c:157)
==22436==    by 0x571005A: doContent (in /usr/lib64/libexpat.so.1.6.2)
==22436==    by 0x57109FB: contentProcessor (in ...
==22436==    by 0x5712A9F: XML_ParseBuffer (in ...
==22436==    by 0x4E4F1E7: parser_feed (parser_expat.c:247)
==22436==    by 0x4E42BBC: xmpp_run_once (event.c:284)
==22436==    by 0x4E42D62: xmpp_run (event.c:336)

Fix xmpp_vsnprintf() and _render_update() behaviour.
2016-09-08 14:52:36 +03:00
Dmitry Podgorny
72173087a9 conn: move _disconnect_cleanup() to other static functions
Also remove trailing spaces.
2016-09-06 22:17:24 +03:00
Dmitry Podgorny
229215b49c conn: xmpp_conn_open_stream() sends user-supplied tag
Default opening tag doesn't allow to implement XEP-0174. In this case
client needs to send specific attributes. As solution user passes
attributes that are sent inside opening tag. Previous variant of this
function is renamed to xmpp_conn_open_stream_default().

The way to pass attributes is not the best one, but it's used to conform
existent interface of xmpp_stanza_get_attributes().

Remove "raw" suffix from functions that work with a raw connection.
2016-09-06 22:06:29 +03:00
Fredrik Fornwall
dd7aeff5d2 Avoid trying to link against libresolv for Android
Android does not have a separate libresolv library.
2016-09-06 01:24:26 +02:00
Dmitry Podgorny
3e95806d2e conn: suppress gcc warning
gcc with -O3 flag reports that 'host' and 'port' can be uninitialised.
But this is not true. Suppress the message.
2016-09-05 11:51:24 +03:00
Tim Nieradzik
7ad42add73 test_string: Fix failing strdup test
`rc` may be initialised with -1.
2016-09-05 09:11:55 +03:00
Garick Hamlin
936ddb0d15 Compute correct send_queue_len.
Previously this was incremented, but not decremented.  I've corrected
the code to decrement it.  It doesn't appear to be used anywhere, but
it is helpful to implement xmpp_graceful_stop().
2016-09-04 03:37:56 +03:00
Dmitry Podgorny
233094af10 tests/parser: include string.h explicitly 2016-09-04 03:35:28 +03:00
Dmitry Podgorny
94e84f0643 README: add travis status icon 2016-09-04 02:17:03 +03:00
Dmitry Podgorny
8662611a34 travis-ci: remove make install 2016-09-04 02:16:19 +03:00
Dmitry Podgorny
60e6c191e9 README: mention about pkg-config dependency 2016-09-04 02:06:26 +03:00
Dmitry Podgorny
211170822f Integrate with Travis-CI 2016-09-04 02:05:00 +03:00
Dmitry Podgorny
c80f99bc68 tests: add tests for string functions 2016-09-04 00:53:24 +03:00
Dmitry Podgorny
53e44aa0e3 util: added strtok_r implementation for old compilers
Visual studios older than 2005 don't have strtok_s() and according to
MSDN vs2005 has NOT thread-safe strtok().
2016-09-04 00:34:26 +03:00
Dmitry Podgorny
2b249130c9 ChangeLog: mention that xmpp_conn_t is reusable 2016-09-03 17:10:26 +03:00
Dmitry Podgorny
84fa4466ee conn: clear authenticated flag on reset 2016-09-03 17:09:21 +03:00
Dmitry Podgorny
beaaab5742 tls_schannel: don't force RC4 for TLS handshake
Leave default configuration. A particular server closes tcp connection
during negotiation otherwise.

tls_schannel is still broken and tls_read() fails with
SEC_E_UNSUPPORTED_FUNCTION error.
2016-09-03 16:38:43 +03:00
Dmitry Podgorny
f351d62355 tests/jid: fixed crash on QNX
QNX version of printf() doesn't check whether a string is valid or not.
Passing NULL pointer leads to a crash inside strlen(). Fix this with a
wrapper _s() which returns "<NULL>" for instead of NULL pointer.
Add checks before strcmp() to avoid crash in case of unexpected result
of the jid functions.
2016-09-02 19:57:25 +03:00
Dmitry Podgorny
b6fcb7035d rand: replace time() with time_stamp() as entropy source
time_stamp() has bigger precision.
2016-09-02 17:38:42 +03:00
Dmitry Podgorny
c0a224cf84 Remove const in parser_free() declaration
To match the definitions.
2016-09-02 17:10:51 +03:00
Dmitry Podgorny
384ef8023e auth: coding style 2016-09-02 17:10:14 +03:00
Dmitry Podgorny
f44232762e tls/schannel: remove unused variable 2016-09-02 17:09:47 +03:00
Dmitry Podgorny
111659cc91 ctx: add workaround for ms compilers without va_copy support 2016-09-02 15:22:31 +03:00
Dmitry Podgorny
4ae4b8c94b event: suppress warning about type overflow 2016-09-02 15:22:14 +03:00
Dmitry Podgorny
2b2de142ef tests/resolver: fix the test and add new testcase
It was broken because of changed API.
2016-09-02 12:45:28 +03:00
Dmitry Podgorny
a45af3a929 resolver: srv_rr_list can be uninitialised
Resolver assumes that srv_rr_list is empty at the beginning. Make it so
explicitly and let user pass uninitialised list as argument.
2016-09-02 12:39:10 +03:00
Dmitry Podgorny
3e77afb27e Fix type mismatch
Backported from NetXMS project.
2016-09-02 11:59:54 +03:00
Dmitry Podgorny
0c60e8d384 tls_openssl: coding style 2016-09-02 00:49:32 +03:00
Dmitry Podgorny
2bff3f8722 conn: unify error codes for API functions
Return error code from strophe.h instead of -1.
2016-09-02 00:49:32 +03:00
Dmitry Podgorny
dc56737b71 conn: implemented xmpp_connect_raw()
This function is similar to xmpp_connect_client(), but doesn't perform
authentication. Instead, it calls user's connection handler immediately
after establishing the connection. Hence, user can implement own
authendication or registration procedures.

Such a "raw" connection can be useful when user interaction is required
(e.g. Data Forms in XEP-0077, OAuth2).
2016-09-02 00:47:58 +03:00
Dmitry Podgorny
3869906357 Fixed spacing in event.c 2016-08-30 23:35:17 +03:00
Dmitry Podgorny
75b19be572 unify _sleep() macro in event.c 2016-08-30 19:43:05 +03:00
Dmitry Podgorny
b0a1842a53 examples/bot: fix memory leaks and use stanza helpers 2016-08-30 15:32:10 +03:00
Dmitry Podgorny
14066d0bff resolver: fix commit 171b285 2016-08-29 20:09:45 +03:00
Chih-Wei Chen
171b285cbe sock : Add DNS-SRV list sorted by priority and weight, check result connection. 2016-08-29 11:32:20 +03:00
Dmitry Podgorny
f46cf669a3 Android: added make files 2016-08-22 15:52:31 +03:00
James Booth
09e5103eee Update ChangeLog 2016-08-22 13:10:23 +01:00
Dmitry Podgorny
1a657c67e2 Fixed typo 2016-05-21 01:28:39 +03:00
Dmitry Podgorny
3e86987f5f sock: fixed build on cygwin
Cygwin doesn't have TCP_KEEPIDLE nor TCP_KEEPALIVE. Therefore, don't
change any tcp keepalive parameter on this system.
2016-05-11 11:30:21 +03:00
Dmitry Podgorny
e83d0d6b62 SCRAM-SHA-1: fixed base64-decoding of salt
Salt can contain 0x00, therefore must be decoded with
xmpp_base64_decode_bin().
2016-05-08 09:01:20 +03:00
Dmitry Podgorny
2ffb278aa4 Implemented public Base64 interface
Base64 is required for vCard avatars. It will also be useful for
an authentication mechanism with future xmpp_connect_raw() interface.
2016-04-30 18:09:01 +00:00
Dmitry Podgorny
7f57e3987a tests/resolver: don't link against -lstrophe 2016-04-30 16:40:10 +00:00
Dmitry Podgorny
c62d1d64ab tests/ctx: enable the test 2016-04-30 16:37:18 +00:00
Dmitry Podgorny
c9a5cba113 tests/jid: enable the test 2016-04-30 16:15:45 +00:00
Dmitry Podgorny
e4a4bdd3a3 Implemented public SHA1 interface
A number of XEPs require SHA1. Publishing its interface helps user to
reduce number of dependencies.
2016-04-29 22:51:23 +00:00
Dmitry Podgorny
565ace7982 tests/snprintf: undef HAVE_SNPRINTF and HAVE_VSNPRINTF 2016-04-29 22:51:23 +00:00
Dmitry Podgorny
71d90d60a5 Fixed comments inside strophe.h
Don't use doxygen comments in strophe.h since functions are documented
in *.c files.
Remove mutex from xmpp_log_t because libstrophe is single-thread
library.
2016-04-29 22:51:23 +00:00
Dmitry Podgorny
b5d9b33b6f Refactor rand
* Removed dependency from internal headers in rand.h. xmpp_rand
  interface can be public in the future;
* xmpp_rand functions accept xmpp_rand_t object instead of xmpp_ctx_t.
2016-04-29 22:51:23 +00:00
Dmitry Podgorny
063f4deb22 Refactor autotools scripts
* Add --disable-tls
* Check for libxml2 if expat is not found
* Single coding style
2016-04-28 22:37:27 +00:00
Dmitry Podgorny
192ab59608 resolver: fixed uninitialised var 2016-04-28 20:40:16 +00:00
Dmitry Podgorny
a3da77b8f6 stanza: return const char* for non allocated strings
If interface function returns char* the result must be freed with
xmpp_free().

In case of const char* the result must not be changed by user. Also, the
result is valid only during stanza lifetime.
2016-04-27 11:56:50 +00:00
Dmitry Podgorny
c0aad0bf00 README: describe autotools dependency 2016-04-27 11:54:04 +00:00
Dmitry Podgorny
a2834f8f92 conn: fixed doxygen comments 2016-04-26 20:27:25 +00:00
Dmitry Podgorny
2ef432f632 conn: xmpp_conn_set_keepalive() stores parameters in conn
Store keepalive parameters in conn object. This allows call the function
with a disconnected conn. Also, the parameters are not cleared on
reconnect and applied once a socket is created.
2016-04-26 19:48:34 +00:00
Dmitry Podgorny
a50d706bcd stanza: added helpers for particular stanzas
These are wrappers for message, iq and presence stanzas.
2016-04-26 19:19:51 +00:00
Dmitry Podgorny
ca7af9c837 Fixed indentation and typos 2016-04-26 19:19:51 +00:00
Dmitry Podgorny
a65679dd72 conn: removed unused fields from xmpp_conn_t 2016-04-26 13:03:16 +00:00
Dmitry Podgorny
211748e65a Replace bit mask hex values with shifts 2016-04-26 13:01:22 +00:00
Dmitry Podgorny
4c0c12343f sha1: moved SHA1HANDSOFF definition 2016-04-22 21:30:17 +00:00
Dmitry Podgorny
96873984b2 conn: handle stream tag properly
If `id == NULL' there were two issues: use-after-free error or
logging wrong error description.
Also open stream handler was called even when error occured and
conn object was disconnected.
2016-04-22 21:04:29 +00:00
Dmitry Podgorny
b06599963b conn: make xmpp_conn_t object reusable
Disconnected xmpp_conn_t object can be connected again. The object
is reset before connection, but the next fields remain untoucned:
  * all handlers
  * flags
  * jid and password

Main use-case of this change is reconnect when an error occurs.
2016-04-22 20:52:36 +00:00
Dmitry Podgorny
ab80d72518 tls/openssl: handle SSL_shutdown() properly
Handle SSL_ERROR_WANT_READ/WRITE and return value 0.
2016-04-19 19:57:52 +00:00
Dmitry Podgorny
ba7422c893 tls/openssl: be more verbose
Log non-recoverable errors. The openssl error queue can contain useful
information.
2016-04-19 18:21:27 +00:00
Dmitry Podgorny
4b444ea699 tls/openssl: fixed indentation 2016-04-19 16:33:47 +00:00
Dmitry Podgorny
96dc61c772 sock: use sock_close() instead of close() 2016-04-16 20:19:16 +00:00
Andrey (Stanson) Kozin
f5c2c81142 Added conn_send_queue_purge() function.
Function frees all data and clean send queue in
    xmpp_conn_release()
    xmpp_connect_client()
    xmpp_connect_component()
2016-04-15 16:08:24 +00:00
Dmitry Podgorny
838ed493a3 updated README.markdown 2016-04-15 15:56:22 +00:00
Dmitry Podgorny
9d7b3394e7 Makefile.am: updated EXTRA_DIST
'make dist' prepares complete tarballs now.
2016-04-15 15:51:12 +00:00
Dmitry Podgorny
9e4e274c4d updated examples/README.md 2016-04-14 15:23:38 +00:00
Tusharsb
e3b9fa1e53 tips for compiling example code
Me and a few more users (at
https://groups.google.com/forum/#!topic/strophe/sPw7-Vpszxs) were struggling
to compile example files. I think this readme file will help others as well.
2016-04-14 14:20:38 +00:00
Dmitry Podgorny
85bf3f4241 conn: don't set flag in xmpp_conn_disable_tls() directly
Instead, use xmpp_conn_set_flags() interface to force all necessary
checks.
2016-04-13 12:43:03 +00:00
Dmitry Podgorny
6d70bf4b0d tests/sha1: fixed indentation 2016-04-13 12:40:42 +00:00
Dmitry Podgorny
3aafeef215 res_query_dump: added comment with printable symbols 2016-04-13 12:38:53 +00:00
Dmitry Podgorny
e60895087e event: let event loop start after xmpp_stop() 2016-04-13 10:25:15 +00:00
Dmitry Podgorny
b169c0a91e conn: refactore connect functions
Common code is moved to a separated function.
2016-04-12 20:19:16 +00:00
Dmitry Podgorny
968cb7dcdf conn: fixed indentation 2016-04-12 20:07:58 +00:00
Dmitry Podgorny
367aeb5844 conn: don't set tcp keepalives for disconnected connection
In XMPP_CONN_DISCONNECTED state conn->sock is undefined.
2016-04-08 18:17:07 +00:00
Dmitry Podgorny
5518a9e10a sock: refactore tcp keepalive setting
- Leave default number of keepalive probes rather than hardcoded value
- QNX and OSX use TCP_KEEPALIVE instead of TCP_KEEPIDLE
- QNX doesn't have TCP_KEEPINTVL
2016-04-08 18:12:48 +00:00
Andrey (Stanson) Kozin
6c1c2a86f8 TCP keepalive setting support 2016-04-08 16:40:56 +00:00
Chih-Wei Chen
cb79f5c10b Revert "Added expat submodule for tracking vendor releases."
This reverts commit 24abd94a82.

Signed-off-by: Chih-Wei Chen <changeway@gmail.com>
2016-03-16 16:38:09 +08:00
Dmitry Podgorny
b7e308d057 Implemented resolver to replace sock_srv_lookup() 2016-02-20 00:15:08 +02:00
Andrey (Stanson) Kozin
714b2f9c03 Free send queue on connection release 2016-02-06 00:10:21 +00:00
Dmitry Podgorny
a7c18ba6c7 autotools: choose correct library for res_query()
See #72 for further information.
2016-02-05 23:37:55 +00:00
Dmitry Podgorny
fc82aaeef2 git: added vim's swp files to .gitignore 2016-02-05 22:46:36 +00:00
Dmitry Podgorny
c291513663 Makefile: remove unused src/thread.c
See #72 for further information.
2016-02-05 21:58:00 +00:00
Rafael Sadowski
a413c68e52 fix: generated syntax errors on BSD's SH(1) 2016-02-05 21:43:34 +00:00
Dmitry Podgorny
5b41247bac rand: remove sizeof(uint8_t) because it's always 1 2016-01-10 13:05:30 +02:00
vf
fc563272fe Fix for MSVC 2016-01-09 17:57:32 +03:00
Dmitry Podgorny
38545af533 parser/expat: reduce code duplication 2015-12-21 13:46:51 +02:00
James Booth
6f612d4f4d Add -no-undefined to LDFLAGS 2015-12-14 00:28:37 +00:00
Dmitry Podgorny
a1bc5e82cf sha1: don't make in-place operations
SHA1HANDSOFF makes SHA1_Transform() use an internal buffer.
2015-12-06 11:11:52 +02:00
Dmitry Podgorny
98c8afd5fc tests: updated SHA1 test
* added new testcase with 128 'a'
* added check that SHA1 functions don't change original strings
2015-12-04 09:57:09 +02:00
Dmitry Podgorny
cff4a4cd71 Merge pull request #76 from Tusharsb/patch-2
Making bot.c compatible to C++
2015-12-02 11:41:58 +02:00
Tusharsb
7bbfd00344 Making bot.c compatible to C++
By this small type casting change, I am able to compile bot.c with both ``gcc`` as well as with ``g++``

I am now able to use bot.c in my c++ programs
2015-12-02 14:53:52 +05:30
Dmitry Podgorny
01af2deed9 conn: fixed memory leak
Memory leak appeared when xmpp_connect_client() was called for a
connection more than once. In this case conn->domain wasn't freed.
2015-10-23 01:28:19 +03:00
Dmitry Podgorny
a54def3e92 examples/bot: fixed memory leak 2015-10-23 00:40:13 +03:00
Dmitry Podgorny
2aea1a627c stanza: avoid copy-paste in 'get' functions 2015-10-21 02:13:55 +03:00
Dmitry Podgorny
e475ca13ea stanza: handle errors better
* Free memory on error in xmpp_stanza_set_attribute()
* Handle memory allocation error in xmpp_stanza_set_text()
2015-10-21 02:11:03 +03:00
Dmitry Podgorny
31582cac92 ChangeLog: added new stanza API 2015-10-20 21:06:35 +03:00
Dmitry Podgorny
c012f20c99 stanza: handle EMEM in xmpp_stanza_set_name() 2015-10-20 16:26:43 +03:00
Tristan Le Guern
d460a5eb16 Convert bot.c to the new helpers 2015-10-20 16:26:43 +03:00
Tristan Le Guern
3a56d68f47 Convert active.c to the new helpers 2015-10-20 16:26:43 +03:00
Tristan Le Guern
9de0293405 Implement xmpp_stanza_reply()
This function creates a copy of the given stanza minus its children and
set the “to” attribute with the value of the original “from”.
2015-10-20 16:26:43 +03:00
Tristan Le Guern
21f742f888 Implement xmpp_stanza_del_attribute() 2015-10-20 16:26:43 +03:00
Tristan Le Guern
0d4bcc0228 Extract the copy loop into its own function
It will help reduce code duplication for xmpp_stanza_copy
2015-10-20 16:26:43 +03:00
Tristan Le Guern
90a595f8ef Implements helpers for to and from attributes
xmpp_stanza_{get,set}_{from,to}
2015-10-20 15:22:20 +03:00
Dmitry Podgorny
64d65b3aed examples: mention about xmpp_conn_set_flags()
xmpp_conn_set_flags() provides features that people sometimes look for.
Adding comment to examples will simplify the search.
2015-10-20 14:36:43 +03:00
Dmitry Podgorny
a39267c1b0 conn: use altport for legacy ssl if specified 2015-10-19 22:42:44 +03:00
Dmitry Podgorny
331db6f565 tests: added test vectors for MD5 2015-10-18 03:05:38 +03:00
Dmitry Podgorny
9cea7e4002 md5: cleanup
* Indentation
* Removed MD5DumpBytes()
* Removed ASM_MD5
2015-10-18 03:03:15 +03:00
Dmitry Podgorny
f63aba88d4 conn: fixed indentations 2015-10-18 02:22:15 +03:00
Dmitry Podgorny
a78201bae0 sock: use xmpp_snprintf instead of snprintf 2015-10-16 14:58:18 +03:00
Tristan Le Guern
a61dba0c13 Move declarations of xmpp_{v,}snprintf.
Use HAVE_SNPRINTF and HAVE_VSNPRINTF to conditionnaly use an internal
version of these functions or use the libc one.
2015-10-16 14:48:10 +03:00
Dmitry Podgorny
60cfcc72e6 snprintf: moved self-test to a separated test 2015-10-16 00:05:26 +03:00
Dmitry Podgorny
4cc9ba79c4 sock: choose target with the lowest priority
sock_srv_lookup chose the last target in the answer section. But it must
choose one with the lowest priority it can reach (due to RFC2052).
2015-10-15 17:49:44 +03:00
Dmitry Podgorny
182803926b conn: added new API xmpp_conn_set_flags()
xmpp_conn_set_flags() and xmpp_conn_get_flags() unify interface of
connection configuration.
This interface allows compile-time check of supported features or even
run-time check. Therefore, applications can be built with older
libstrophe which doesn't support some optional flags.
2015-10-15 16:01:13 +03:00
Dmitry Podgorny
e41b7a06e4 sha1: moved self test to separated test 2015-10-15 00:35:19 +03:00
Dmitry Podgorny
0994022066 scram: renamed BLOCK_SIZE
BLOCK_SIZE is too common name, so remove it to HMAC_BLOCK_SIZE.
2015-10-15 00:11:09 +03:00
Dmitry Podgorny
c156e13791 sock: removed unused static functions 2015-10-14 01:45:25 +03:00
Tristan Le Guern
a47b71e52b netbuf_* and friends should be static 2015-10-13 23:17:09 +02:00
Tristan Le Guern
db908563d0 xmpp_default_logger should be static 2015-10-13 23:16:44 +02:00
Dmitry Podgorny
b5e49a0600 base64: fixed crash when len is small 2015-10-13 23:20:41 +03:00
Dmitry Podgorny
e0a13ecdaa tests/base64: updated and added to Makefile.am 2015-10-13 23:19:25 +03:00
Dmitry Podgorny
fc856f36a3 tests/parser: fixed gcc warning
tests/check_parser.c:59:9: error: variable ‘ret’ set but not used
2015-10-13 22:39:27 +03:00
Dmitry Podgorny
9b67acbfc4 tests: moved common routines to test.[ch] 2015-10-13 22:38:18 +03:00
Dmitry Podgorny
b04c40d3ea tls: don't hang with openssl implementation
* Exit from tls_start() on fatal errors. If SSL_connect() fails and
  returns -1 this leads to endless loop in case of fatal error.
* Don't set writefds on SSL_ERROR_WANT_READ. Otherwise, this makes
  select(2) exit immediately what leads to CPU usage.
2015-10-13 02:43:23 +03:00
Tristan Le Guern
442914c375 Shorten the nlen+dlen+rlen part 2015-10-13 01:11:45 +03:00
Tristan Le Guern
a4558b69df Publicly expose JID manipulation functions 2015-10-13 01:11:25 +03:00
Dmitry Podgorny
07751974ac conn: fixed typo 2015-10-13 00:53:15 +03:00
Dmitry Podgorny
8ff46add8c conn: don't remember tls state from old connection
* Clear conn->secured and conn->tls_failed. These values could be
  saved after re-connect.
* conn is not secured if conn->tls is NULL. This condition handles
  disconnected connections.
2015-10-13 00:44:23 +03:00
Dmitry Podgorny
b7fbc81740 conn: added API xmpp_conn_is_secured()
This patch is provided by @kjkao. New API is already used in
WorksSystems/wks_xep0047.
2015-10-13 00:10:02 +03:00
Dmitry Podgorny
36af7afa27 conn: implemented old-style SSL connection
Added new API xmpp_conn_set_old_style_ssl(). This function forces
using of old-style SSL connection.
2015-10-12 22:25:39 +03:00
Dmitry Podgorny
254b9d73a1 sock: do nothing if srv lookup fails
Proper action is performed in xmpp_connect_client.
2015-10-12 22:06:27 +03:00
Dmitry Podgorny
8fcac79301 Makefile.am: removed whitespaces 2015-10-12 20:51:24 +03:00
Dmitry Podgorny
a48add8f13 ChangeLog: new features in 0.8.9 2015-10-12 16:12:34 +03:00
Dmitry Podgorny
8627fbb13f Implemented UUID generation (RFC4122)
This patch adds new API:
  * xmpp_uuid_gen()
2015-10-12 15:17:22 +03:00
Dmitry Podgorny
5e64c850bd Added stddef.h to strophe.h to define size_t 2015-10-12 15:02:59 +03:00
Dmitry Podgorny
533664903a tls: fixed GnuTLS implementation 2015-10-11 16:30:50 +03:00
Dmitry Podgorny
cda805163f conn: cleanup of headers
* added stdarg.h
* removed unused headers
2015-10-11 05:38:12 +03:00
Dmitry Podgorny
3d4c657467 Removed stdio.h from strophe.h 2015-10-11 05:25:19 +03:00
Dmitry Podgorny
8339fd0420 sock: socket should be non-blocking
Event loop handles asynchronous connections.
2015-10-11 05:20:31 +03:00
Dmitry Podgorny
63946ff7ef sock: set AI_ADDRCONFIG only if defined
AI_ADDRCONFIG is undefined on some systems.
2015-10-10 23:09:48 +03:00
Dmitry Podgorny
e6bbfa7a62 Updated license in new files 2015-10-10 01:11:08 +03:00
Chih-Wei Chen
b2a98fb9b6 sock : Add IPv6 support 2015-10-10 00:24:08 +03:00
Dmitry Podgorny
f326c2f42f sha1: added prefix crypto_ to SHA1 API
sha1.c contains symbols that overlap with libcrypto. This patch
fixes linking with libstrophe as static library.

Prefix crypto_ will help to group other crypto API in the future.
2015-10-09 12:14:23 +03:00
Dennis Schridde
3b55c20879 Fix --without-libxml2
The arguments of AC_ARG_WITH are (package, help-string, [action-if-given], [action-if-not-given]).
  action-if-given takes effect when the flag is given in **either** form (--with or --without).
  The proper code for action-if-given would thus be with_libxml2=$withval, which is already the default.
  Thus leaving this argument empty is the proper course of action.

cf. https://autotools.io/autoconf/arguments.html
2015-10-09 02:20:01 +03:00
christoph
a335466450 Fix invalid write in dopr(...)
Fix an invalid write in dopr(...) that occured when maxlen == 0 and
buffer != 0 since 0-1 > 0 using size_t.
2015-10-07 22:45:44 +03:00
Dmitry Podgorny
c73ddf065b autotools: set development version to 0.8.9 2015-10-07 22:27:26 +03:00
Dmitry Podgorny
fa585fd107 Removed outdated vs2008 directory 2015-10-07 22:20:22 +03:00
Dmitry Podgorny
7a782df9f5 auth: memory leak in _make_scram_sha1_init_msg() 2015-10-07 20:02:45 +03:00
Tristan Le Guern
982d840472 Signed to unsigned conversion to appease GCC 2015-10-07 19:48:35 +03:00
Tristan Le Guern
75938845fd Add missing prototypes to strophe.h 2015-10-07 19:46:55 +03:00
Dmitry Podgorny
e70e755e19 tests: added UT for SCRAM-SHA1 functions 2015-10-07 19:42:16 +03:00
Dmitry Podgorny
5e37de2b63 tests: added test vectors for Hash_DRBG 2015-10-07 19:35:42 +03:00
Dmitry Podgorny
10656ead46 Introduced PRNG based on Hash_DRBG (NIST SP 800-90A)
This pseudo-random number generator solves problem with
platform-independent generation of randomized nonces.
Current implementation uses weak entropy, especially when
kernel.randomize_va_space = 0. But it can be improved by
adding new sources to xmpp_rand_reseed().

New internal API introduced:
  xmpp_rand_new
  xmpp_rand_free
  xmpp_rand
  xmpp_rand_bytes
  xmpp_rand_nonce
2015-10-07 19:35:42 +03:00
Dmitry Podgorny
75b1a633d6 sha1: moved wrapper SHA1() to sha1.c 2015-10-07 19:35:42 +03:00
Tristan Le Guern
109aaa71a5 Fix behaviour of libstrophe on signed char arch
The use of 0xff as a separator for libexpat only works on arch where
char is defined as an unsigned char.  This is an unportable behaviour.

Before this patch this is what I experienced:

xmpp DEBUG sock_connect to im.bouledef.eu:5222 returned 3
xmpp DEBUG attempting to connect to im.bouledef.eu
xmpp DEBUG connection successful
conn DEBUG SENT: <?xml version="1.0"?><stream:stream to="bouledef.eu" xml:lang="en" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
conn ERROR Server did not open valid stream.
xmpp DEBUG Closing socket.
DEBUG: disconnected
event DEBUG Stopping event loop.
xmpp DEBUG RECV: <http://etherx.jabber.org/streamsÿfeatures><urn:ietf:params:xml:ns:xmpp-tlsÿstarttls><urn:ietf:params:xml:ns:xmpp-tlsÿrequired/></urn:ietf:params:xml:ns:xmpp-tlsÿstarttls></http://etherx.jabber.org/streamsÿfeatures>
event DEBUG Event loop completed.
name = http://etherx.jabber.org/streamsÿstream
2015-10-07 15:01:14 +03:00
Dmitry Podgorny
92709a773c hash: fixed hash_new() prototype 2015-09-28 14:31:48 +03:00
Tristan Le Guern
93f9a5d1e8 Don't lie about array parameters 2015-09-28 14:26:25 +03:00
Tristan Le Guern
0acec5c335 -Wshadow for hash.c 2015-09-28 14:26:25 +03:00
Tristan Le Guern
0e8d407f93 Correct a type in scram.c 2015-09-28 14:26:25 +03:00
Tristan Le Guern
ed5f982312 Don't lie about array parameters
Passing an array as a parameter to a function in C doesn't work, they decay
into pointer.  Defining them is pointless and error prone, so just
declare a pointer.
2015-09-28 14:26:24 +03:00
James Booth
cd92f69c76 Fixed Changelog 2015-08-18 22:07:06 +01:00
James Booth
73080e0660 Fixed indentation in Changelog 2015-08-18 22:00:43 +01:00
James Booth
7cdef1e319 Check for name element when reading mechanisms
Fixes an issue where the server sends whitespace between
elements, a segfault would occur when performing a strcmp
on the name.
2015-08-03 23:05:04 +01:00
James Booth
527bc0573a Fixed _log_open_tag to remove namespace prefix with libexpat 2015-03-28 17:37:11 +00:00
James Booth
59d2dd55d2 Added codelite project to .gitignore 2015-03-26 20:58:05 +00:00
James Booth
b1cbcffdc7 Bumped version, added to Changelog 2015-03-26 20:52:48 +00:00
James Booth
154b70ed2c Merge remote-tracking branch 'cwtitan/namespace' 2015-03-26 20:44:10 +00:00
Codewalker
e33a98e498 Streamline xmpp_stanza_to_text for the namespace patch by following XML
namespace scoping guidelines and not outputting the xmlns attribute in
contexts where it can be inferred from the parent element.
2015-01-23 11:11:23 -06:00
shooding
239d365ea1 fix Makefile.am to respect openssl_CFLAGS, which is useful if openssl is not installed in the default path, e.g. cross-compiling. 2015-01-14 18:06:35 +08:00
Dmitry Podgorny
57ed30b2bc autotools: fixed build with old versions of automake
Automake-1.11 and some newer versions fail if m4/ doesn't exist. This
behaviour was changed to warning in version 1.13.2.
2015-01-03 01:01:07 +02:00
Codewalker
86f913b001 Fix use of snprintf (which does not exist on all platforms) in auth.c
by replacing it with xmpp_snprintf in order to be consistent with the
rest of the code. Also fixes compile error on MSVC.
2015-01-02 20:21:59 +02:00
Codewalker
e2f1c1e94a Add XML namespace support. 2014-12-28 22:46:16 -06:00
Codewalker
f62d817c71 Fix error spam in event loop when no connections are open.
On Win32 at least, select() will immediately fail with an error if
there are no file descriptors to wait for (max == 0). In the simple case
of a single XMPP session and an event loop that runs only while the
connection is open, this isn't a problem, but doesn't work for more
complex scenarios.

Add some handling so that if xmpp_run_once is called and there are no
active connections, simply sleep for duration of the timeout and
return.
2014-12-24 12:08:05 -06:00
Codewalker
b753e6cf18 Fix a bug where select() could fail due to negative max socket fd.
Connection objects in the disconnected state should not have their
fd taken into account when determining the maximum socket fd number,
as they are not set in the bitmask with FD_SET, and their fd could
be anything, even a wildly large or small number.
2014-12-24 12:04:39 -06:00
Dmitry Podgorny
0fed8a55e4 examples: updated header in component.c 2014-12-15 14:47:47 +02:00
Dmitry Podgorny
d28520ba30 added examples/component to .gitignore 2014-12-15 14:42:50 +02:00
Milan Kubik
c52ba85846 XEP-0114: Added an example for component connection.
The example is based on basic.c program.
To run the example, a configured server is needed.
2014-12-15 14:42:50 +02:00
Dmitry Podgorny
3b906f6ceb XEP-0114: minor fixes to auth.c
- src/sha1.c is used instead of openssl;
 - xmpp_alloc/free should be used instead of malloc/free;
 - coding style fixes.
2014-12-15 14:42:50 +02:00
Milan Kubík
5d76e052ec XEP-0114: external component authentication
New API xmpp_connect_component() introduced.
2014-12-15 14:41:18 +02:00
Dariusz Dwornikowski
37a40dec23 Merge pull request #42 from tdi/master
Update headers not to mention LICENSE.txt but licenses directly Closes #31
2014-11-13 13:13:37 +01:00
Dmitry Podgorny
2093aac817 rpm: include shared library and pkg-config file 2014-10-31 04:13:49 +02:00
Kristofer White
29fa1bf27e Updates to rpm/libstrophe.spec 2014-10-31 04:11:13 +02:00
Dmitry Podgorny
f364ed184b autotools: fixed building of check_parser
By default libtool choose dynamic library for linking. Since non-public
API is hidden in libstrophe.so check_parser has been broken. As solution
libtool takes static libstophe.a now.
2014-10-30 23:17:16 +02:00
Dmitry Podgorny
40c9fe22b3 .gitignore: added files generated by make check 2014-10-30 23:16:40 +02:00
Dmitry Podgorny
c33c0a6998 hash: removed useless condition in hash_iter_next
Situation ((entry != NULL) && (i >= table->length)) can never happen.
2014-10-29 18:43:06 +02:00
Sergey Anufrienko
92e674e412 fix bug leading to losing of hash entries in hash_iter_next 2014-10-28 16:42:28 +03:00
Dmitry Podgorny
9f82aac8ce sha1: compile-time endianness check for some compilers
Newer gcc and clang provide macro __BYTE_ORDER__.
2014-10-25 16:37:21 +03:00
Dmitry Podgorny
a3f1b83f3a sha1: run-time check for endianness
WORDS_BIGENDIAN is never defined what breaks sha1 on big-endian
architectures. Instead, make run-time check.
2014-10-25 16:03:18 +03:00
Dariusz Dwornikowski
71f75b2e2e Closes #31 2014-10-23 08:44:52 +02:00
Dmitry Podgorny
b23104f920 ChangeLog: set future version to 0.8.7 2014-10-21 10:23:12 +03:00
Dmitry Podgorny
057f9068c6 autotools: removed duplication in configure.ac 2014-10-21 10:21:55 +03:00
Fabian Freyer
3231214344 Added --with-pkgconfigdir 2014-10-08 18:13:32 +02:00
Fabian Freyer
55efc601cb Refactored configure.ac, added pkg-config support 2014-10-08 18:13:31 +02:00
Fabian Freyer
dcbf3fb4d5 autotools: check for ssl.h if pkg-config failed
Some distros provides libssl without openssl.pc.
2014-09-30 16:02:43 +03:00
Fabian Freyer
e2acd98612 autotools: added AC_CONFIG_MACRO_DIR 2014-09-30 16:00:36 +03:00
92 changed files with 9187 additions and 6073 deletions

30
.gitignore vendored
View File

@@ -1,8 +1,7 @@
*.swp
Makefile
test-driver
.libs
src/*.lo
*.la
Makefile.in
configure
libtool
@@ -21,25 +20,44 @@ autom4te.cache
.deps
.sconsign*
src/*.o
src/*.lo
examples/*.o
tests/*.o
tests/check_parser
*.a
*.la
*.pc
*.tar.gz
*.zip
docs/html
TAGS
tags
examples/basic
examples/active
examples/roster
examples/basic
examples/bot
examples/component
examples/roster
examples/uuid
examples/vcard
test_stamp
test-suite.log
tests/*.o
tests/*.log
tests/*.trs
tests/check_parser
tests/test_base64
tests/test_ctx
tests/test_hash
tests/test_jid
tests/test_md5
tests/test_rand
tests/test_resolver
tests/test_sasl
tests/test_scram
tests/test_sha1
tests/test_snprintf
tests/test_string
tests/test_sock
m4/
libstrophe.project
libs/
obj/
expat/

15
.travis.yml Normal file
View File

@@ -0,0 +1,15 @@
language: c
install:
- sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
before_script:
- ./bootstrap.sh
script:
- ./configure ${CONFIGURE_OPT} && make && make check-TESTS
env:
- CONFIGURE_OPT="--without-libxml2"
- CONFIGURE_OPT="--with-libxml2"
- CONFIGURE_OPT="--disable-tls --without-libxml2"
- CONFIGURE_OPT="--disable-tls --with-libxml2"
matrix:
fast_finish: true

View File

@@ -1,5 +1,72 @@
TBA
0.9.2
- OpenSSL tls module verifies certificate by default. Set flag
XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification
- Certificate hostname verification is forced for openssl-1.0.2 and
newer
- OpenSSL tls module disables insecure SSLv2 SSLv3 and TLSv1
- Support of handlers with the same callback function, but different
userdata
- System handlers are deleted on xmpp_conn_t reconnection. Old system
handlers could cause problems
- Default timeout for xmpp_run() is increased from 1 millisecond to 1
second in order to reduce CPU consumption
- Reduced memory usage in expat module
- New functions:
- xmpp_ctx_set_timeout()
- xmpp_sha1_digest()
0.9.1
- Fixed bug #95 (DNS lookup failing on Cygwin)
- Removed dependency on the check package
0.9.0
- IPv6 support
- Legacy SSL support
- Initial Android support
- Resolver returns all SRV records instead of one. Lookup is performed
according to RFC2052
- xmpp_connect_raw() provides access to a xmpp_conn object just after
establishing TCP connection. This allows to implement in-band
registration, authentication mechanisms or serverless messaging
- xmpp_conn_t object is reusable now and can be reconnected with saving
all handlers, flags, jid and password
- New API:
- xmpp_uuid_gen()
- xmpp_connect_raw()
- xmpp_conn_open_stream_default()
- xmpp_conn_open_stream()
- xmpp_conn_tls_start()
- xmpp_conn_get_flags()
- xmpp_conn_set_flags()
- xmpp_conn_set_keepalive()
- xmpp_conn_is_secured()
- xmpp_stanza_del_attribute()
- xmpp_stanza_get_to()
- xmpp_stanza_get_from()
- xmpp_stanza_set_to()
- xmpp_stanza_set_from()
- xmpp_stanza_reply()
- xmpp_message_new()
- xmpp_message_get_body()
- xmpp_message_set_body()
- xmpp_iq_new()
- xmpp_presence_new()
- Exposed private API:
- xmpp_jid_new()
- xmpp_jid_bare()
- xmpp_jid_node()
- xmpp_jid_domain()
- xmpp_jid_resource()
- xmpp_stanza_get_attribute_count()
- xmpp_stanza_get_attributes()
0.8.8
- XML namespace support
- XEP-0114 support
0.8.7
- SCRAM-SHA-1 authentication mechanism
- pkg-config support
0.8.5
- libtoolize to generate .so

2337
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -6,27 +6,64 @@ AM_CFLAGS = -g -Wall
PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@
SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@
STROPHE_FLAGS = -I$(top_srcdir)
RESOLV_LIBS = @RESOLV_LIBS@
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter
STROPHE_LIBS = libstrophe.la
## Main build targets
lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(STROPHE_FLAGS) $(PARSER_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS)
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
# Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
libstrophe_la_SOURCES = src/auth.c src/conn.c src/ctx.c \
src/event.c src/handler.c src/hash.c \
src/jid.c src/md5.c src/sasl.c src/scram.c src/sha1.c \
src/snprintf.c src/sock.c src/stanza.c src/thread.c \
src/tls_openssl.c src/util.c \
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
src/sasl.h src/scram.h src/sha1.h src/sock.h src/thread.h src/tls.h \
libstrophe_la_SOURCES = \
src/auth.c \
src/conn.c \
src/crypto.c \
src/ctx.c \
src/event.c \
src/handler.c \
src/hash.c \
src/jid.c \
src/md5.c \
src/rand.c \
src/resolver.c \
src/sasl.c \
src/scram.c \
src/sha1.c \
src/snprintf.c \
src/sock.c \
src/stanza.c \
src/util.c \
src/uuid.c
libstrophe_la_SOURCES += \
src/common.h \
src/hash.h \
src/md5.h \
src/ostypes.h \
src/parser.h \
src/rand.h \
src/resolver.h \
src/sasl.h \
src/scram.h \
src/sha1.h \
src/snprintf.h \
src/sock.h \
src/tls.h \
src/util.h
if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c
else
libstrophe_la_SOURCES += src/tls_openssl.c
endif
if PARSER_EXPAT
libstrophe_la_SOURCES += src/parser_expat.c
else
@@ -36,28 +73,122 @@ endif
include_HEADERS = strophe.h
noinst_HEADERS = strophepp.h
EXTRA_DIST = docs
pkgconfig_DATA = libstrophe.pc
EXTRA_DIST = \
Doxyfile \
GPL-LICENSE.txt \
LICENSE.txt \
MIT-LICENSE.txt \
bootstrap.sh \
build-android.sh \
docs/footer.html \
examples/README.md \
jni/Android.mk \
jni/Application.mk \
rpm/README \
rpm/libstrophe.spec \
src/tls_gnutls.c \
src/tls_schannel.c \
tests/res_query_dump.c
## Examples
noinst_PROGRAMS = examples/active examples/roster examples/basic examples/bot
noinst_PROGRAMS = \
examples/active \
examples/basic \
examples/bot \
examples/component \
examples/roster \
examples/uuid \
examples/vcard
examples_active_SOURCES = examples/active.c
examples_active_CFLAGS = $(STROPHE_FLAGS)
examples_active_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS)
examples_active_LDADD = $(STROPHE_LIBS)
examples_basic_SOURCES = examples/basic.c
examples_basic_CFLAGS = $(STROPHE_FLAGS)
examples_basic_LDADD = $(STROPHE_LIBS)
examples_basic_LDADD = $(STROPHE_LIBS)
examples_bot_SOURCES = examples/bot.c
examples_bot_CFLAGS = $(STROPHE_FLAGS)
examples_bot_LDADD = $(STROPHE_LIBS)
examples_bot_LDADD = $(STROPHE_LIBS)
examples_component_SOURCES = examples/component.c
examples_component_CFLAGS = $(STROPHE_FLAGS)
examples_component_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS)
examples_uuid_SOURCES = examples/uuid.c
examples_uuid_CFLAGS = $(STROPHE_FLAGS)
examples_uuid_LDADD = $(STROPHE_LIBS)
examples_vcard_SOURCES = examples/vcard.c
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
examples_vcard_LDADD = $(STROPHE_LIBS)
## Tests
TESTS = tests/check_parser
check_PROGRAMS = tests/check_parser
TESTS = \
tests/check_parser \
tests/test_sha1 \
tests/test_md5 \
tests/test_rand \
tests/test_scram \
tests/test_ctx \
tests/test_base64 \
tests/test_hash \
tests/test_jid \
tests/test_snprintf \
tests/test_string \
tests/test_resolver
check_PROGRAMS = $(TESTS)
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
tests_check_parser_CFLAGS = @check_CFLAGS@ $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
tests_check_parser_LDADD = @check_LIBS@ $(STROPHE_LIBS)
tests_check_parser_LDADD = $(STROPHE_LIBS)
tests_check_parser_LDFLAGS = -static
tests_test_ctx_SOURCES = tests/test_ctx.c
tests_test_ctx_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_ctx_LDADD = $(STROPHE_LIBS)
tests_test_ctx_LDFLAGS = -static
tests_test_base64_SOURCES = tests/test_base64.c tests/test.c tests/test.h
tests_test_base64_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_base64_LDADD = $(STROPHE_LIBS)
tests_test_base64_LDFLAGS = -static
tests_test_hash_SOURCES = tests/test_hash.c
tests_test_hash_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_hash_LDADD = $(STROPHE_LIBS)
tests_test_hash_LDFLAGS = -static
tests_test_jid_SOURCES = tests/test_jid.c
tests_test_jid_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_jid_LDADD = $(STROPHE_LIBS)
tests_test_jid_LDFLAGS = -static
tests_test_resolver_SOURCES = tests/test_resolver.c tests/test.h
tests_test_resolver_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_resolver_LDADD = $(STROPHE_LIBS)
tests_test_resolver_LDFLAGS = -static
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c
tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c
tests_test_sha1_CFLAGS = -I$(top_srcdir)/src
tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c
tests_test_md5_CFLAGS = -I$(top_srcdir)/src
tests_test_snprintf_SOURCES = tests/test_snprintf.c
tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src
tests_test_string_SOURCES = tests/test_string.c tests/test.h
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_string_LDADD = $(STROPHE_LIBS)
tests_test_string_LDFLAGS = -static

View File

@@ -1,8 +1,9 @@
# libstrophe
libstrophe [![Build Status](https://travis-ci.org/strophe/libstrophe.png?branch=master)](https://travis-ci.org/strophe/libstrophe)
==========
libstrophe is a lightweight XMPP client library written in C. It has
minimal dependencies and is configurable for various environments. It
runs well on both Linux, Unix, and Windows based platforms.
runs well on Linux, Unix and Windows based platforms.
Its goals are:
@@ -10,7 +11,8 @@ Its goals are:
- well documented
- reliable
## Build Instructions
Build Instructions
------------------
If you are building from a source control checkout, run:
@@ -23,9 +25,7 @@ From the top-level directory, run the following commands:
./configure
make
This will create a static library, also in the top-level
directory, which can be linked into other programs. The
public API is defined in `strophe.h` which is also in the
The public API is defined in `strophe.h` which is in the
top-level directory.
The `examples` directory contains some examples of how to
@@ -41,26 +41,31 @@ another path use the `--prefix` option during configure, e.g.:
./configure --prefix=/usr
## Requirements
### Android
Run script `build-android.sh` and follow the instructions. You will
need expat sources and android-ndk.
Requirements
------------
libstrophe requires:
- expat or libxml2 - expat is the default; use --with-libxml2 to
switch
- libresolv on UNIX systems - make sure you include -lresolv
if you are compiling by hand.
- libtool
- openssl on UNIX systems
In addition, if you wish to run the unit tests, you will need the
check package.
To build libstrophe using autotools you will need autoconf, automake,
libtool and pkg-config.
### OS X (with Homebrew package manager)
Installation
------------
You can install libstrophe with:
libstrophe package has been added to popular Linux distributions,
BSD systems and OSX package managers.
brew install libstrophe
## Documentation
Documentation
-------------
API documentation is inline with the code and conforms to Doxygen
standards. You can generate an HTML version of the API documentation

View File

@@ -1,3 +1,5 @@
#!/bin/sh
# Some versions of aclocal fail if m4/ doesn't exist
mkdir -p m4
autoreconf -i

39
build-android.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/sh
DIR=`dirname $0`
EXPAT_PATH="$DIR/expat"
EXPAT_FILE='lib/expat.h'
echo
echo Attention: libstrophe will be built without TLS support. To enable TLS
echo you need to replace \'src/tls_dummy.c\' with \'src/tls_opnessl.c\' in
echo \'jni/Android.mk\', add path to the openssl headers and link your program
echo with libssl and libcrypto.
echo
if [ ! -d $EXPAT_PATH ]; then
mkdir $EXPAT_PATH
fi
# TODO Accept expat tarball as argument and extract it to the right place.
# Or download sources from sf.net.
if [ ! -d $EXPAT_PATH/lib -o ! -f "$EXPAT_PATH/$EXPAT_FILE" ]; then
cat <<EOT
Error: expat sources not found.
Extract expat sources to $EXPAT_PATH. Make sure $EXPAT_PATH/$EXPAT_FILE and
other source files exist.
EOT
exit 1
fi
ndk-build -C "$DIR" clean || exit 1
ndk-build -C "$DIR" || exit 1
echo
echo "basic example:"
ls -l "$DIR"/libs/*/basic
echo
echo "libstrophe.a:"
ls -l "$DIR"/obj/local/*/libstrophe.a

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.8.7], [jack@metajack.im])
AC_INIT([libstrophe], [0.9.2], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen])
@@ -9,63 +9,123 @@ PKG_PROG_PKG_CONFIG
AC_CANONICAL_HOST
AS_CASE([$host_os],
[freebsd*], [PLATFORM="freebsd"],
[PLATFORM="nix"])
PKG_CHECK_MODULES([openssl], [openssl], [],
[AC_CHECK_HEADER(openssl/ssl.h, [openssl_LIBS="-lssl -lcrypto"], [AC_MSG_ERROR([openssl not found; openssl required])])])
PKG_CHECK_MODULES([check], [check >= 0.9.4], [], [AC_MSG_WARN([libcheck not found; unit tests will not be compilable])])
[freebsd*], [PLATFORM="bsd"],
[openbsd*], [PLATFORM="bsd"],
[netbsd*], [PLATFORM="bsd"],
[*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"],
[PLATFORM="nix"])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing])],
[with_libxml2=check],
[with_libxml2=no])
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
if test "x$with_libxml2" != xno; then
PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
[with_libxml2=yes], [dummy=1])
if test "x$with_libxml2" != xyes; then
old_CFLAGS=$CFLAGS
CFLAGS="-I${includedir}/libxml2"
AC_CHECK_HEADER([libxml/parser.h],
[with_libxml2=yes; libxml2_CFLAGS="-I${includedir}/libxml2"; libxml2_LIBS="-lxml2"],
[AC_MSG_ERROR([libxml2 not found.])])
CFLAGS=$old_CFLAGS
fi
else
PKG_CHECK_MODULES([expat], [expat >= 2.0.0], [],
[AC_CHECK_HEADER(expat.h, [expat_LIBS="-lexpat"], [AC_MSG_ERROR([expat not found; expat required.])])])
if test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"],
[AC_CHECK_HEADER([openssl/ssl.h],
[
openssl_LIBS="-lssl -lcrypto"
PC_LIBS="${openssl_LIBS} ${PC_LIBS}"
],
[AC_MSG_ERROR([openssl not found; openssl required])]
)])
fi
if test "x$with_libxml2" = xyes; then
with_parser=libxml2
PARSER_NAME=libxml2
PARSER_CFLAGS=$libxml2_CFLAGS
PARSER_LIBS=$libxml2_LIBS
with_parser=""
if test "x$with_libxml2" != xyes; then
PKG_CHECK_MODULES([expat], [expat >= 2.0.0],
[
with_parser="expat"
PC_REQUIRES="expat ${PC_REQUIRES}"
],
[AC_CHECK_HEADER([expat.h],
[
with_parser="expat"
expat_LIBS="-lexpat"
PC_LIBS="${expat_LIBS} ${PC_LIBS}"
])
])
fi
if test "x$with_libxml2" != xno -a "x$with_parser" = x; then
PKG_CHECK_MODULES([libxml2], [libxml-2.0 >= 2.7],
[
with_parser="libxml2"
PC_REQUIRES="libxml-2.0 ${PC_REQUIRES}"
],
[
old_CFLAGS=$CFLAGS
CFLAGS="-I${includedir}/libxml2"
AC_CHECK_HEADER([libxml/parser.h],
[
with_parser="libxml2"
libxml2_CFLAGS="-I${includedir}/libxml2"
libxml2_LIBS="-lxml2"
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
])
CFLAGS=$old_CFLAGS
])
fi
if test "x$with_parser" = xlibxml2; then
PARSER_CFLAGS=$libxml2_CFLAGS
PARSER_LIBS=$libxml2_LIBS
elif test "x$with_parser" = xexpat; then
PARSER_CFLAGS=$expat_CFLAGS
PARSER_LIBS=$expat_LIBS
else
with_parser=expat
PARSER_NAME=expat
PARSER_CFLAGS=$expat_CFLAGS
PARSER_LIBS=$expat_LIBS
AC_MSG_ERROR([no XML parser was found, libstrophe requires expat or libxml2])
fi
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
AC_SEARCH_LIBS([socket], [socket])
if test "x$PLATFORM" != xfreebsd; then
AC_CHECK_LIB([resolv], [res_query], [],
[AC_CHECK_LIB([resolv], [__res_query], [],
[AC_MSG_ERROR([libresolv not found; libresolv required. ])])])
else
AC_MSG_NOTICE([skipping libresolv checks for freebsd])
fi
AS_CASE([$PLATFORM],
[bsd], [RESOLV_LIBS=""],
[qnx], [RESOLV_LIBS="-lsocket"],
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
[android], [RESOLV_LIBS=""],
[RESOLV_LIBS="-lresolv"])
AC_CHECK_HEADERS([arpa/nameser_compat.h])
LIBS_TMP="${LIBS}"
LIBS="${RESOLV_LIBS}"
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netdb.h>
int main() {
(void)res_query(NULL, 0, 0, NULL, 0);
return 0;
}
])],
[],
[AC_MSG_ERROR([res_query() not found with LIBS="${LIBS}"])])
LIBS="${LIBS_TMP}"
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir],
[install directory for libstrophe.pc pkg-config file])],
[], [with_pkgconfigdir='$(libdir)/pkgconfig'])
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AC_SUBST(PARSER_NAME)
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}])
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}])
AC_SUBST([PC_LIBS], [${PC_LIBS}])
AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS)
AC_CONFIG_FILES([Makefile])
AC_SUBST(RESOLV_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT

7
examples/README.md Normal file
View File

@@ -0,0 +1,7 @@
Build Instructions
==================
Compile example files with the following gcc flags:
```
gcc -o bot bot.c `pkg-config --cflags --libs libstrophe`
```

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* This example demonstrates basic handler functions by printing out
@@ -27,7 +24,7 @@ int handle_reply(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_stanza_t *query, *item;
char *type;
const char *type;
type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0)
@@ -58,11 +55,8 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */
iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "active1");
xmpp_stanza_set_attribute(iq, "to", "xxxxxxxxx.com");
iq = xmpp_iq_new(ctx, "get", "active1");
xmpp_stanza_set_to(iq, "xxxxxxxxx.com");
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");
@@ -107,6 +101,13 @@ int main(int argc, char **argv)
/* create a connection */
conn = xmpp_conn_new(ctx);
/*
* also you can disable TLS support or force legacy SSL
* connection without STARTTLS
*
* see xmpp_conn_set_flags() or examples/basic.c
*/
/* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]);
xmpp_conn_set_pass(conn, argv[2]);

View File

@@ -6,16 +6,17 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>
#include <string.h>
#include <strophe.h>
/* hardcoded TCP keepalive timeout and interval */
#define KA_TIMEOUT 60
#define KA_INTERVAL 1
/* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
@@ -23,9 +24,13 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
int secured;
if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
xmpp_disconnect(conn);
}
else {
@@ -39,20 +44,45 @@ int main(int argc, char **argv)
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char *jid, *pass, *host;
char *jid, *pass, *host = NULL;
long flags = 0;
int tcp_keepalive = 0;
int i;
/* take a jid and password on the command line */
if (argc < 3 || argc > 4) {
fprintf(stderr, "Usage: basic <jid> <pass> [<host>]\n\n");
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--disable-tls") == 0)
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
else if (strcmp(argv[i], "--mandatory-tls") == 0)
flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
else if (strcmp(argv[i], "--legacy-ssl") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1;
else
break;
}
if ((argc - i) < 2 || (argc - i) > 3) {
fprintf(stderr, "Usage: basic [options] <jid> <pass> [<host>]\n\n"
"Options:\n"
" --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n"
" --legacy-ssl Use old style SSL.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
return 1;
}
jid = argv[1];
pass = argv[2];
host = NULL;
jid = argv[i];
pass = argv[i + 1];
if (i + 2 < argc)
host = argv[i + 2];
if (argc == 4)
host = argv[3];
/*
* Note, this example doesn't handle errors. Applications should check
* return values of non-void functions.
*/
/* init library */
xmpp_initialize();
@@ -64,6 +94,11 @@ int main(int argc, char **argv)
/* create a connection */
conn = xmpp_conn_new(ctx);
/* configure connection properties (optional) */
xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */
if (tcp_keepalive) xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
/* setup authentication information */
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* simple bot example
@@ -28,106 +25,116 @@
int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
{
xmpp_stanza_t *reply, *query, *name, *version, *text;
char *ns;
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
printf("Received version request from %s\n", xmpp_stanza_get_attribute(stanza, "from"));
reply = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(reply, "iq");
xmpp_stanza_set_type(reply, "result");
xmpp_stanza_set_id(reply, xmpp_stanza_get_id(stanza));
xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_t *reply, *query, *name, *version, *text;
const char *ns;
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
printf("Received version request from %s\n", xmpp_stanza_get_from(stanza));
reply = xmpp_stanza_reply(stanza);
xmpp_stanza_set_type(reply, "result");
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");
ns = xmpp_stanza_get_ns(xmpp_stanza_get_children(stanza));
if (ns) {
xmpp_stanza_set_ns(query, ns);
}
name = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(name, "name");
xmpp_stanza_add_child(query, name);
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, "libstrophe example bot");
xmpp_stanza_add_child(name, text);
version = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(version, "version");
xmpp_stanza_add_child(query, version);
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, "1.0");
xmpp_stanza_add_child(version, text);
xmpp_stanza_add_child(reply, query);
name = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(name, "name");
xmpp_stanza_add_child(query, name);
xmpp_stanza_release(name);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
return 1;
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, "libstrophe example bot");
xmpp_stanza_add_child(name, text);
xmpp_stanza_release(text);
version = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(version, "version");
xmpp_stanza_add_child(query, version);
xmpp_stanza_release(version);
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, "1.0");
xmpp_stanza_add_child(version, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(reply, query);
xmpp_stanza_release(query);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
return 1;
}
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
{
xmpp_stanza_t *reply, *body, *text;
char *intext, *replytext;
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
if(!xmpp_stanza_get_child_by_name(stanza, "body")) return 1;
if(xmpp_stanza_get_attribute(stanza, "type") !=NULL && !strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error")) return 1;
intext = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
printf("Incoming message from %s: %s\n", xmpp_stanza_get_attribute(stanza, "from"), intext);
reply = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(reply, "message");
xmpp_stanza_set_type(reply, xmpp_stanza_get_type(stanza)?xmpp_stanza_get_type(stanza):"chat");
xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
body = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(body, "body");
replytext = malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
strcat(replytext, " to you too!");
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, replytext);
xmpp_stanza_add_child(body, text);
xmpp_stanza_add_child(reply, body);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
free(replytext);
return 1;
xmpp_ctx_t *ctx = (xmpp_ctx_t*)userdata;
xmpp_stanza_t *body, *reply;
const char *type;
char *intext, *replytext;
int quit = 0;
body = xmpp_stanza_get_child_by_name(stanza, "body");
if (body == NULL)
return 1;
type = xmpp_stanza_get_type(stanza);
if (type != NULL && strcmp(type, "error") == 0)
return 1;
intext = xmpp_stanza_get_text(body);
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
reply = xmpp_stanza_reply(stanza);
if (xmpp_stanza_get_type(reply) == NULL)
xmpp_stanza_set_type(reply, "chat");
if (strcmp(intext, "quit") == 0) {
replytext = strdup("bye!");
quit = 1;
} else {
replytext = (char *) malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
strcat(replytext, " to you too!");
}
xmpp_free(ctx, intext);
xmpp_message_set_body(reply, replytext);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
free(replytext);
if (quit)
xmpp_disconnect(conn);
return 1;
}
/* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
if (status == XMPP_CONN_CONNECT) {
xmpp_stanza_t* pres;
fprintf(stderr, "DEBUG: connected\n");
xmpp_handler_add(conn,version_handler, "jabber:iq:version", "iq", NULL, ctx);
xmpp_handler_add(conn,message_handler, NULL, "message", NULL, ctx);
/* Send initial <presence/> so that we appear online to contacts */
pres = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pres, "presence");
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
xmpp_stanza_t* pres;
fprintf(stderr, "DEBUG: connected\n");
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, ctx);
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx);
/* Send initial <presence/> so that we appear online to contacts */
pres = xmpp_presence_new(ctx);
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
}
else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
}
@@ -140,10 +147,10 @@ int main(int argc, char **argv)
/* take a jid and password on the command line */
if (argc != 3) {
fprintf(stderr, "Usage: bot <jid> <pass>\n\n");
return 1;
fprintf(stderr, "Usage: bot <jid> <pass>\n\n");
return 1;
}
jid = argv[1];
pass = argv[2];
@@ -157,6 +164,13 @@ int main(int argc, char **argv)
/* create a connection */
conn = xmpp_conn_new(ctx);
/*
* also you can disable TLS support or force legacy SSL
* connection without STARTTLS
*
* see xmpp_conn_set_flags() or examples/basic.c
*/
/* setup authentication information */
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);

97
examples/component.c Normal file
View File

@@ -0,0 +1,97 @@
/* component.c
** libstrophe XMPP client library -- external component (XEP-0114) example
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* This example demonstrates simple connection to a server
** as an external component. See XEP-0114 for more details.
** This program requires correctly configured server to run.
*/
#include <stdio.h>
#include <stdlib.h>
#include <strophe.h>
/* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n");
xmpp_disconnect(conn);
}
else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char *jid, *pass, *host, *port_err = NULL;
unsigned short port = 0;
/* take a jid and password on the command line */
if (argc < 4 || argc > 5) {
fprintf(stderr, "Usage: component <jid> <pass> <host> [<port>]\n\n");
return 1;
}
jid = argv[1];
pass = argv[2];
host = argv[3];
if (argc == 5) {
short tmp_port = (short) strtol(argv[4], &port_err, 10);
if (tmp_port < 0 || *port_err != '\0') {
fprintf(stderr, "Invalid value of <port> [%s].\n", argv[4]);
return 1;
}
port = (unsigned short) tmp_port;
}
/* init library */
xmpp_initialize();
/* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log);
/* create a connection */
conn = xmpp_conn_new(ctx);
/* setup authentication information */
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);
/* initiate connection */
xmpp_connect_component(conn, host, port, conn_handler, ctx);
/* enter the event loop -
our connect handler will trigger an exit */
xmpp_run(ctx);
/* release our connection and context */
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
/* final shutdown of the library */
xmpp_shutdown();
return 0;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* This example demonstrates basic handler functions by printing out
@@ -26,7 +23,7 @@ int handle_reply(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_stanza_t *query, *item;
char *type, *name;
const char *type, *name;
type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0)
@@ -65,10 +62,7 @@ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
fprintf(stderr, "DEBUG: connected\n");
/* create iq stanza for request */
iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "roster1");
iq = xmpp_iq_new(ctx, "get", "roster1");
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");
@@ -112,6 +106,13 @@ int main(int argc, char **argv)
/* create a connection */
conn = xmpp_conn_new(ctx);
/*
* also you can disable TLS support or force legacy SSL
* connection without STARTTLS
*
* see xmpp_conn_set_flags() or examples/basic.c
*/
/* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]);
xmpp_conn_set_pass(conn, argv[2]);

23
examples/uuid.c Normal file
View File

@@ -0,0 +1,23 @@
#include <stdio.h>
#include <strophe.h>
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
char *uuid;
int rc = 0;
ctx = xmpp_ctx_new(NULL, NULL);
uuid = xmpp_uuid_gen(ctx);
if (uuid != NULL) {
printf("%s\n", uuid);
xmpp_free(ctx, uuid);
} else {
fprintf(stderr, "Couldn't allocate memory.\n");
rc = 1;
}
xmpp_ctx_free(ctx);
return rc;
}

284
examples/vcard.c Normal file
View File

@@ -0,0 +1,284 @@
/* vcard.c
* strophe XMPP client library -- vCard example
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <libgen.h> /* basename */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *recipient;
const char *img_path;
} vcard_t;
typedef void (*vcard_cb_t)(vcard_t *, xmpp_stanza_t *);
#define REQ_TIMEOUT 5000
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *tmp;
char *s;
char *tok;
char *saveptr = NULL;
char *copy;
unsigned char *img;
size_t img_size;
size_t written;
FILE *fd;
tmp = xmpp_stanza_get_child_by_name(stanza, "TYPE");
assert(tmp != NULL);
s = xmpp_stanza_get_text(tmp);
assert(s != NULL);
printf("PHOTO: %s, saving to file %s\n", s, vc->img_path);
xmpp_free(vc->ctx, s);
tmp = xmpp_stanza_get_child_by_name(stanza, "BINVAL");
assert(tmp != NULL);
s = xmpp_stanza_get_text(tmp);
assert(s != NULL);
/* remove \n and \r */
copy = (char *)malloc(strlen(s) + 1);
assert(copy != NULL);
copy[0] = '\0';
tok = strtok_r(s, "\n\r", &saveptr);
while (tok != NULL) {
strcat(copy, tok);
tok = strtok_r(NULL, "\n\r", &saveptr);
}
xmpp_base64_decode_bin(vc->ctx, copy, strlen(copy), &img, &img_size);
assert(img != NULL);
fd = fopen(vc->img_path, "w");
assert(fd != NULL);
written = fwrite(img, 1, img_size, fd);
if (written < img_size)
printf("Saving photo failed\n");
fclose(fd);
free(copy);
xmpp_free(vc->ctx, s);
xmpp_free(vc->ctx, img);
}
static void vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza,
const char *info)
{
char *s = xmpp_stanza_get_text(stanza);
assert(s != NULL);
printf("%s: %s\n", info, s);
xmpp_free(vc->ctx, s);
}
static void vcard_bday(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Birthday");
}
static void vcard_desc(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Description");
}
static void vcard_email(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *userid = xmpp_stanza_get_child_by_name(stanza, "USERID");
if (userid != NULL)
vcard_print_string(vc, userid, "E-mail");
}
static void vcard_fn(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Full name");
}
static void vcard_name(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(stanza, "GIVEN");
xmpp_stanza_t *family = xmpp_stanza_get_child_by_name(stanza, "FAMILY");
if (name != NULL)
vcard_print_string(vc, name, "Given name");
if (family != NULL)
vcard_print_string(vc, family, "Family name");
}
static void vcard_nick(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Nickname");
}
static void vcard_url(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "URL");
}
static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
{
vcard_cb_t cb = NULL;
const char *tag;
size_t i;
static struct {
const char *tag;
vcard_cb_t cb;
} vcard_tbl[] = {
{ "PHOTO", vcard_photo },
{ "BDAY", vcard_bday },
{ "DESC", vcard_desc },
{ "EMAIL", vcard_email },
{ "FN", vcard_fn },
{ "N", vcard_name },
{ "NICKNAME", vcard_nick },
{ "URL", vcard_url },
};
tag = xmpp_stanza_get_name(stanza);
if (tag == NULL)
goto exit;
for (i = 0; i < ARRAY_SIZE(vcard_tbl); ++i) {
if (strcmp(tag, vcard_tbl[i].tag) == 0) {
cb = vcard_tbl[i].cb;
break;
}
}
exit:
return cb;
}
static int timedout(xmpp_conn_t * const conn, void * const userdata)
{
fprintf(stderr, "Timeout reached.\n");
xmpp_disconnect(conn);
return 0;
}
static int recv_vcard(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
void * const userdata)
{
vcard_t *vc = userdata;
vcard_cb_t cb;
xmpp_stanza_t *child;
char *s;
size_t s_size;
int rc;
printf("Received vCard.\n\n");
child = xmpp_stanza_get_child_by_name(stanza, "error");
if (child != NULL) {
rc = xmpp_stanza_to_text(child, &s, &s_size);
assert(rc == XMPP_EOK);
printf("Error returned: %s.\n", s);
xmpp_free(vc->ctx, s);
goto exit;
}
child = xmpp_stanza_get_child_by_name(stanza, "vCard");
assert(child != NULL);
child = xmpp_stanza_get_children(child);
while (child != NULL) {
cb = vcard_cb_get(child);
if (cb != NULL)
cb(vc, child);
child = xmpp_stanza_get_next(child);
}
exit:
xmpp_disconnect(conn);
return 0;
}
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
{
printf("Requesting vCard from %s.\n", to);
xmpp_send_raw_string(conn, "<iq from='%s' to='%s' type='get' id='%s'>"
"<vCard xmlns='vcard-temp'/></iq>",
xmpp_conn_get_bound_jid(conn), to, id);
}
static void conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata)
{
vcard_t *vc = userdata;
if (status == XMPP_CONN_CONNECT) {
send_vcard_req(conn, vc->recipient, "vc1");
xmpp_id_handler_add(conn, recv_vcard, "vc1", vc);
xmpp_timed_handler_add(conn, timedout, REQ_TIMEOUT, NULL);
} else {
if (error != 0)
fprintf(stderr, "Disconnected with error=%d.\n", error);
if (stream_error != NULL)
fprintf(stderr, "Stream error type=%d text=%s.\n",
stream_error->type, stream_error->text);
xmpp_stop(vc->ctx);
}
}
int main(int argc, char **argv)
{
xmpp_log_t *log;
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
const char *jid;
const char *pass;
char *prog;
vcard_t vcard;
if (argc < 4 || argc > 5) {
prog = argc > 0 ? strdup(argv[0]) : NULL;
printf("Usage: %s <login-jid> <password> <recipient-jid> "
"[image-file]\n\n", prog == NULL ? "vcard" : basename(prog));
printf("If vCard contains a photo it will be stored to "
"image-file. If you don't provide the image-file "
"default filename will be generated.\n");
free(prog);
return 1;
}
jid = argv[1];
pass = argv[2];
vcard.recipient = argv[3];
vcard.img_path = argc > 4 ? argv[4] : "vcard.jpg";
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);
vcard.ctx = ctx;
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
xmpp_run(ctx);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

1
expat

Submodule expat deleted from adf19a3186

78
jni/Android.mk Normal file
View File

@@ -0,0 +1,78 @@
LOCAL_PATH:= $(call my-dir)
#
# examples/basic
#
include $(CLEAR_VARS)
LOCAL_MODULE := basic
LOCAL_CFLAGS :=
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/..
LOCAL_SRC_FILES := \
../examples/basic.c
LOCAL_STATIC_LIBRARIES := libstrophe libexpat
include $(BUILD_EXECUTABLE)
#
# libstrohe (static library)
#
include $(CLEAR_VARS)
LOCAL_MODULE := libstrophe
LOCAL_CFLAGS :=
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
$(LOCAL_PATH)/../src \
$(LOCAL_PATH)/../expat/lib
LOCAL_SRC_FILES := \
../src/auth.c \
../src/conn.c \
../src/crypto.c \
../src/ctx.c \
../src/event.c \
../src/handler.c \
../src/hash.c \
../src/jid.c \
../src/md5.c \
../src/parser_expat.c \
../src/rand.c \
../src/resolver.c \
../src/sasl.c \
../src/scram.c \
../src/sha1.c \
../src/snprintf.c \
../src/sock.c \
../src/stanza.c \
../src/tls_dummy.c \
../src/util.c \
../src/uuid.c
LOCAL_STATIC_LIBRARIES := libstrophe
include $(BUILD_STATIC_LIBRARY)
#
# expat
#
include $(CLEAR_VARS)
LOCAL_MODULE := libexpat
LOCAL_CFLAGS := -DHAVE_MEMMOVE
#LOCAL_C_INCLUDES := \
# $(LOCAL_PATH)/expat
LOCAL_SRC_FILES := \
../expat/lib/xmlparse.c \
../expat/lib/xmlrole.c \
../expat/lib/xmltok.c \
../expat/lib/xmltok_impl.c \
../expat/lib/xmltok_ns.c
LOCAL_STATIC_LIBRARIES := libexpat
include $(BUILD_STATIC_LIBRARY)

2
jni/Application.mk Normal file
View File

@@ -0,0 +1,2 @@
APP_ABI := armeabi armeabi-v7a mips x86
APP_PLATFORM := android-19

14
libstrophe.pc.in Normal file
View File

@@ -0,0 +1,14 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libstrophe
Description: A simple, lightweight C library for writing XMPP clients
URL: http://strophe.im/libstrophe/
Version: @VERSION@
Requires:
Requires.private: @PC_REQUIRES@
Libs: -L${libdir} -lstrophe
Libs.private: @PC_LIBS@
Cflags: -I${includedir} @PC_CFLAGS@

View File

@@ -1,6 +1,6 @@
1. Setup
yum install gcc make expat-devel libstrophe
yum install gcc make autoconf automake expat-devel openssl-devel
Fedora:

View File

@@ -8,12 +8,26 @@ License: MIT/GPLv3
URL: http://strophe.im/libstrophe/
Source0: libstrophe_git.tar.gz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: openssl-devel
BuildRequires: expat-devel
Requires: expat
Requires: openssl
Requires: expat
%description
XMPP library in C
%package devel
Summary: Headers and libraries for building apps that use libstrophe
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
%description devel
This package contains headers and libraries required to build applications that
use the strophe XMPP library.
%prep
%setup -n libstrophe
./bootstrap.sh
@@ -25,8 +39,21 @@ make %{?_smp_mflags}
%install
make install DESTDIR=%{buildroot}
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files
%defattr(-,root,root,-)
%{_libdir}/libstrophe.so*
%doc
%files devel
%defattr(-,root,root,-)
%{_libdir}/libstrophe.a
%{_libdir}/libstrophe.la
%{_libdir}/pkgconfig/libstrophe.pc
%{_includedir}/strophe.h
%doc
%changelog

View File

@@ -1,29 +1,27 @@
/* auth.c
** strophe XMPP client library -- auth functions and handlers
**
** Copyright (C) 2005-2009 Collecta, Inc.
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
/** @file
* Authentication function and handlers.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "strophe.h"
#include "common.h"
#include "sasl.h"
#include "sha1.h"
#include "rand.h"
#ifdef _MSC_VER
#define strcasecmp stricmp
@@ -55,9 +53,22 @@
*/
#define LEGACY_TIMEOUT 15000 /* 15 seconds */
#endif
#ifndef HANDSHAKE_TIMEOUT
/** @def HANDSHAKE_TIMEOUT
* Time to wait for component authentication to complete
*/
#define HANDSHAKE_TIMEOUT 15000 /* 15 seconds */
#endif
static void _auth(xmpp_conn_t * const conn);
static void _handle_open_sasl(xmpp_conn_t * const conn);
static void _handle_open_tls(xmpp_conn_t * const conn);
static int _handle_component_auth(xmpp_conn_t * const conn);
static int _handle_component_hs_response(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_missing_legacy(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_legacy(xmpp_conn_t * const conn,
@@ -92,6 +103,8 @@ static int _handle_session(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_missing_session(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_missing_handshake(xmpp_conn_t * const conn,
void * const userdata);
/* stream:error handler */
static int _handle_error(xmpp_conn_t * const conn,
@@ -99,12 +112,12 @@ static int _handle_error(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_stanza_t *child;
char *name;
const char *name;
/* free old stream error if it's still there */
if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza);
if (conn->stream_error->text)
if (conn->stream_error->text)
xmpp_free(conn->ctx, conn->stream_error->text);
xmpp_free(conn->ctx, conn->stream_error);
}
@@ -118,7 +131,7 @@ static int _handle_error(xmpp_conn_t * const conn,
if (conn->stream_error) {
child = xmpp_stanza_get_children(stanza);
do {
char *ns = NULL;
const char *ns = NULL;
if (child) {
ns = xmpp_stanza_get_ns(child);
@@ -225,9 +238,9 @@ static int _handle_features(xmpp_conn_t * const conn,
/* check for SASL */
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_SASL) == 0)) {
for (mech = xmpp_stanza_get_children(child); mech;
for (mech = xmpp_stanza_get_children(child); mech;
mech = xmpp_stanza_get_next(mech)) {
if (strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
text = xmpp_stanza_get_text(mech);
if (strcasecmp(text, "PLAIN") == 0)
conn->sasl_support |= SASL_MASK_PLAIN;
@@ -244,7 +257,7 @@ static int _handle_features(xmpp_conn_t * const conn,
}
_auth(conn);
return 0;
}
@@ -267,33 +280,21 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
char *name;
const char *name;
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",
"handle proceedtls called for %s", name);
xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name);
if (strcmp(name, "proceed") == 0) {
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
conn->tls = tls_new(conn->ctx, conn->sock);
if (!tls_start(conn->tls))
{
xmpp_debug(conn->ctx, "xmpp", "Couldn't start TLS! error %d", tls_error(conn->tls));
tls_free(conn->tls);
conn->tls = NULL;
conn->tls_failed = 1;
/* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn);
}
else
{
conn->secured = 1;
conn_prepare_reset(conn, auth_handle_open);
conn_open_stream(conn);
}
if (conn_tls_start(conn) == 0) {
conn_prepare_reset(conn, _handle_open_tls);
conn_open_stream(conn);
} else {
/* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn);
}
}
return 0;
@@ -303,20 +304,20 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
char *name;
const char *name;
name = xmpp_stanza_get_name(stanza);
/* the server should send a <success> or <failure> stanza */
if (strcmp(name, "failure") == 0) {
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed",
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed",
(char *)userdata);
/* fall back to next auth method */
_auth(conn);
} else if (strcmp(name, "success") == 0) {
/* SASL PLAIN auth successful, we need to restart the stream */
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
/* SASL auth successful, we need to restart the stream */
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
(char *)userdata);
/* reset parser */
@@ -342,7 +343,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
char *text;
char *response;
xmpp_stanza_t *auth, *authdata;
char *name;
const char *name;
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",\
@@ -361,10 +362,10 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
if (!auth) {
disconnect_mem_error(conn);
return 0;
}
}
xmpp_stanza_set_name(auth, "response");
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) {
disconnect_mem_error(conn);
@@ -377,7 +378,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
handler_add(conn, _handle_digestmd5_rspauth,
handler_add(conn, _handle_digestmd5_rspauth,
XMPP_NS_SASL, NULL, NULL, NULL);
xmpp_send(conn, auth);
@@ -397,7 +398,7 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_stanza_t *auth;
char *name;
const char *name;
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",
@@ -410,7 +411,7 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
if (!auth) {
disconnect_mem_error(conn);
return 0;
}
}
xmpp_stanza_set_name(auth, "response");
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
xmpp_send(conn, auth);
@@ -430,7 +431,7 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
char *text;
char *response;
xmpp_stanza_t *auth, *authdata;
char *name;
const char *name;
char *challenge;
char *scram_init = (char *)userdata;
@@ -443,7 +444,7 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
if (!text)
goto err;
challenge = (char *)base64_decode(conn->ctx, text, strlen(text));
challenge = xmpp_base64_decode_str(conn->ctx, text, strlen(text));
xmpp_free(conn->ctx, text);
if (!challenge)
goto err;
@@ -489,46 +490,25 @@ err:
return 0;
}
static char *_get_nonce(xmpp_ctx_t *ctx)
{
unsigned char buffer[sizeof(clock_t) + sizeof(time_t)] = {0};
clock_t ticks = clock();
time_t t;
if (ticks != (clock_t)-1) {
*(clock_t *)buffer = ticks;
}
t = time((time_t *)(buffer + sizeof(clock_t)));
if (t == (time_t)-1) {
*(time_t *)(buffer + sizeof(clock_t)) = (time_t)rand();
}
return base64_encode(ctx, buffer, sizeof(buffer));
}
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
{
xmpp_ctx_t *ctx = conn->ctx;
size_t message_len;
char *node;
char *message;
char *nonce;
char nonce[32];
node = xmpp_jid_node(conn->ctx, conn->jid);
node = xmpp_jid_node(ctx, conn->jid);
if (!node) {
return NULL;
}
nonce = _get_nonce(conn->ctx);
if (!nonce) {
return NULL;
}
xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce));
message_len = strlen(node) + strlen(nonce) + 8 + 1;
message = xmpp_alloc(conn->ctx, message_len);
message = xmpp_alloc(ctx, message_len);
if (message) {
xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
xmpp_free(conn->ctx, node);
}
xmpp_free(conn->ctx, nonce);
xmpp_free(ctx, node);
return message;
}
@@ -543,7 +523,7 @@ static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn)
xmpp_stanza_set_name(starttls, "starttls");
xmpp_stanza_set_ns(starttls, XMPP_NS_TLS);
}
return starttls;
}
@@ -559,14 +539,14 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
xmpp_stanza_set_attribute(auth, "mechanism", mechanism);
}
return auth;
}
/* authenticate the connection
* this may get called multiple times. if any auth method fails,
/* authenticate the connection
* this may get called multiple times. if any auth method fails,
* this will get called again until one auth method succeeds or every
* method fails
* method fails
*/
static void _auth(xmpp_conn_t * const conn)
{
@@ -584,19 +564,15 @@ static void _auth(xmpp_conn_t * const conn)
anonjid = 0;
}
if (conn->tls_support)
{
tls_t *tls = tls_new(conn->ctx, conn->sock);
if (conn->tls_support) {
tls_t *tls = tls_new(conn);
/* If we couldn't init tls, it isn't there, so go on */
if (!tls)
{
if (!tls) {
conn->tls_support = 0;
_auth(conn);
return;
}
else
{
} else {
tls_free(tls);
}
@@ -607,7 +583,7 @@ static void _auth(xmpp_conn_t * const conn)
return;
}
handler_add(conn, _handle_proceedtls_default,
handler_add(conn, _handle_proceedtls_default,
XMPP_NS_TLS, NULL, NULL, NULL);
xmpp_send(conn, auth);
@@ -615,7 +591,18 @@ static void _auth(xmpp_conn_t * const conn)
/* TLS was tried, unset flag */
conn->tls_support = 0;
} else if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
/* _auth() will be called later */
return;
}
if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) {
xmpp_error(conn->ctx, "xmpp", "TLS is not supported, but set as "
"mandatory for this connection");
conn_disconnect(conn);
return;
}
if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
/* some crap here */
auth = _make_sasl_auth(conn, "ANONYMOUS");
if (!auth) {
@@ -632,7 +619,7 @@ static void _auth(xmpp_conn_t * const conn)
/* SASL ANONYMOUS was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
} else if (anonjid) {
xmpp_error(conn->ctx, "auth",
xmpp_error(conn->ctx, "auth",
"No node in JID, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAMSHA1) {
@@ -650,8 +637,8 @@ static void _auth(xmpp_conn_t * const conn)
return;
}
str = (char *)base64_encode(conn->ctx, (unsigned char *)scram_init,
strlen(scram_init));
str = xmpp_base64_encode(conn->ctx, (unsigned char *)scram_init,
strlen(scram_init));
if (!str) {
xmpp_free(conn->ctx, scram_init);
xmpp_stanza_release(auth);
@@ -688,7 +675,7 @@ static void _auth(xmpp_conn_t * const conn)
}
handler_add(conn, _handle_digestmd5_challenge,
handler_add(conn, _handle_digestmd5_challenge,
XMPP_NS_SASL, NULL, NULL, NULL);
xmpp_send(conn, auth);
@@ -706,7 +693,7 @@ static void _auth(xmpp_conn_t * const conn)
if (!authdata) {
disconnect_mem_error(conn);
return;
}
}
authid = _get_authid(conn);
if (!authid) {
disconnect_mem_error(conn);
@@ -734,15 +721,12 @@ static void _auth(xmpp_conn_t * const conn)
conn->sasl_support &= ~SASL_MASK_PLAIN;
} else if (conn->type == XMPP_CLIENT) {
/* legacy client authentication */
iq = xmpp_stanza_new(conn->ctx);
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
if (!iq) {
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_auth1");
query = xmpp_stanza_new(conn->ctx);
if (!query) {
@@ -820,7 +804,7 @@ static void _auth(xmpp_conn_t * const conn)
} else {
xmpp_stanza_release(authdata);
xmpp_stanza_release(iq);
xmpp_error(conn->ctx, "auth",
xmpp_error(conn->ctx, "auth",
"Cannot authenticate without resource");
xmpp_disconnect(conn);
return;
@@ -829,7 +813,7 @@ static void _auth(xmpp_conn_t * const conn)
xmpp_stanza_release(authdata);
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
handler_add_timed(conn, _handle_missing_legacy,
handler_add_timed(conn, _handle_missing_legacy,
LEGACY_TIMEOUT, NULL);
xmpp_send(conn, iq);
@@ -841,7 +825,7 @@ static void _auth(xmpp_conn_t * const conn)
/** Set up handlers at stream start.
* This function is called internally to Strophe for handling the opening
* of an XMPP stream. It's called by the parser when a stream is opened
* or reset, and adds the initial handlers for <stream:error/> and
* or reset, and adds the initial handlers for <stream:error/> and
* <stream:features/>. This function is not intended for use outside
* of Strophe.
*
@@ -852,15 +836,23 @@ void auth_handle_open(xmpp_conn_t * const conn)
/* reset all timed handlers */
handler_reset_timed(conn, 0);
/* setup handler for stream:error */
handler_add(conn, _handle_error,
NULL, "stream:error", NULL, NULL);
/* setup handler for stream:error, we will keep this handler
* for reopened streams until connection is disconnected */
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
/* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features,
NULL, "stream:features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features,
FEATURES_TIMEOUT, NULL);
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
/* called when stream:stream tag received after TLS establishment */
static void _handle_open_tls(xmpp_conn_t * const conn)
{
/* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features,
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
/* called when stream:stream tag received after SASL auth */
@@ -870,7 +862,7 @@ static void _handle_open_sasl(xmpp_conn_t * const conn)
/* setup stream:features handlers */
handler_add(conn, _handle_features_sasl,
NULL, "stream:features", NULL, NULL);
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features_sasl,
FEATURES_TIMEOUT, NULL);
}
@@ -903,23 +895,19 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
/* if bind is required, go ahead and start it */
if (conn->bind_required) {
/* bind resource */
/* setup response handlers */
handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL);
handler_add_timed(conn, _handle_missing_bind,
BIND_TIMEOUT, NULL);
/* send bind request */
iq = xmpp_stanza_new(conn->ctx);
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
if (!iq) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_bind1");
bind = xmpp_stanza_copy(bind);
if (!bind) {
xmpp_stanza_release(iq);
@@ -935,7 +923,7 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
resource = NULL;
}
/* if we have a resource to request, do it. otherwise the
/* if we have a resource to request, do it. otherwise the
server will assign us one */
if (resource) {
res = xmpp_stanza_new(conn->ctx);
@@ -986,12 +974,12 @@ static int _handle_missing_features_sasl(xmpp_conn_t * const conn,
xmpp_disconnect(conn);
return 0;
}
static int _handle_bind(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
char *type;
const char *type;
xmpp_stanza_t *iq, *session;
/* delete missing bind handler */
@@ -1018,24 +1006,21 @@ static int _handle_bind(xmpp_conn_t * const conn,
if (conn->session_required) {
/* setup response handlers */
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
handler_add_timed(conn, _handle_missing_session,
handler_add_timed(conn, _handle_missing_session,
SESSION_TIMEOUT, NULL);
/* send session request */
iq = xmpp_stanza_new(conn->ctx);
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
if (!iq) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "set");
xmpp_stanza_set_id(iq, "_xmpp_session1");
session = xmpp_stanza_new(conn->ctx);
if (!session) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(session, "session");
@@ -1049,9 +1034,9 @@ static int _handle_bind(xmpp_conn_t * const conn,
xmpp_stanza_release(iq);
} else {
conn->authenticated = 1;
/* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL,
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL,
conn->userdata);
}
} else {
@@ -1074,7 +1059,7 @@ static int _handle_session(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
char *type;
const char *type;
/* delete missing session handler */
xmpp_timed_handler_delete(conn, _handle_missing_session);
@@ -1088,7 +1073,7 @@ static int _handle_session(xmpp_conn_t * const conn,
xmpp_debug(conn->ctx, "xmpp", "Session establishment successful.");
conn->authenticated = 1;
/* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} else {
@@ -1111,7 +1096,8 @@ static int _handle_legacy(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
char *type, *name;
const char *type;
const char *name;
/* delete missing handler */
xmpp_timed_handler_delete(conn, _handle_missing_legacy);
@@ -1151,3 +1137,120 @@ static int _handle_missing_legacy(xmpp_conn_t * const conn,
return 0;
}
void auth_handle_component_open(xmpp_conn_t * const conn)
{
int rc;
/* reset all timed handlers */
handler_reset_timed(conn, 0);
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
handler_add(conn, _handle_component_hs_response, NULL,
"handshake", NULL, NULL);
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
rc = _handle_component_auth(conn);
if (rc != 0) {
xmpp_error(conn->ctx, "auth", "Component authentication failed.");
xmpp_disconnect(conn);
}
}
/* Will compute SHA1 and authenticate the component to the server */
int _handle_component_auth(xmpp_conn_t * const conn)
{
uint8_t md_value[SHA1_DIGEST_SIZE];
SHA1_CTX mdctx;
char *digest;
size_t i;
if (conn->stream_id == NULL) {
xmpp_error(conn->ctx, "auth", "Received no stream id from the server.");
return XMPP_EINT;
}
/* Feed the session id and passphrase to the algorithm.
* We need to compute SHA1(session_id + passphrase)
*/
crypto_SHA1_Init(&mdctx);
crypto_SHA1_Update(&mdctx, (uint8_t*)conn->stream_id,
strlen(conn->stream_id));
crypto_SHA1_Update(&mdctx, (uint8_t*)conn->pass, strlen(conn->pass));
crypto_SHA1_Final(&mdctx, md_value);
digest = xmpp_alloc(conn->ctx, 2*sizeof(md_value)+1);
if (digest) {
/* convert the digest into string representation */
for (i = 0; i < sizeof(md_value); i++)
xmpp_snprintf(digest+i*2, 3, "%02x", md_value[i]);
digest[2*sizeof(md_value)] = '\0';
xmpp_debug(conn->ctx, "auth", "Digest: %s, len: %d",
digest, strlen(digest));
/* Send the digest to the server */
xmpp_send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>",
XMPP_NS_COMPONENT, digest);
xmpp_debug(conn->ctx, "auth", "Sent component handshake to the server.");
xmpp_free(conn->ctx, digest);
} else {
xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component "\
"handshake digest.");
return XMPP_EMEM;
}
return 0;
}
/* Check if the received stanza is <handshake/> and set auth to true
* and fire connection handler.
*/
int _handle_component_hs_response(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
const char *name;
xmpp_timed_handler_delete(conn, _handle_missing_handshake);
name = xmpp_stanza_get_name(stanza);
if (strcmp(name, "handshake") != 0) {
char *msg;
size_t msg_size;
xmpp_stanza_to_text(stanza, &msg, &msg_size);
if (msg) {
xmpp_debug(conn->ctx, "auth", "Handshake failed: %s", msg);
xmpp_free(conn->ctx, msg);
}
xmpp_disconnect(conn);
return XMPP_EINT;
} else {
conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
}
/* We don't need this handler anymore, return 0 so it can be deleted
* from the list of handlers.
*/
return 0;
}
int _handle_missing_handshake(xmpp_conn_t * const conn, void * const userdata)
{
xmpp_error(conn->ctx, "xmpp", "Server did not reply to handshake request.");
xmpp_disconnect(conn);
return 0;
}
void auth_handle_open_raw(xmpp_conn_t * const conn)
{
handler_reset_timed(conn, 0);
/* user handlers are not called before authentication is completed. */
conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
}
void auth_handle_open_stub(xmpp_conn_t * const conn)
{
xmpp_warn(conn->ctx, "auth", "Stub callback is called.");
}

View File

@@ -1,15 +1,12 @@
/* common.h
** strophe XMPP client library -- internal common structures
**
** Copyright (C) 2005-2009 Collecta, Inc.
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -30,6 +27,8 @@
#include "hash.h"
#include "util.h"
#include "parser.h"
#include "rand.h"
#include "snprintf.h"
/** run-time context **/
@@ -48,51 +47,43 @@ struct _xmpp_ctx_t {
const xmpp_mem_t *mem;
const xmpp_log_t *log;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist;
unsigned long timeout;
};
/* convenience functions for accessing the context */
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size);
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size);
const size_t size);
char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s);
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap);
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap);
/* wrappers for xmpp_log at specific levels */
void xmpp_error(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
const char * const area,
const char * const fmt,
...);
void xmpp_warn(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
const char * const area,
const char * const fmt,
...);
void xmpp_info(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
const char * const area,
const char * const fmt,
...);
void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
/** jid */
/* these return new strings that must be xmpp_free()'d */
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
const char *domain,
const char *resource);
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid);
const char * const area,
const char * const fmt,
...);
/** connection **/
@@ -116,36 +107,44 @@ typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t {
/* common members */
int user_handler;
void *handler;
int (*handler)();
void *userdata;
int enabled; /* handlers are added disabled and enabled after the
* handler chain is processed to prevent stanzas from
* getting processed by newly added handlers */
* handler chain is processed to prevent stanzas from
* getting processed by newly added handlers */
xmpp_handlist_t *next;
union {
/* timed handlers */
struct {
unsigned long period;
uint64_t last_stamp;
};
/* id handlers */
struct {
char *id;
};
/* normal handlers */
struct {
char *ns;
char *name;
char *type;
};
/* timed handlers */
struct {
unsigned long period;
uint64_t last_stamp;
};
/* id handlers */
struct {
char *id;
};
/* normal handlers */
struct {
char *ns;
char *name;
char *type;
};
};
};
#define SASL_MASK_PLAIN 0x01
#define SASL_MASK_DIGESTMD5 0x02
#define SASL_MASK_ANONYMOUS 0x04
#define SASL_MASK_SCRAMSHA1 0x08
#define MAX_DOMAIN_LEN 256
#define SASL_MASK_PLAIN (1 << 0)
#define SASL_MASK_DIGESTMD5 (1 << 1)
#define SASL_MASK_ANONYMOUS (1 << 2)
#define SASL_MASK_SCRAMSHA1 (1 << 3)
enum {
XMPP_PORT_CLIENT = 5222,
XMPP_PORT_CLIENT_LEGACY_SSL = 5223,
XMPP_PORT_COMPONENT = 5347,
};
typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn);
@@ -153,19 +152,26 @@ struct _xmpp_conn_t {
unsigned int ref;
xmpp_ctx_t *ctx;
xmpp_conn_type_t type;
int is_raw;
xmpp_conn_state_t state;
uint64_t timeout_stamp;
int error;
xmpp_stream_error_t *stream_error;
sock_t sock;
tls_t *tls;
sock_t sock;
int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */
tls_t *tls;
int tls_support;
int tls_disabled;
int tls_mandatory;
int tls_legacy_ssl;
int tls_trust;
int tls_failed; /* set when tls fails, so we don't try again */
int sasl_support; /* if true, field is a bitfield of supported
mechanisms */
mechanisms */
int secured; /* set when stream is secured with TLS */
/* if server returns <bind/> or <session/> we must do them */
@@ -174,8 +180,6 @@ struct _xmpp_conn_t {
char *lang;
char *domain;
char *connectdomain;
char *connectport;
char *jid;
char *pass;
char *bound_jid;
@@ -195,7 +199,7 @@ struct _xmpp_conn_t {
/* timeouts */
unsigned int connect_timeout;
/* event handlers */
/* event handlers */
/* stream open handler */
xmpp_open_handler open_handler;
@@ -215,7 +219,9 @@ struct _xmpp_conn_t {
void conn_disconnect(xmpp_conn_t * const conn);
void conn_disconnect_clean(xmpp_conn_t * const conn);
void conn_established(xmpp_conn_t * const conn);
void conn_open_stream(xmpp_conn_t * const conn);
int conn_tls_start(xmpp_conn_t * const conn);
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
void conn_parser_reset(xmpp_conn_t * const conn);
@@ -244,32 +250,32 @@ struct _xmpp_stanza_t {
/* handler management */
void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza);
xmpp_stanza_t * const stanza);
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx);
void handler_reset_timed(xmpp_conn_t *conn, int user_only);
void handler_add_timed(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
void handler_add_id(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata);
xmpp_handler handler,
const char * const id,
void * const userdata);
void handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */
void disconnect_mem_error(xmpp_conn_t * const conn);
/* auth functions */
void auth_handle_open(xmpp_conn_t * const conn);
/* replacement snprintf and vsnprintf */
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...);
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
void auth_handle_component_open(xmpp_conn_t * const conn);
void auth_handle_open_raw(xmpp_conn_t * const conn);
void auth_handle_open_stub(xmpp_conn_t * const conn);
#endif /* __LIBSTROPHE_COMMON_H__ */

1107
src/conn.c

File diff suppressed because it is too large Load Diff

491
src/crypto.c Normal file
View File

@@ -0,0 +1,491 @@
/* crypto.c
* strophe XMPP client library -- public interface for digests, encodings
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Public interface for digests and encodings used in XEPs.
*/
/** @defgroup Digests Message digests
*/
/** @defgroup Encodings Encodings
*/
#include <assert.h>
#include <string.h> /* memset, memcpy */
#include "common.h" /* xmpp_alloc */
#include "ostypes.h" /* uint8_t, size_t */
#include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */
#include "strophe.h" /* xmpp_ctx_t, xmpp_free */
struct _xmpp_sha1_t {
xmpp_ctx_t *xmpp_ctx;
SHA1_CTX ctx;
uint8_t digest[SHA1_DIGEST_SIZE];
};
static char *digest_to_string(const uint8_t *digest, char *s, size_t len)
{
int i;
if (len < SHA1_DIGEST_SIZE * 2 + 1)
return NULL;
for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
xmpp_snprintf(s + i * 2, 3, "%02x", digest[i]);
return s;
}
static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
{
char *s;
size_t slen;
slen = SHA1_DIGEST_SIZE * 2 + 1;
s = xmpp_alloc(ctx, slen);
if (s) {
s = digest_to_string(digest, s, slen);
assert(s != NULL);
}
return s;
}
/** Compute SHA1 message digest.
* Returns an allocated string which represents SHA1 message digest in
* hexadecimal notation. The string must be freed with xmpp_free().
*
* @param ctx a Strophe context object
* @param data buffer for digest computation
* @param len size of the data buffer
*
* @return an allocated string or NULL on allocation error
*
* @ingroup Digests
*/
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
{
uint8_t digest[SHA1_DIGEST_SIZE];
crypto_SHA1((const uint8_t *)data, len, digest);
return digest_to_string_alloc(ctx, digest);
}
/** Compute SHA1 message digest.
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
* bytes long.
*
* @param data buffer for digest computation
* @param len size of the data buffer
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
*
* @ingroup Digests
*/
void xmpp_sha1_digest(const unsigned char *data, size_t len,
unsigned char *digest)
{
crypto_SHA1((const uint8_t *)data, len, digest);
}
/** Create new SHA1 object.
* SHA1 object is used to compute SHA1 digest of a buffer that is split
* in multiple chunks or provided in stream mode. A single buffer can be
* processed by short functions xmpp_sha1() and xmpp_sha1_digest().
* Follow the next use-case for xmpp_sha1_t object:
* @code
* xmpp_sha1_t *sha1 = xmpp_sha1_new(ctx);
* // Repeat update for all chunks of data
* xmpp_sha1_update(sha1, data, len);
* xmpp_sha1_final(sha1);
* char *digest = xmpp_sha1_to_string_alloc(sha1);
* xmpp_sha1_free(sha1);
* @endcode
*
* @param ctx a Strophe context object
*
* @return new SHA1 object
*
* @ingroup Digests
*/
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
{
xmpp_sha1_t *sha1;
sha1 = xmpp_alloc(ctx, sizeof(*sha1));
if (sha1) {
memset(sha1, 0, sizeof(*sha1));
crypto_SHA1_Init(&sha1->ctx);
sha1->xmpp_ctx = ctx;
}
return sha1;
}
/** Destroy SHA1 object.
*
* @param sha1 a SHA1 object
*
* @ingroup Digests
*/
void xmpp_sha1_free(xmpp_sha1_t *sha1)
{
xmpp_free(sha1->xmpp_ctx, sha1);
}
/** Update SHA1 context with the next portion of data.
* Can be called repeatedly.
*
* @param sha1 a SHA1 object
* @param data pointer to a buffer to be hashed
* @param len size of the data buffer
*
* @ingroup Digests
*/
void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len)
{
crypto_SHA1_Update(&sha1->ctx, data, len);
}
/** Finish SHA1 computation.
* Don't call xmpp_sha1_update() after this function. Retrieve resulting
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
*
* @param sha1 a SHA1 object
*
* @ingroup Digests
*/
void xmpp_sha1_final(xmpp_sha1_t *sha1)
{
crypto_SHA1_Final(&sha1->ctx, sha1->digest);
}
/** Return message digest rendered as a string.
* Stores the string to a user's buffer and returns the buffer. Call this
* function after xmpp_sha1_final().
*
* @param sha1 a SHA1 object
* @param s output string
* @param slen size reserved for the string including '\0'
*
* @return pointer s or NULL if resulting string is bigger than slen bytes
*
* @ingroup Digests
*/
char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
{
return digest_to_string(sha1->digest, s, slen);
}
/** Return message digest rendered as a string.
* Returns an allocated string. Free the string using the Strophe context
* which is passed to xmpp_sha1_new(). Call this function after
* xmpp_sha1_final().
*
* @param sha1 a SHA1 object
*
* @return an allocated string
*
* @ingroup Digests
*/
char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1)
{
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
}
/** Stores message digest to a user's buffer.
*
* @param sha1 a SHA1 object
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
*
* @ingroup Digests
*/
void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest)
{
assert(SHA1_DIGEST_SIZE == XMPP_SHA1_DIGEST_SIZE);
memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE);
}
/* Base64 encoding routines. Implemented according to RFC 3548. */
/* map of all byte values to the base64 values, or to
'65' which indicates an invalid character. '=' is '64' */
static const unsigned char _base64_invcharmap[256] = {
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63,
52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65
};
/* map of all 6-bit values to their corresponding byte
in the base64 alphabet. Padding char is the value '64' */
static const char _base64_charmap[65] = {
'A','B','C','D', 'E','F','G','H',
'I','J','K','L', 'M','N','O','P',
'Q','R','S','T', 'U','V','W','X',
'Y','Z','a','b', 'c','d','e','f',
'g','h','i','j', 'k','l','m','n',
'o','p','q','r', 's','t','u','v',
'w','x','y','z', '0','1','2','3',
'4','5','6','7', '8','9','+','/',
'='
};
static size_t base64_encoded_len(const size_t len)
{
/* encoded steam is 4 bytes for every three, rounded up */
return ((len + 2)/3) << 2;
}
static char *base64_encode(xmpp_ctx_t *ctx,
const unsigned char * const buffer, const size_t len)
{
size_t clen;
char *cbuf, *c;
uint32_t word, hextet;
size_t i;
clen = base64_encoded_len(len);
cbuf = xmpp_alloc(ctx, clen + 1);
if (cbuf != NULL) {
c = cbuf;
/* loop over data, turning every 3 bytes into 4 characters */
for (i = 0; i + 2 < len; i += 3) {
word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2];
hextet = (word & 0x00FC0000) >> 18;
*c++ = _base64_charmap[hextet];
hextet = (word & 0x0003F000) >> 12;
*c++ = _base64_charmap[hextet];
hextet = (word & 0x00000FC0) >> 6;
*c++ = _base64_charmap[hextet];
hextet = (word & 0x000003F);
*c++ = _base64_charmap[hextet];
}
/* zero, one or two bytes left */
switch (len - i) {
case 0:
break;
case 1:
hextet = (buffer[len-1] & 0xFC) >> 2;
*c++ = _base64_charmap[hextet];
hextet = (buffer[len-1] & 0x03) << 4;
*c++ = _base64_charmap[hextet];
*c++ = _base64_charmap[64]; /* pad */
*c++ = _base64_charmap[64]; /* pad */
break;
case 2:
hextet = (buffer[len-2] & 0xFC) >> 2;
*c++ = _base64_charmap[hextet];
hextet = ((buffer[len-2] & 0x03) << 4) |
((buffer[len-1] & 0xF0) >> 4);
*c++ = _base64_charmap[hextet];
hextet = (buffer[len-1] & 0x0F) << 2;
*c++ = _base64_charmap[hextet];
*c++ = _base64_charmap[64]; /* pad */
break;
}
/* add a terminal null */
*c = '\0';
}
return cbuf;
}
static size_t base64_decoded_len(const char * const buffer, const size_t len)
{
size_t nudge = 0;
unsigned char c;
size_t i;
if (len < 4) return 0;
/* count the padding characters for the remainder */
for (i = len; i > 0; --i) {
c = _base64_invcharmap[(unsigned char)buffer[i-1]];
if (c < 64) break;
if (c == 64) ++nudge;
if (c > 64) return 0;
}
if (nudge > 2) return 0;
/* decoded steam is 3 bytes for every four */
return 3 * (len >> 2) - nudge;
}
static void base64_decode(xmpp_ctx_t *ctx,
const char * const buffer, const size_t len,
unsigned char **out, size_t *outlen)
{
size_t dlen;
unsigned char *dbuf, *d;
uint32_t word, hextet = 0;
size_t i;
/* len must be a multiple of 4 */
if (len & 0x03) goto _base64_error;
dlen = base64_decoded_len(buffer, len);
if (dlen == 0) goto _base64_error;
dbuf = xmpp_alloc(ctx, dlen + 1);
if (dbuf != NULL) {
d = dbuf;
/* loop over each set of 4 characters, decoding 3 bytes */
for (i = 0; i + 3 < len; i += 4) {
hextet = _base64_invcharmap[(unsigned char)buffer[i]];
if (hextet & 0xC0) break;
word = hextet << 18;
hextet = _base64_invcharmap[(unsigned char)buffer[i+1]];
if (hextet & 0xC0) break;
word |= hextet << 12;
hextet = _base64_invcharmap[(unsigned char)buffer[i+2]];
if (hextet & 0xC0) break;
word |= hextet << 6;
hextet = _base64_invcharmap[(unsigned char)buffer[i+3]];
if (hextet & 0xC0) break;
word |= hextet;
*d++ = (word & 0x00FF0000) >> 16;
*d++ = (word & 0x0000FF00) >> 8;
*d++ = (word & 0x000000FF);
}
if (hextet > 64) goto _base64_decode_error;
/* handle the remainder */
switch (dlen % 3) {
case 0:
/* nothing to do */
break;
case 1:
/* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(unsigned char)buffer[len-4]];
if (hextet & 0xC0) goto _base64_decode_error;
word = hextet << 2;
hextet = _base64_invcharmap[(unsigned char)buffer[len-3]];
if (hextet & 0xC0) goto _base64_decode_error;
word |= hextet >> 4;
*d++ = word & 0xFF;
hextet = _base64_invcharmap[(unsigned char)buffer[len-2]];
if (hextet != 64) goto _base64_decode_error;
hextet = _base64_invcharmap[(unsigned char)buffer[len-1]];
if (hextet != 64) goto _base64_decode_error;
break;
case 2:
/* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(unsigned char)buffer[len-4]];
if (hextet & 0xC0) goto _base64_decode_error;
word = hextet << 10;
hextet = _base64_invcharmap[(unsigned char)buffer[len-3]];
if (hextet & 0xC0) goto _base64_decode_error;
word |= hextet << 4;
hextet = _base64_invcharmap[(unsigned char)buffer[len-2]];
if (hextet & 0xC0) goto _base64_decode_error;
word |= hextet >> 2;
*d++ = (word & 0xFF00) >> 8;
*d++ = (word & 0x00FF);
hextet = _base64_invcharmap[(unsigned char)buffer[len-1]];
if (hextet != 64) goto _base64_decode_error;
break;
}
*d = '\0';
}
*out = dbuf;
*outlen = dbuf == NULL ? 0 : dlen;
return;
_base64_decode_error:
/* invalid character; abort decoding! */
xmpp_free(ctx, dbuf);
_base64_error:
*out = NULL;
*outlen = 0;
}
/** Base64 encoding routine.
* Returns an allocated string which must be freed with xmpp_free().
*
* @param ctx a Strophe context
* @param data buffer to encode
* @param len size of the data buffer
*
* @return an allocated null-terminated string or NULL on error
*
* @ingroup Encodings
*/
char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
{
return base64_encode(ctx, data, len);
}
/** Base64 decoding routine.
* Returns an allocated string which must be freed with xmpp_free(). User
* calls this function when the result must be a string. When decoded buffer
* contains '\0' NULL is returned.
*
* @param ctx a Strophe context
* @param base64 encoded buffer
* @param len size of the buffer
*
* @return an allocated null-terminated string or NULL on error
*
* @ingroup Encodings
*/
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
{
unsigned char *buf = NULL;
size_t buflen;
if (len == 0) {
/* handle empty string */
buf = xmpp_alloc(ctx, 1);
if (buf)
buf[0] = '\0';
buflen = 0;
} else {
base64_decode(ctx, base64, len, &buf, &buflen);
}
if (buf) {
if (buflen != strlen((char *)buf)) {
xmpp_free(ctx, buf);
buf = NULL;
}
}
return (char *)buf;
}
/** Base64 decoding routine.
* Returns an allocated buffer which must be freed with xmpp_free().
*
* @param ctx a Strophe context
* @param base64 encoded buffer
* @param len size of the encoded buffer
* @param out allocated buffer is stored here
* @param outlen size of the allocated buffer
*
* @note on an error the `*out` will be NULL
*
* @ingroup Encodings
*/
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
unsigned char **out, size_t *outlen)
{
base64_decode(ctx, base64, len, out, outlen);
}

147
src/ctx.c
View File

@@ -1,15 +1,12 @@
/* ctx.c
** strophe XMPP client library -- run-time context implementation
**
** Copyright (C) 2005-2009 Collecta, Inc.
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -39,7 +36,7 @@
* result in strange (and platform dependent) behavior.
*
* Specifically, the socket library on Win32 platforms must be initialized
* before use (although this is not the case on POSIX systems). The TLS
* before use (although this is not the case on POSIX systems). The TLS
* subsystem must also seed the random number generator.
*/
@@ -52,6 +49,11 @@
#include "common.h"
#include "util.h"
/* Workaround for visual studio without va_copy support. */
#if defined(_MSC_VER) && _MSC_VER < 1800
#define va_copy(d,s) ((d) = (s))
#endif
/** Initialize the Strophe library.
* This function initializes subcomponents of the Strophe library and must
* be called for Strophe to operate correctly.
@@ -89,6 +91,14 @@ void xmpp_shutdown(void)
#define LIBXMPP_VERSION_MINOR (0)
#endif
#ifndef EVENT_LOOP_DEFAULT_TIMEOUT
/** @def EVENT_LOOP_DEFAULT_TIMEOUT
* The default timeout in milliseconds for the event loop.
* This is set to 1 second.
*/
#define EVENT_LOOP_DEFAULT_TIMEOUT 1000
#endif
/** Check that Strophe supports a specific API version.
*
* @param major the major version number
@@ -101,12 +111,12 @@ void xmpp_shutdown(void)
int xmpp_version_check(int major, int minor)
{
return (major == LIBXMPP_VERSION_MAJOR) &&
(minor >= LIBXMPP_VERSION_MINOR);
(minor >= LIBXMPP_VERSION_MINOR);
}
/* We define the global default allocator, logger, and context here. */
/* Wrap stdlib routines malloc, free, and realloc for default memory
/* Wrap stdlib routines malloc, free, and realloc for default memory
* management.
*/
static void *_malloc(const size_t size, void * const userdata)
@@ -135,9 +145,9 @@ static xmpp_mem_t xmpp_default_mem = {
/* log levels and names */
static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
/** Log a message.
* The default logger writes to stderr.
@@ -148,21 +158,21 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
* @param area the area the log message is for
* @param msg the log message
*/
void xmpp_default_logger(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
static void xmpp_default_logger(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
xmpp_log_level_t filter_level = * (xmpp_log_level_t*)userdata;
if (level >= filter_level)
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
}
static const xmpp_log_t _xmpp_default_loggers[] = {
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
};
/** Get a default logger with filtering.
@@ -180,7 +190,6 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
{
/* clamp to the known range */
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG;
return (xmpp_log_t*)&_xmpp_default_loggers[level];
}
@@ -190,7 +199,7 @@ static xmpp_log_t xmpp_default_log = { NULL, NULL };
/* convenience functions for accessing the context */
/** Allocate memory in a Strophe context.
* All Strophe functions will use this to allocate memory.
* All Strophe functions will use this to allocate memory.
*
* @param ctx a Strophe context object
* @param size the number of bytes to allocate
@@ -223,7 +232,7 @@ void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
* @return a pointer to the reallocated memory or NULL on an error
*/
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size)
const size_t size)
{
return ctx->mem->realloc(p, size, ctx->mem->userdata);
}
@@ -232,7 +241,7 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
* Write a log message to the logger for the context for the specified
* level and area. This function takes a printf-style format string and a
* variable argument list (in va_list) format. This function is not meant
* to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
* to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
* and xmpp_debug.
*
* @param ctx a Strophe context object
@@ -242,10 +251,10 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
* @param ap variable argument list supplied for the format string
*/
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap)
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap)
{
int oldret, ret;
char smbuf[1024];
@@ -255,23 +264,23 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
va_copy(copy, ap);
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
if (ret >= (int)sizeof(smbuf)) {
buf = (char *)xmpp_alloc(ctx, ret + 1);
if (!buf) {
buf = NULL;
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
va_end(copy);
return;
}
oldret = ret;
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
if (ret > oldret) {
xmpp_error(ctx, "log", "Unexpected error");
xmpp_free(ctx, buf);
va_end(copy);
return;
}
buf = (char *)xmpp_alloc(ctx, ret + 1);
if (!buf) {
buf = NULL;
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
va_end(copy);
return;
}
oldret = ret;
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
if (ret > oldret) {
xmpp_error(ctx, "log", "Unexpected error");
xmpp_free(ctx, buf);
va_end(copy);
return;
}
} else {
buf = smbuf;
buf = smbuf;
}
va_end(copy);
@@ -284,7 +293,7 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
/** Write to the log at the ERROR level.
* This is a convenience function for writing to the log at the
* ERROR level. It takes a printf-style format string followed by a
* ERROR level. It takes a printf-style format string followed by a
* variable list of arguments for formatting.
*
* @param ctx a Strophe context object
@@ -384,29 +393,35 @@ void xmpp_debug(const xmpp_ctx_t * const ctx,
*
* @ingroup Context
*/
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
{
xmpp_ctx_t *ctx = NULL;
if (mem == NULL)
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
else
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
if (ctx != NULL) {
if (mem != NULL)
ctx->mem = mem;
else
ctx->mem = &xmpp_default_mem;
if (mem != NULL)
ctx->mem = mem;
else
ctx->mem = &xmpp_default_mem;
if (log == NULL)
ctx->log = &xmpp_default_log;
else
ctx->log = log;
if (log == NULL)
ctx->log = &xmpp_default_log;
else
ctx->log = log;
ctx->connlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->connlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
if (ctx->rand == NULL) {
xmpp_free(ctx, ctx);
ctx = NULL;
}
}
return ctx;
@@ -421,6 +436,18 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
void xmpp_ctx_free(xmpp_ctx_t * const ctx)
{
/* mem and log are owned by their suppliers */
xmpp_rand_free(ctx, ctx->rand);
xmpp_free(ctx, ctx); /* pull the hole in after us */
}
/** Set the timeout to use when calling xmpp_run().
*
* @param ctx a Strophe context object
* @param timeout the time to wait for events in milliseconds
*
* @ingroup Context
*/
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout)
{
ctx->timeout = timeout;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -17,15 +14,15 @@
*/
/** @defgroup EventLoop Event loop
* These functions manage the Strophe event loop.
*
* These functions manage the Strophe event loop.
*
* Simple tools can use xmpp_run() and xmpp_stop() to manage the life
* cycle of the program. A common idiom is to set up a few initial
* event handers, call xmpp_run(), and then respond and react to
* events as they come in. At some point, one of the handlers will
* call xmpp_stop() to quit the event loop which leads to the program
* terminating.
*
*
* More complex programs will have their own event loops, and should
* ensure that xmpp_run_once() is called regularly from there. For
* example, a GUI program will already include an event loop to
@@ -40,25 +37,20 @@
#ifndef _WIN32
#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
#define _sleep(x) usleep((x) * 1000)
#else
#include <winsock2.h>
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNRESET WSAECONNRESET
#define ECONNABORTED WSAECONNABORTED
#define _sleep(x) Sleep(x)
#endif
#include <strophe.h>
#include "common.h"
#include "parser.h"
#ifndef DEFAULT_TIMEOUT
/** @def DEFAULT_TIMEOUT
* The default timeout in milliseconds for the event loop.
* This is set to 1 millisecond.
*/
#define DEFAULT_TIMEOUT 1
#endif
/** Run the event loop once.
* This function will run send any data that has been queued by
* xmpp_send and related functions and run through the Strophe even
@@ -84,230 +76,219 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
int towrite;
char buf[4096];
uint64_t next;
long usec;
uint64_t usec;
int tls_read_bytes = 0;
if (ctx->loop_status == XMPP_LOOP_QUIT) return;
ctx->loop_status = XMPP_LOOP_RUNNING;
/* send queued data */
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
if (conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next;
continue;
}
conn = connitem->conn;
if (conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next;
continue;
}
/* if we're running tls, there may be some remaining data waiting to
* be sent, so push that out */
if (conn->tls) {
ret = tls_clear_pending_write(conn->tls);
/* if we're running tls, there may be some remaining data waiting to
* be sent, so push that out */
if (conn->tls) {
ret = tls_clear_pending_write(conn->tls);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occured */
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
}
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occurred */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
}
/* write all data from the send queue to the socket */
sq = conn->send_queue_head;
while (sq) {
towrite = sq->len - sq->written;
/* write all data from the send queue to the socket */
sq = conn->send_queue_head;
while (sq) {
towrite = sq->len - sq->written;
if (conn->tls) {
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
if (conn->tls) {
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
conn->error = tls_error(conn->tls);
} else {
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
if (ret < 0 && !sock_is_recoverable(sock_error()))
conn->error = sock_error();
}
if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */
if (ret != towrite)
break; /* partial write or an error */
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occured */
conn->error = tls_error(conn->tls);
break;
} else if (ret < towrite) {
/* not all data could be sent now */
if (ret >= 0) sq->written += ret;
break;
}
/* all data for this queue item written, delete and move on */
xmpp_free(ctx, sq->data);
tsq = sq;
sq = sq->next;
conn->send_queue_len--;
xmpp_free(ctx, tsq);
} else {
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
/* pop the top item */
conn->send_queue_head = sq;
/* if we've sent everything update the tail */
if (!sq) conn->send_queue_tail = NULL;
}
if (ret < 0 && !sock_is_recoverable(sock_error())) {
/* an error occured */
conn->error = sock_error();
break;
} else if (ret < towrite) {
/* not all data could be sent now */
if (ret >= 0) sq->written += ret;
break;
}
}
/* tear down connection on error */
if (conn->error) {
/* FIXME: need to tear down send queues and random other things
* maybe this should be abstracted */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
/* all data for this queue item written, delete and move on */
xmpp_free(ctx, sq->data);
tsq = sq;
sq = sq->next;
xmpp_free(ctx, tsq);
/* pop the top item */
conn->send_queue_head = sq;
/* if we've sent everything update the tail */
if (!sq) conn->send_queue_tail = NULL;
}
/* tear down connection on error */
if (conn->error) {
/* FIXME: need to tear down send queues and random other things
* maybe this should be abstracted */
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
connitem = connitem->next;
connitem = connitem->next;
}
/* reset parsers if needed */
for (connitem = ctx->connlist; connitem; connitem = connitem->next) {
if (connitem->conn->reset_parser)
conn_parser_reset(connitem->conn);
if (connitem->conn->reset_parser)
conn_parser_reset(connitem->conn);
}
/* fire any ready timed handlers, then
make sure we don't wait past the time when timed handlers need
to be called */
/* fire any ready timed handlers, then make sure we don't wait past
the time when timed handlers need to be called */
next = handler_fire_timed(ctx);
usec = ((next < timeout) ? next : timeout) * 1000;
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
tv.tv_sec = (long)(usec / 1000000);
tv.tv_usec = (long)(usec % 1000000);
FD_ZERO(&rfds);
FD_ZERO(&rfds);
FD_ZERO(&wfds);
/* find events to watch */
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
/* connect has been called and we're waiting for it to complete */
/* connection will give us write or error events */
/* make sure the timeout hasn't expired */
if (time_elapsed(conn->timeout_stamp, time_stamp()) <=
conn->connect_timeout)
FD_SET(conn->sock, &wfds);
else {
conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn);
}
break;
case XMPP_STATE_CONNECTED:
FD_SET(conn->sock, &rfds);
break;
case XMPP_STATE_DISCONNECTED:
/* do nothing */
default:
break;
}
/* Check if there is something in the SSL buffer. */
if (conn->tls) {
tls_read_bytes += tls_pending(conn->tls);
}
if (conn->sock > max) max = conn->sock;
conn = connitem->conn;
connitem = connitem->next;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
/* connect has been called and we're waiting for it to complete */
/* connection will give us write or error events */
/* make sure the timeout hasn't expired */
if (time_elapsed(conn->timeout_stamp, time_stamp()) <=
conn->connect_timeout)
FD_SET(conn->sock, &wfds);
else {
conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn);
}
break;
case XMPP_STATE_CONNECTED:
FD_SET(conn->sock, &rfds);
if (conn->send_queue_len > 0)
FD_SET(conn->sock, &wfds);
break;
case XMPP_STATE_DISCONNECTED:
/* do nothing */
default:
break;
}
/* Check if there is something in the SSL buffer. */
if (conn->tls)
tls_read_bytes += tls_pending(conn->tls);
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
max = conn->sock;
connitem = connitem->next;
}
/* check for events */
ret = select(max + 1, &rfds, &wfds, NULL, &tv);
if (max > 0)
ret = select(max + 1, &rfds, &wfds, NULL, &tv);
else {
if (timeout > 0)
_sleep(timeout);
return;
}
/* select errored */
if (ret < 0) {
if (!sock_is_recoverable(sock_error()))
xmpp_error(ctx, "xmpp", "event watcher internal error %d",
sock_error());
return;
if (!sock_is_recoverable(sock_error()))
xmpp_error(ctx, "xmpp", "event watcher internal error %d",
sock_error());
return;
}
/* no events happened */
if (ret == 0 && tls_read_bytes == 0) return;
/* process events */
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
conn = connitem->conn;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
if (FD_ISSET(conn->sock, &wfds)) {
/* connection complete */
switch (conn->state) {
case XMPP_STATE_CONNECTING:
if (FD_ISSET(conn->sock, &wfds)) {
/* connection complete */
/* check for error */
if (sock_connect_error(conn->sock) != 0) {
/* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed");
conn_disconnect(conn);
break;
}
/* check for error */
ret = sock_connect_error(conn->sock);
if (ret != 0) {
/* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
conn_disconnect(conn);
break;
}
conn->state = XMPP_STATE_CONNECTED;
xmpp_debug(ctx, "xmpp", "connection successful");
conn->state = XMPP_STATE_CONNECTED;
xmpp_debug(ctx, "xmpp", "connection successful");
conn_established(conn);
}
/* send stream init */
conn_open_stream(conn);
}
break;
case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
if (conn->tls) {
ret = tls_read(conn->tls, buf, 4096);
} else {
ret = sock_read(conn->sock, buf, 4096);
}
break;
case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
if (conn->tls) {
ret = tls_read(conn->tls, buf, 4096);
} else {
ret = sock_read(conn->sock, buf, 4096);
}
if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret);
if (!ret) {
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf);
xmpp_send_error(conn, XMPP_SE_INVALID_XML, "parse error");
}
} else {
if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) {
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
conn->error = tls_error(conn->tls);
conn_disconnect(conn);
}
} else {
/* return of 0 means socket closed by server */
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
conn->error = ECONNRESET;
conn_disconnect(conn);
}
}
}
if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret);
if (!ret) {
/* parse error, we need to shut down */
/* FIXME */
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
conn_disconnect(conn);
}
} else {
if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls)))
{
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
conn->error = tls_error(conn->tls);
conn_disconnect(conn);
}
} else {
/* return of 0 means socket closed by server */
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
conn->error = ECONNRESET;
conn_disconnect(conn);
}
}
}
break;
case XMPP_STATE_DISCONNECTED:
/* do nothing */
default:
break;
}
break;
case XMPP_STATE_DISCONNECTED:
/* do nothing */
default:
break;
}
connitem = connitem->next;
connitem = connitem->next;
}
/* fire any ready handlers */
@@ -328,9 +309,12 @@ void xmpp_run(xmpp_ctx_t *ctx)
ctx->loop_status = XMPP_LOOP_RUNNING;
while (ctx->loop_status == XMPP_LOOP_RUNNING) {
xmpp_run_once(ctx, DEFAULT_TIMEOUT);
xmpp_run_once(ctx, ctx->timeout);
}
/* make it possible to start event loop again */
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
xmpp_debug(ctx, "event", "Event loop completed.");
}
@@ -347,5 +331,5 @@ void xmpp_stop(xmpp_ctx_t *ctx)
xmpp_debug(ctx, "event", "Stopping event loop.");
if (ctx->loop_status == XMPP_LOOP_RUNNING)
ctx->loop_status = XMPP_LOOP_QUIT;
ctx->loop_status = XMPP_LOOP_QUIT;
}

View File

@@ -1,15 +1,12 @@
/* handler.c
** strophe XMPP client library -- event handler management
**
** Copyright (C) 2005-2009 Collecta, Inc.
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -27,6 +24,31 @@
#include "common.h"
#include "ostypes.h"
/* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
* must handle this situation correctly. Current function helps to avoid
* list corruption in described scenario.
*
* TODO Convert handler lists to double-linked lists. Current implementation
* works for O(n).
*/
static void _handler_item_remove(xmpp_handlist_t **head,
xmpp_handlist_t *item)
{
xmpp_handlist_t *i = *head;
if (i == item)
*head = item->next;
else if (i != NULL) {
while (i->next != NULL && i->next != item)
i = i->next;
if (i->next == item) {
i->next = item->next;
}
}
}
/** Fire off all stanza handlers that match.
* This function is called internally by the event loop whenever stanzas
* are received from the XMPP server.
@@ -35,92 +57,83 @@
* @param stanza a Strophe stanza object
*/
void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza)
xmpp_stanza_t * const stanza)
{
xmpp_handlist_t *item, *prev;
char *id, *ns, *name, *type;
xmpp_handlist_t *item, *next, *head, *head_old;
const char *id, *ns, *name, *type;
int ret;
/* call id handlers */
id = xmpp_stanza_get_id(stanza);
if (id) {
prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) {
xmpp_handlist_t *next = item->next;
head = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
/* enable all added handlers */
for (item = head; item; item = item->next)
item->enabled = 1;
if (item->user_handler && !conn->authenticated) {
item = next;
continue;
}
item = head;
while (item) {
/* don't fire user handlers until authentication succeeds and
and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = item->next;
continue;
}
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
/* handler is one-shot, so delete it */
if (prev)
prev->next = next;
else {
hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, next);
}
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
next = item->next;
if (!ret) {
/* handler is one-shot, so delete it */
head_old = head;
_handler_item_remove(&head, item);
if (head != head_old) {
/* replace old value */
hash_add(conn->id_handlers, id, head);
}
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
item = NULL;
}
if (item)
prev = item;
item = next;
}
xmpp_free(conn->ctx, item);
}
item = next;
}
}
/* call handlers */
ns = xmpp_stanza_get_ns(stanza);
name = xmpp_stanza_get_name(stanza);
type = xmpp_stanza_get_type(stanza);
/* enable all added handlers */
for (item = conn->handlers; item; item = item->next)
item->enabled = 1;
item->enabled = 1;
prev = NULL;
item = conn->handlers;
while (item) {
/* skip newly added handlers */
if (!item->enabled) {
prev = item;
item = item->next;
continue;
}
/* don't fire user handlers until authentication succeeds and
skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = item->next;
continue;
}
/* don't call user handlers until authentication succeeds */
if (item->user_handler && !conn->authenticated) {
prev = item;
item = item->next;
continue;
}
next = item->next;
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
(!item->name || (name && strcmp(name, item->name) == 0)) &&
(!item->type || (type && strcmp(type, item->type) == 0))) {
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
(!item->name || (name && strcmp(name, item->name) == 0)) &&
(!item->type || (type && strcmp(type, item->type) == 0)))
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
/* handler is one-shot, so delete it */
if (prev)
prev->next = item->next;
else
conn->handlers = item->next;
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* handler is one-shot, so delete it */
_handler_item_remove(&conn->handlers, item);
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item);
item = NULL;
}
if (item) {
prev = item;
item = item->next;
} else if (prev)
item = prev->next;
else
item = conn->handlers;
xmpp_free(conn->ctx, item);
}
}
item = next;
}
}
@@ -134,57 +147,56 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
{
xmpp_connlist_t *connitem;
xmpp_handlist_t *handitem, *temp;
int ret, fired;
xmpp_handlist_t *item, *next;
xmpp_conn_t *conn;
uint64_t elapsed, min;
uint64_t timestamp;
int ret;
min = (uint64_t)(-1);
connitem = ctx->connlist;
while (connitem) {
if (connitem->conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next;
continue;
}
/* enable all handlers that were added */
for (handitem = connitem->conn->timed_handlers; handitem;
handitem = handitem->next)
handitem->enabled = 1;
conn = connitem->conn;
if (conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next;
continue;
}
handitem = connitem->conn->timed_handlers;
while (handitem) {
/* skip newly added handlers */
if (!handitem->enabled) {
handitem = handitem->next;
continue;
}
/* enable all handlers that were added */
for (item = conn->timed_handlers; item; item = item->next)
item->enabled = 1;
/* only fire user handlers after authentication */
if (handitem->user_handler && !connitem->conn->authenticated) {
handitem = handitem->next;
continue;
}
item = conn->timed_handlers;
while (item) {
/* don't fire user handlers until authentication succeeds and
skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = item->next;
continue;
}
fired = 0;
elapsed = time_elapsed(handitem->last_stamp, time_stamp());
if (elapsed >= handitem->period) {
/* fire! */
fired = 1;
handitem->last_stamp = time_stamp();
ret = ((xmpp_timed_handler)handitem->handler)(connitem->conn, handitem->userdata);
} else if (min > (handitem->period - elapsed))
min = handitem->period - elapsed;
temp = handitem;
handitem = handitem->next;
next = item->next;
timestamp = time_stamp();
elapsed = time_elapsed(item->last_stamp, timestamp);
if (elapsed >= item->period) {
/* fire! */
item->last_stamp = timestamp;
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(conn->ctx, item);
}
} else if (min > (item->period - elapsed))
min = item->period - elapsed;
/* delete handler if it returned false */
if (fired && !ret)
xmpp_timed_handler_delete(connitem->conn, temp->handler);
}
item = next;
}
connitem = connitem->next;
connitem = connitem->next;
}
return min;
@@ -202,25 +214,27 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
handitem = conn->timed_handlers;
while (handitem) {
if ((user_only && handitem->user_handler) || !user_only)
handitem->last_stamp = time_stamp();
handitem = handitem->next;
if ((user_only && handitem->user_handler) || !user_only)
handitem->last_stamp = time_stamp();
handitem = handitem->next;
}
}
static void _timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata,
const int user_handler)
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata,
const int user_handler)
{
xmpp_handlist_t *item, *tail;
/* check if handler is already in the list */
for (item = conn->timed_handlers; item; item = item->next) {
if (item->handler == (void *)handler)
break;
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
break;
}
}
if (item) return;
@@ -229,7 +243,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
if (!item) return;
item->user_handler = user_handler;
item->handler = (void *)handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
@@ -239,12 +253,12 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
/* append item to list */
if (!conn->timed_handlers)
conn->timed_handlers = item;
conn->timed_handlers = item;
else {
tail = conn->timed_handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
tail = conn->timed_handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
}
}
@@ -256,7 +270,7 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
xmpp_timed_handler handler)
xmpp_timed_handler handler)
{
xmpp_handlist_t *item, *prev;
@@ -265,35 +279,36 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
prev = NULL;
item = conn->timed_handlers;
while (item) {
if (item->handler == (void *)handler)
break;
prev = item;
item = item->next;
}
if (item->handler == handler) {
if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
if (item) {
if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
xmpp_free(conn->ctx, item);
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->timed_handlers;
} else {
prev = item;
item = item->next;
}
}
}
static void _id_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata, int user_handler)
xmpp_handler handler,
const char * const id,
void * const userdata, int user_handler)
{
xmpp_handlist_t *item, *tail;
/* check if handler is already in the list */
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) {
if (item->handler == (void *)handler)
break;
item = item->next;
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
break;
}
item = item->next;
}
if (item) return;
@@ -302,25 +317,25 @@ static void _id_handler_add(xmpp_conn_t * const conn,
if (!item) return;
item->user_handler = user_handler;
item->handler = (void *)handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
item->id = xmpp_strdup(conn->ctx, id);
if (!item->id) {
xmpp_free(conn->ctx, item);
return;
xmpp_free(conn->ctx, item);
return;
}
/* put on list in hash table */
tail = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!tail)
hash_add(conn->id_handlers, id, item);
hash_add(conn->id_handlers, id, item);
else {
while (tail->next)
tail = tail->next;
tail->next = item;
while (tail->next)
tail = tail->next;
tail->next = item;
}
}
@@ -333,49 +348,54 @@ static void _id_handler_add(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_id_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id)
xmpp_handler handler,
const char * const id)
{
xmpp_handlist_t *item, *prev;
xmpp_handlist_t *item, *prev, *next;
prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!item) return;
while (item) {
if (item->handler == (void *)handler)
break;
next = item->next;
prev = item;
item = item->next;
}
if (item->handler == handler) {
if (prev)
prev->next = next;
else {
hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, next);
}
if (item) {
if (prev)
prev->next = item->next;
else {
hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, item->next);
}
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
item = next;
} else {
prev = item;
item = next;
}
}
}
/* add a stanza handler */
static void _handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata, int user_handler)
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata, int user_handler)
{
xmpp_handlist_t *item, *tail;
/* check if handler already in list */
for (item = conn->handlers; item; item = item->next) {
if (item->handler == (void *)handler)
break;
/* same handler function can process different stanzas and
distinguish them according to userdata. */
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
break;
}
}
if (item) return;
@@ -384,46 +404,46 @@ static void _handler_add(xmpp_conn_t * const conn,
if (!item) return;
item->user_handler = user_handler;
item->handler = (void *)handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
if (ns) {
item->ns = xmpp_strdup(conn->ctx, ns);
if (!item->ns) {
xmpp_free(conn->ctx, item);
return;
}
item->ns = xmpp_strdup(conn->ctx, ns);
if (!item->ns) {
xmpp_free(conn->ctx, item);
return;
}
} else
item->ns = NULL;
item->ns = NULL;
if (name) {
item->name = xmpp_strdup(conn->ctx, name);
if (!item->name) {
if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item);
return;
}
item->name = xmpp_strdup(conn->ctx, name);
if (!item->name) {
if (item->ns) xmpp_free(conn->ctx, item->ns);
xmpp_free(conn->ctx, item);
return;
}
} else
item->name = NULL;
item->name = NULL;
if (type) {
item->type = xmpp_strdup(conn->ctx, type);
if (!item->type) {
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
xmpp_free(conn->ctx, item);
}
item->type = xmpp_strdup(conn->ctx, type);
if (!item->type) {
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
xmpp_free(conn->ctx, item);
}
} else
item->type = NULL;
item->type = NULL;
/* append to list */
if (!conn->handlers)
conn->handlers = item;
conn->handlers = item;
else {
tail = conn->handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
tail = conn->handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
}
}
@@ -435,7 +455,7 @@ static void _handler_add(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler)
xmpp_handler handler)
{
xmpp_handlist_t *prev, *item;
@@ -444,23 +464,21 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
prev = NULL;
item = conn->handlers;
while (item) {
if (item->handler == (void *)handler)
break;
prev = item;
item = item->next;
}
if (item->handler == handler) {
if (prev)
prev->next = item->next;
else
conn->handlers = item->next;
if (item) {
if (prev)
prev->next = item->next;
else
conn->handlers = item->next;
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item);
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->handlers;
} else {
prev = item;
item = item->next;
}
}
}
@@ -469,7 +487,7 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
* and continue firing regularly after that. Strophe will try its best
* to fire handlers as close to the period times as it can, but accuracy
* will vary depending on the resolution of the event loop.
*
*
* If the handler function returns true, it will be kept, and if it
* returns false, it will be deleted from the list of handlers.
*
@@ -481,9 +499,9 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
{
_timed_handler_add(conn, handler, period, userdata, 1);
}
@@ -498,9 +516,9 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn,
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add_timed(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
{
_timed_handler_add(conn, handler, period, userdata, 0);
}
@@ -522,9 +540,9 @@ void handler_add_timed(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_id_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata)
xmpp_handler handler,
const char * const id,
void * const userdata)
{
_id_handler_add(conn, handler, id, userdata, 1);
}
@@ -539,9 +557,9 @@ void xmpp_id_handler_add(xmpp_conn_t * const conn,
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add_id(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const id,
void * const userdata)
xmpp_handler handler,
const char * const id,
void * const userdata)
{
_id_handler_add(conn, handler, id, userdata, 0);
}
@@ -569,11 +587,11 @@ void handler_add_id(xmpp_conn_t * const conn,
* @ingroup Handlers
*/
void xmpp_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
{
_handler_add(conn, handler, ns, name, type, userdata, 1);
}
@@ -590,11 +608,83 @@ void xmpp_handler_add(xmpp_conn_t * const conn,
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
{
_handler_add(conn, handler, ns, name, type, userdata, 0);
}
/** Delete all system handlers.
* This function is used to reset conn object before re-connecting.
*
* @param conn a Strophe connection object
*/
void handler_system_delete_all(xmpp_conn_t *conn)
{
xmpp_handlist_t *item, *next, *head, *head_old;
hash_iterator_t *iter;
const char *key;
char *key2 = NULL;
/* TODO unify all kinds of handlers and avoid copy-paste below */
item = conn->handlers;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->handlers, item);
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item);
item = next;
} else
item = item->next;
}
item = conn->timed_handlers;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(conn->ctx, item);
item = next;
} else
item = item->next;
}
iter = hash_iter_new(conn->id_handlers);
key = iter == NULL ? NULL : hash_iter_next(iter);
while (key != NULL) {
head = head_old = (xmpp_handlist_t *)hash_get(conn->id_handlers, key);
item = head;
while (item) {
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&head, item);
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
item = next;
} else
item = item->next;
}
if (head != head_old)
key2 = xmpp_strdup(conn->ctx, key);
/* Hash table implementation is not perfect, so we need to find next
key before dropping current one. Otherwise, we will get access to
freed memory. */
key = hash_iter_next(iter);
if (head != head_old) {
/* hash_add() replaces value if the key exists */
if (head != NULL)
hash_add(conn->id_handlers, key2, head);
else
hash_drop(conn->id_handlers, key2);
xmpp_free(conn->ctx, key2);
}
}
if (iter) hash_iter_release(iter);
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -50,7 +47,7 @@ struct _hash_iterator_t {
/** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free)
hash_free_func free_func)
{
hash_t *result = NULL;
@@ -65,7 +62,7 @@ hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
result->length = size;
result->ctx = ctx;
result->free = free;
result->free = free_func;
result->num_keys = 0;
/* give the caller a reference */
result->ref = 1;
@@ -109,18 +106,35 @@ void hash_release(hash_t * const table)
/** hash a key for our table lookup */
static int _hash_key(hash_t *table, const char *key)
{
int hash = 0;
int shift = 0;
const char *c = key;
unsigned hash = 0;
unsigned shift = 0;
const unsigned char *c = (const unsigned char *)key;
while (*c != '\0') {
while (*c != 0) {
/* assume 32 bit ints */
hash ^= ((int)*c++ << shift);
hash ^= ((unsigned)*c++ << shift);
shift += 8;
if (shift > 24) shift = 0;
}
return hash % (unsigned)table->length;
}
return hash % table->length;
hashentry_t *_hash_entry_find(hash_t *table, const char *key)
{
hashentry_t *entry;
int table_index = _hash_key(table, key);
/* look up the hash entry */
entry = table->entries[table_index];
while (entry != NULL) {
/* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) {
/* match */
break;
}
entry = entry->next;
}
return entry;
}
/** add a key, value pair to a hash table.
@@ -131,25 +145,27 @@ int hash_add(hash_t *table, const char * const key, void *data)
{
xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry = NULL;
int index = _hash_key(table, key);
int table_index = _hash_key(table, key);
/* drop existing entry, if any */
hash_drop(table, key);
/* find and replace existing entry, if any */
entry = _hash_entry_find(table, key);
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
return -1;
if (entry == NULL) {
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
return -1;
}
/* insert ourselves in the linked list */
entry->next = table->entries[table_index];
table->entries[table_index] = entry;
table->num_keys++;
}
entry->value = data;
/* insert ourselves in the linked list */
/* TODO: this leaks duplicate keys */
entry->next = table->entries[index];
table->entries[index] = entry;
table->num_keys++;
return 0;
}
@@ -158,22 +174,9 @@ int hash_add(hash_t *table, const char * const key, void *data)
void *hash_get(hash_t *table, const char *key)
{
hashentry_t *entry;
int index = _hash_key(table, key);
void *result = NULL;
/* look up the hash entry */
entry = table->entries[index];
while (entry != NULL) {
/* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) {
/* match */
result = entry->value;
return result;
}
entry = entry->next;
}
/* no match */
return result;
entry = _hash_entry_find(table, key);
return entry == NULL ? NULL : entry->value;
}
/** delete a key from a hash table */
@@ -181,10 +184,10 @@ int hash_drop(hash_t *table, const char *key)
{
xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry, *prev;
int index = _hash_key(table, key);
int table_index = _hash_key(table, key);
/* look up the hash entry */
entry = table->entries[index];
entry = table->entries[table_index];
prev = NULL;
while (entry != NULL) {
/* traverse the linked list looking for the key */
@@ -193,7 +196,7 @@ int hash_drop(hash_t *table, const char *key)
xmpp_free(ctx, entry->key);
if (table->free) table->free(ctx, entry->value);
if (prev == NULL) {
table->entries[index] = entry->next;
table->entries[table_index] = entry->next;
} else {
prev->next = entry->next;
}
@@ -238,7 +241,7 @@ void hash_iter_release(hash_iterator_t *iter)
iter->ref--;
if (iter->ref <= 0) {
if (iter->ref == 0) { // ref is unsigned!!!
hash_release(iter->table);
xmpp_free(ctx, iter);
}
@@ -250,12 +253,13 @@ const char * hash_iter_next(hash_iterator_t *iter)
{
hash_t *table = iter->table;
hashentry_t *entry = iter->entry;
int i = iter->index + 1;
int i;
/* advance until we find the next entry */
if (entry != NULL) entry = entry->next;
if (entry == NULL) {
/* we're off the end of list, search for a new entry */
i = iter->index + 1;
while (i < iter->table->length) {
entry = table->entries[i];
if (entry != NULL) {
@@ -266,7 +270,7 @@ const char * hash_iter_next(hash_iterator_t *iter)
}
}
if ((entry == NULL) || (i >= table->length)) {
if (entry == NULL) {
/* no more keys! */
return NULL;
}
@@ -275,4 +279,3 @@ const char * hash_iter_next(hash_iterator_t *iter)
iter->entry = entry;
return entry->key;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -25,7 +22,7 @@ typedef void (*hash_free_func)(const xmpp_ctx_t * const ctx, void *p);
/** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free);
hash_free_func free_func);
/** allocate a new reference to an existing hash table */
hash_t *hash_clone(hash_t * const table);

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -36,7 +33,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
const char *resource)
{
char *result;
int len,nlen,dlen,rlen;
size_t len, nlen, dlen, rlen;
/* jid must at least have a domain */
if (domain == NULL) return NULL;
@@ -59,7 +56,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
result[nlen+dlen] = '/';
memcpy(result+nlen+dlen+1, resource, rlen - 1);
}
result[nlen+dlen+rlen] = '\0';
result[len] = '\0';
}
return result;
@@ -75,15 +72,13 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
{
char *result;
const char *c;
size_t len;
c = strchr(jid, '/');
if (c == NULL) return xmpp_strdup(ctx, jid);
result = xmpp_alloc(ctx, c-jid+1);
len = strcspn(jid, "/");
result = xmpp_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, jid, c-jid);
result[c-jid] = '\0';
memcpy(result, jid, len);
result[len] = '\0';
}
return result;
@@ -124,7 +119,8 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
{
char *result = NULL;
const char *c,*s;
const char *c;
size_t dlen;
c = strchr(jid, '@');
if (c == NULL) {
@@ -134,15 +130,11 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
/* advance past the separator */
c++;
}
s = strchr(c, '/');
if (s == NULL) {
/* no resource */
s = c + strlen(c);
}
result = xmpp_alloc(ctx, (s-c) + 1);
dlen = strcspn(c, "/"); /* do not include resource */
result = xmpp_alloc(ctx, dlen + 1);
if (result != NULL) {
memcpy(result, c, (s-c));
result[s-c] = '\0';
memcpy(result, c, dlen);
result[dlen] = '\0';
}
return result;
@@ -158,20 +150,8 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
*/
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
{
char *result = NULL;
const char *c;
int len;
c = strchr(jid, '/');
if (c != NULL) {
c++;
len = strlen(c);
result = xmpp_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, c, len);
result[len] = '\0';
}
}
return result;
return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL;
}

View File

@@ -37,14 +37,14 @@
#define PUT_32BIT_LSB_FIRST(cp, value) \
do { \
(cp)[0] = (value) & 0xFF; \
(cp)[1] = ((value) >> 8) & 0xFF; \
(cp)[2] = ((value) >> 16) & 0xFF; \
(cp)[3] = ((value) >> 24) & 0xFF; \
(cp)[0] = (value) & 0xFF; \
(cp)[1] = ((value) >> 8) & 0xFF; \
(cp)[2] = ((value) >> 16) & 0xFF; \
(cp)[3] = ((value) >> 24) & 0xFF; \
} while(0)
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
struct MD5Context *ctx);
struct MD5Context *ctx);
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
@@ -60,7 +60,7 @@ void MD5Init(struct MD5Context *ctx)
ctx->bits[0] = 0;
ctx->bits[1] = 0;
memset(ctx->in, 0, 64);
memset(ctx->in, 0, 64);
}
/*
@@ -75,33 +75,33 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
t = ctx->bits[0];
if ((ctx->bits[0] = (t + ((uint32_t)len << 3)) & 0xffffffff) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = ctx->in + t;
unsigned char *p = ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
MD5Transform(ctx->buf, ctx->in, ctx);
buf += t;
len -= t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
MD5Transform(ctx->buf, ctx->in, ctx);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
MD5Transform(ctx->buf, ctx->in, ctx);
buf += 64;
len -= 64;
memcpy(ctx->in, buf, 64);
MD5Transform(ctx->buf, ctx->in, ctx);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
@@ -131,15 +131,15 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
MD5Transform(ctx->buf, ctx->in, ctx);
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
MD5Transform(ctx->buf, ctx->in, ctx);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
/* Append length in bits and transform */
@@ -151,11 +151,9 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
PUT_32BIT_LSB_FIRST(digest + 12, ctx->buf[3]);
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
#ifndef ASM_MD5
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
@@ -168,14 +166,14 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
/* debugging version: */
/*
#define MD5STEP(f, w, x, y, z, data, s) \
printf("MD5STEP: w: %x x: %x y: %x z: %x data: %x s: %x\n", \
w, x, y, z, data, s); \
printf("f(x,y,z) = %x\n", f(x,y,z)+data); \
( w += f(x, y, z) + data, printf(" - w: %x ", w), \
w = w<<s | w>>(32-s), printf(" - w: %x\n", w), w += x )
printf("MD5STEP: w: %x x: %x y: %x z: %x data: %x s: %x\n", \
w, x, y, z, data, s); \
printf("f(x,y,z) = %x\n", f(x,y,z)+data); \
( w += f(x, y, z) + data, printf(" - w: %x ", w), \
w = w<<s | w>>(32-s), printf(" - w: %x\n", w), w += x )
*/
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
@@ -183,7 +181,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
struct MD5Context *ctx)
struct MD5Context *ctx)
{
register uint32_t a, b, c, d, i;
uint32_t in[16];
@@ -270,23 +268,3 @@ static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
buf[2] += c;
buf[3] += d;
}
#ifdef DEBUG_MD5
#include <stdio.h>
void MD5DumpBytes(unsigned char *b, int len)
{
int i;
for (i=0; i<len; i++) {
if (i%32==0 && i!=0) {
printf("\n");
}
printf("%02x", b[i]&0xff);
}
printf("\n");
}
#endif /* DEBUG_MD5 */
#endif /* !MD5_ASM */

View File

@@ -15,18 +15,14 @@
#include "ostypes.h"
struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
unsigned char in[64];
uint32_t buf[4];
uint32_t bits[2];
unsigned char in[64];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
uint32_t len);
uint32_t len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
#ifdef DEBUG_MD5
void MD5DumpBytes(unsigned char *b, int len);
#endif
#endif /* !MD5_H */

View File

@@ -1,15 +1,12 @@
/* oocontext.cpp
** strophe XMPP client library -- C++ context implementation
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdlib.h>
@@ -17,7 +14,7 @@
#include "strophe.h"
#include "strophepp.h"
XMPP::Context::Context()
XMPP::Context::Context()
{
m_mem.alloc = callAlloc;
m_mem.realloc = callRealloc;
@@ -51,8 +48,8 @@ void XMPP::Context::free(void *p)
}
void XMPP::Context::log(const xmpp_log_level_t level,
const char * const area,
const char * const msg)
const char * const area,
const char * const msg)
{
/* do nothing by default */
}
@@ -68,7 +65,7 @@ void *XMPP::Context::callAlloc(const size_t size, void * const userdata)
}
void *XMPP::Context::callRealloc(void *p, const size_t size,
void * const userdata)
void * const userdata)
{
return reinterpret_cast<Context *>(userdata)->realloc(p, size);
}
@@ -79,10 +76,9 @@ void XMPP::Context::callFree(void *p, void * const userdata)
}
void XMPP::Context::callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
}

View File

@@ -1,15 +1,12 @@
/* oostanza.cpp
** strophe XMPP client library -- C++ context implementation
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include "strophe.h"
@@ -31,8 +28,8 @@ void *Stanza::operator new(size_t size, Context *ctx)
if (!p) return p;
*reinterpret_cast<Context **>(p) = ctx;
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
sizeof(Context *));
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
sizeof(Context *));
return p;
}
@@ -64,7 +61,7 @@ Stanza *Stanza::create(Context *ctx)
void Stanza::release()
{
if (::xmpp_stanza_release(m_stanza))
delete this;
delete this;
}
Stanza *Stanza::clone()
@@ -78,5 +75,3 @@ Stanza *Stanza::copy()
// TODO
return NULL;
}

View File

@@ -7,10 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -20,6 +17,8 @@
#ifndef __LIBSTROPHE_OSTYPES_H__
#define __LIBSTROPHE_OSTYPES_H__
#include <stddef.h> /* size_t */
#if defined (_MSC_VER) && _MSC_VER < 1600
typedef signed char int8_t;
typedef short int int16_t;
@@ -30,6 +29,17 @@ typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
#ifndef UINT16_MAX
#define UINT16_MAX ((uint16_t)0xffff)
#endif /* UINT16_MAX */
#ifndef UINT32_MAX
#define UINT32_MAX ((uint32_t)0xffffffff)
#endif /* UINT32_MAX */
#ifndef SIZE_MAX
#define SIZE_MAX UINT32_MAX
#endif /* SIZE_MAX */
#else
#include <stdint.h>
#endif

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -36,7 +33,8 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
parser_end_callback endcb,
parser_stanza_callback stanzacb,
void *userdata);
void parser_free(parser_t * const parser);
void parser_free(parser_t *parser);
char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname);
int parser_reset(parser_t *parser);
int parser_feed(parser_t *parser, char *chunk, int len);

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -26,6 +23,15 @@
#include "common.h"
#include "parser.h"
/* Use the Unit Separator to delimit namespace and name in our XML*/
#define NAMESPACE_SEP ('\x1F')
/* Allocate inner text by this number bytes more. Expat splits string
* "new\nline" into 3 strings: "new" "\n" "line". Expecting this pattern,
* we can leave few bytes in the inner_text for "\n". It should reduce
* number of re-allocations in 2 times for multi-line texts. */
#define INNER_TEXT_PADDING 2
struct _parser_t {
xmpp_ctx_t *ctx;
XML_Parser expat;
@@ -35,25 +41,98 @@ struct _parser_t {
void *userdata;
int depth;
xmpp_stanza_t *stanza;
char* inner_text;
/* number of allocated bytes */
int inner_text_size;
/* excluding terminal '\0' */
int inner_text_used;
};
/* return allocated string with the name from a delimited
* namespace/name string */
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
{
char *result = NULL;
const char *c;
size_t len;
c = strchr(nsname, NAMESPACE_SEP);
if (c == NULL) return xmpp_strdup(ctx, nsname);
c++;
len = strlen(c);
result = xmpp_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, c, len);
result[len] = '\0';
}
return result;
}
/* return allocated string with the namespace from a delimited string */
static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
{
char *result = NULL;
const char *c;
c = strchr(nsname, NAMESPACE_SEP);
if (c != NULL) {
result = xmpp_alloc(ctx, (c-nsname) + 1);
if (result != NULL) {
memcpy(result, nsname, (c-nsname));
result[c-nsname] = '\0';
}
}
return result;
}
static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
{
char *attr;
int i;
if (!attrs) return;
for (i = 0; attrs[i]; i += 2) {
xmpp_stanza_set_attribute(stanza, attrs[i], attrs[i+1]);
/* namespaced attributes aren't used in xmpp, discard namespace */
attr = _xml_name(stanza->ctx, attrs[i]);
xmpp_stanza_set_attribute(stanza, attr, attrs[i+1]);
xmpp_free(stanza->ctx, attr);
}
}
static void complete_inner_text(parser_t *parser)
{
xmpp_stanza_t *stanza;
if (parser->inner_text) {
/* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx);
/* FIXME: disconnect on allocation error */
if (stanza) {
xmpp_stanza_set_text(stanza, parser->inner_text);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
}
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
}
}
static void _start_element(void *userdata,
const XML_Char *name,
const XML_Char *nsname,
const XML_Char **attrs)
{
parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *child;
char *ns, *name;
ns = _xml_namespace(parser->ctx, nsname);
name = _xml_name(parser->ctx, nsname);
if (parser->depth == 0) {
/* notify the owner */
@@ -61,39 +140,33 @@ static void _start_element(void *userdata,
parser->startcb((char *)name, (char **)attrs,
parser->userdata);
} else {
/* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) {
/* something terrible happened */
/* FIXME: shutdown disconnect */
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
} else if (!parser->stanza) {
/* starting a new toplevel stanza */
parser->stanza = xmpp_stanza_new(parser->ctx);
if (!parser->stanza) {
/* FIXME: can't allocate, disconnect */
}
xmpp_stanza_set_name(parser->stanza, name);
_set_attributes(parser->stanza, attrs);
} else {
/* starting a child of parser->stanza */
child = xmpp_stanza_new(parser->ctx);
if (!child) {
/* FIXME: can't allocate, disconnect */
}
xmpp_stanza_set_name(child, name);
_set_attributes(child, attrs);
/* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) {
/* something terrible happened */
/* FIXME: shutdown disconnect */
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
} else {
child = xmpp_stanza_new(parser->ctx);
if (!child) {
/* FIXME: can't allocate, disconnect */
}
xmpp_stanza_set_name(child, name);
_set_attributes(child, attrs);
if (ns)
xmpp_stanza_set_ns(child, ns);
/* add child to parent */
xmpp_stanza_add_child(parser->stanza, child);
/* the child is owned by the toplevel stanza now */
xmpp_stanza_release(child);
/* make child the current stanza */
parser->stanza = child;
}
if (parser->stanza != NULL) {
complete_inner_text(parser);
xmpp_stanza_add_child(parser->stanza, child);
xmpp_stanza_release(child);
}
parser->stanza = child;
}
}
if (ns) xmpp_free(parser->ctx, ns);
if (name) xmpp_free(parser->ctx, name);
parser->depth++;
}
@@ -108,36 +181,46 @@ static void _end_element(void *userdata, const XML_Char *name)
if (parser->endcb)
parser->endcb((char *)name, parser->userdata);
} else {
if (parser->stanza->parent) {
/* we're finishing a child stanza, so set current to the parent */
parser->stanza = parser->stanza->parent;
} else {
complete_inner_text(parser);
if (parser->stanza->parent) {
/* we're finishing a child stanza, so set current to the parent */
parser->stanza = parser->stanza->parent;
} else {
if (parser->stanzacb)
parser->stanzacb(parser->stanza,
parser->userdata);
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}
}
}
static void _characters(void *userdata, const XML_Char *s, int len)
{
parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *stanza;
char *p;
if (parser->depth < 2) return;
/* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx);
if (!stanza) {
/* FIXME: allocation error, disconnect */
return;
/* Join all parts to a single resulting string. Stanza is created in
* _start_element() and _end_element(). */
if (parser->inner_text_used + len >= parser->inner_text_size) {
parser->inner_text_size = parser->inner_text_used + len + 1 +
INNER_TEXT_PADDING;
p = xmpp_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size);
if (p == NULL) {
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_used = 0;
parser->inner_text_size = 0;
return;
}
parser->inner_text = p;
parser->inner_text[parser->inner_text_used] = '\0';
}
xmpp_stanza_set_text_with_size(stanza, s, len);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
parser->inner_text_used += len;
strncat(parser->inner_text, s, len);
}
parser_t *parser_new(xmpp_ctx_t *ctx,
@@ -158,6 +241,9 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
parser->userdata = userdata;
parser->depth = 0;
parser->stanza = NULL;
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
parser_reset(parser);
}
@@ -165,12 +251,22 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
return parser;
}
char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{
return _xml_name(ctx, nsname);
}
/* free a parser */
void parser_free(parser_t *parser)
{
if (parser->expat)
XML_ParserFree(parser->expat);
if (parser->inner_text) {
xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
xmpp_free(parser->ctx, parser);
}
@@ -183,12 +279,17 @@ int parser_reset(parser_t *parser)
if (parser->stanza)
xmpp_stanza_release(parser->stanza);
parser->expat = XML_ParserCreate(NULL);
parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
if (!parser->expat) return 0;
parser->depth = 0;
parser->stanza = NULL;
if (parser->inner_text) {
xmpp_free (parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
XML_SetUserData(parser->expat, parser);
XML_SetElementHandler(parser->expat, _start_element, _end_element);
XML_SetCharacterDataHandler(parser->expat, _characters);

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -39,28 +36,92 @@ struct _parser_t {
xmpp_stanza_t *stanza;
};
static void _set_attributes(xmpp_stanza_t *stanza, const xmlChar **attrs)
static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
const xmlChar **attrs)
{
int i;
int i, len;
char *value;
if (!attrs) return;
for (i = 0; attrs[i]; i += 2) {
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], (const char *)attrs[i+1]);
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
for (i = 0; i < nattrs*5; i += 5) {
len = attrs[i+4] - attrs[i+3];
value = xmpp_alloc(stanza->ctx, len + 1);
if (value) {
memcpy(value, attrs[i+3], len);
value[len] = '\0';
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value);
xmpp_free(stanza->ctx, value);
}
}
}
/* SAX2 gives us the attrs in an incredibly inconvenient array,
* convert it to what the start callback is expecting */
static char **_convert_attrs(parser_t *parser, int nattrs,
const xmlChar **attrs)
{
int c, i, o, len;
char *value;
char **ret;
if (!attrs) return NULL;
ret = xmpp_alloc(parser->ctx, (nattrs+1)*2*sizeof(char*));
if (!ret) return NULL;
memset(ret, 0, (nattrs+1)*2*sizeof(char*));
for (c = 0; c < nattrs; c++) {
i = c * 5;
o = c * 2;
len = attrs[i+4] - attrs[i+3];
value = xmpp_alloc(parser->ctx, len + 1);
if (value) {
memcpy(value, attrs[i+3], len);
value[len] = '\0';
ret[o] = xmpp_strdup(parser->ctx, (char*)attrs[i]);
ret[o+1] = value;
}
}
return ret;
}
static void _free_cbattrs(parser_t *parser, char **attrs)
{
int i;
if (!attrs)
return;
for (i = 0; attrs[i]; i += 2) {
if (attrs[i]) xmpp_free(parser->ctx, attrs[i]);
if (attrs[i+1]) xmpp_free(parser->ctx, attrs[i+1]);
}
xmpp_free(parser->ctx, attrs);
}
static void _start_element(void *userdata,
const xmlChar *name, const xmlChar **attrs)
const xmlChar *name, const xmlChar *prefix,
const xmlChar *uri, int nnamespaces,
const xmlChar **namespaces, int nattrs,
int ndefaulted, const xmlChar **attrs)
{
parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *child;
char **cbattrs;
if (parser->depth == 0) {
/* notify the owner */
if (parser->startcb)
parser->startcb((char *)name, (char **)attrs,
if (parser->startcb) {
cbattrs = _convert_attrs(parser, nattrs, attrs);
parser->startcb((char *)name, cbattrs,
parser->userdata);
_free_cbattrs(parser, cbattrs);
}
} else {
/* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) {
@@ -74,7 +135,9 @@ static void _start_element(void *userdata,
/* FIXME: can't allocate, disconnect */
}
xmpp_stanza_set_name(parser->stanza, (char *)name);
_set_attributes(parser->stanza, attrs);
_set_attributes(parser->stanza, nattrs, attrs);
if (uri)
xmpp_stanza_set_ns(parser->stanza, (char *)uri);
} else {
/* starting a child of conn->stanza */
child = xmpp_stanza_new(parser->ctx);
@@ -82,7 +145,9 @@ static void _start_element(void *userdata,
/* FIXME: can't allocate, disconnect */
}
xmpp_stanza_set_name(child, (char *)name);
_set_attributes(child, attrs);
_set_attributes(child, nattrs, attrs);
if (uri)
xmpp_stanza_set_ns(child, (char *)uri);
/* add child to parent */
xmpp_stanza_add_child(parser->stanza, child);
@@ -98,7 +163,8 @@ static void _start_element(void *userdata,
parser->depth++;
}
static void _end_element(void *userdata, const xmlChar *name)
static void _end_element(void *userdata, const xmlChar *name,
const xmlChar *prefix, const xmlChar *uri)
{
parser_t *parser = (parser_t *)userdata;
@@ -156,8 +222,9 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
parser->ctx = ctx;
parser->xmlctx = NULL;
memset(&parser->handlers, 0, sizeof(xmlSAXHandler));
parser->handlers.startElement = _start_element;
parser->handlers.endElement = _end_element;
parser->handlers.initialized = XML_SAX2_MAGIC;
parser->handlers.startElementNs = _start_element;
parser->handlers.endElementNs = _end_element;
parser->handlers.characters = _characters;
parser->startcb = startcb;
parser->endcb = endcb;
@@ -172,11 +239,18 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
return parser;
}
char* parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{
return xmpp_strdup(ctx, nsname);
}
/* free a parser */
void parser_free(parser_t *parser)
{
if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
xmpp_stanza_release(parser->stanza);
xmpp_free(parser->ctx, parser);
}
@@ -185,28 +259,22 @@ int parser_reset(parser_t *parser)
{
if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
parser->depth = 0;
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
parser, NULL, 0, NULL);
if (!parser->xmlctx) return 0;
parser->depth = 0;
parser->stanza = NULL;
return 1;
return parser->xmlctx ? 1 : 0;
}
/* feed a chunk of data to the parser */
int parser_feed(parser_t *parser, char *chunk, int len)
{
/* xmlParseChunk API returns 0 on success which is opposite logic to
/* xmlParseChunk API returns 0 on success which is opposite logic to
the status returned by parser_feed */
if(!xmlParseChunk(parser->xmlctx, chunk, len, 0)) {
return 1;
} else {
return 0;
}
return !xmlParseChunk(parser->xmlctx, chunk, len, 0);
}

311
src/rand.c Normal file
View File

@@ -0,0 +1,311 @@
/* rand.c
* strophe XMPP client library -- pseudo-random number generator
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Pseudo-random number generator.
*
* Implemented Hash_DRBG mechanism according to NIST SP 800-90A.
* Hash function is SHA1.
*/
/** @defgroup Random Pseudo-random number generator
*/
#include <assert.h>
#include <string.h> /* memeset */
#include <time.h> /* clock, time */
#include "common.h" /* xmpp_alloc, xmpp_free */
#include "ostypes.h" /* uint8_t, uint32_t, size_t */
#include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */
#include "rand.h" /* xmpp_rand_t */
#define outlen SHA1_DIGEST_SIZE
#define seedlen (440 / 8)
#define reseed_interval 0x7fffffff
/* maximum number of bytes that can be generated per call */
#define GENERATE_MAX (outlen * 10)
#define ENTROPY_MAX 128
#define NONCE_MAX 8
#define RESEED_NEEDED (-1)
struct Hash_DRBG_CTX_struc {
uint8_t V[seedlen];
uint8_t C[seedlen];
uint32_t reseed_counter;
};
typedef struct Hash_DRBG_CTX_struc Hash_DRBG_CTX;
struct _xmpp_rand_t {
int inited;
unsigned reseed_count;
Hash_DRBG_CTX ctx;
};
/* returns smallest number mupliple of y that not less than x */
#define round_up(x, y) (((x) + (y) - 1) / (y) * (y))
/* returns smallest integer number that not less than x/y */
#define div_round_up(x, y) (((x) + (y) - 1) / (y))
/* adds two arrays as numbers in big-endian representation and stores
* result in the first one.
*/
static void arr_add(uint8_t *arr1, size_t arr1_len,
uint8_t *arr2, size_t arr2_len)
{
size_t i;
uint32_t acc;
uint32_t carry = 0;
assert(arr1_len >= arr2_len);
for (i = 1; (i <= arr2_len) || (carry != 0 && i <= arr1_len); ++i) {
acc = (uint32_t)arr1[arr1_len - i] + carry;
if (i <= arr2_len)
acc += (uint32_t)arr2[arr2_len - i];
carry = acc >> 8;
arr1[arr1_len - i] = (uint8_t)(acc & 0xff);
}
}
/* stores 32-bit number in big-endian representation */
static void store_be32(uint32_t val, uint8_t be[4])
{
be[0] = (uint8_t)((val >> 24) & 0xff);
be[1] = (uint8_t)((val >> 16) & 0xff);
be[2] = (uint8_t)((val >> 8) & 0xff);
be[3] = (uint8_t)(val & 0xff);
}
static void Hash_df(uint8_t *input_string, size_t input_string_len,
uint8_t *output_string, size_t no_of_bytes_to_return)
{
uint8_t counter;
uint8_t temp[round_up(seedlen, outlen)];
uint8_t conj[ENTROPY_MAX + NONCE_MAX + seedlen + 6];
size_t len;
size_t i;
size_t offset;
assert(no_of_bytes_to_return <= sizeof(temp));
assert(input_string_len + 5 <= sizeof(conj));
len = div_round_up(no_of_bytes_to_return, outlen);
for (i = 1; i <= len; ++i) {
offset = (i - 1) * outlen;
counter = (uint8_t)i;
conj[0] = counter;
store_be32((uint32_t)no_of_bytes_to_return * 8, conj + 1);
memcpy(conj + 5, input_string, input_string_len);
crypto_SHA1(conj, input_string_len + 5, temp + offset);
}
memcpy(output_string, temp, no_of_bytes_to_return);
}
/* assume personalization_string is zero length string */
static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
uint8_t *entropy_input,
size_t entropy_input_len,
uint8_t *nonce, size_t nonce_len)
{
uint8_t seed_material[ENTROPY_MAX + NONCE_MAX];
uint8_t seed0[seedlen + 1];
uint8_t *seed = seed0 + 1;
assert(entropy_input_len <= ENTROPY_MAX);
assert(nonce_len <= NONCE_MAX);
memcpy(seed_material, entropy_input, entropy_input_len);
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen);
seed0[0] = 0;
memcpy(ctx->V, seed, seedlen);
Hash_df(seed0, sizeof(seed0), ctx->C, seedlen);
ctx->reseed_counter = 1;
}
/* assume additional_input is zero length string */
static void Hash_DRBG_Reseed(Hash_DRBG_CTX *ctx,
uint8_t *entropy_input,
size_t entropy_input_len)
{
uint8_t seed_material[1 + seedlen + ENTROPY_MAX];
uint8_t seed0[seedlen + 1];
uint8_t *seed = seed0 + 1;
assert(entropy_input_len <= ENTROPY_MAX);
seed_material[0] = 1;
memcpy(seed_material + 1, ctx->V, seedlen);
memcpy(seed_material + 1 + seedlen, entropy_input, entropy_input_len);
Hash_df(seed_material, entropy_input_len + seedlen + 1, seed, seedlen);
seed0[0] = 0;
memcpy(ctx->V, seed, seedlen);
Hash_df(seed0, sizeof(seed0), ctx->C, seedlen);
ctx->reseed_counter = 1;
}
static void Hashgen(uint8_t *V, uint8_t *output,
size_t requested_number_of_bytes)
{
uint8_t data[seedlen];
uint8_t W[GENERATE_MAX];
uint8_t i1 = 1;
size_t m;
size_t i;
size_t offset;
assert(requested_number_of_bytes <= sizeof(W));
m = div_round_up(requested_number_of_bytes, outlen);
memcpy(data, V, seedlen);
for (i = 1; i <= m; ++i) {
offset = (i - 1) * outlen;
crypto_SHA1(data, seedlen, W + offset);
/* increase data by 1 */
arr_add(data, sizeof(data), &i1, 1);
}
memcpy(output, W, requested_number_of_bytes);
}
/* assume additional_input is zero length string */
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx, uint8_t *output,
size_t requested_number_of_bytes)
{
uint8_t H[outlen];
uint8_t V3[seedlen + 1];
uint8_t reseed_counter[4];
if (ctx->reseed_counter > reseed_interval || ctx->reseed_counter == 0)
return RESEED_NEEDED;
Hashgen(ctx->V, output, requested_number_of_bytes);
V3[0] = 3;
memcpy(V3 + 1, ctx->V, seedlen);
crypto_SHA1(V3, sizeof(V3), H);
arr_add(ctx->V, sizeof(ctx->V), ctx->C, sizeof(ctx->C));
arr_add(ctx->V, sizeof(ctx->V), H, sizeof(H));
store_be32(ctx->reseed_counter, reseed_counter);
arr_add(ctx->V, sizeof(ctx->V), reseed_counter, sizeof(reseed_counter));
++ctx->reseed_counter;
return 0;
}
#define ENTROPY_ACCUMULATE(ptr, last, type, arg) \
do { \
type __arg = (type)(arg); \
if ((char*)ptr + sizeof(__arg) < (char*)last) { \
*(type*)ptr = __arg; \
ptr = (void*)((char*)ptr + sizeof(__arg)); \
} \
} while (0)
static void xmpp_rand_reseed(xmpp_rand_t *rand)
{
uint8_t entropy[ENTROPY_MAX];
uint8_t *ptr = entropy;
const uint8_t *last = entropy + sizeof(entropy);
size_t len;
/* entropy:
* 1. time_stamp()
* 2. clock(3)
* 3. xmpp_rand_t address to make unique seed within one process
* 4. counter to make unique seed within one context
* 5. stack address
* 6. local ports of every connection in list (getsockname)
* 7. other non-constant info that can be retieved from socket
*
* rand(3) can't be used as it isn't thread-safe.
* XXX 6 and 7 are not implemented yet.
*/
ENTROPY_ACCUMULATE(ptr, last, uint64_t, time_stamp());
ENTROPY_ACCUMULATE(ptr, last, clock_t, clock());
ENTROPY_ACCUMULATE(ptr, last, void *, rand);
ENTROPY_ACCUMULATE(ptr, last, unsigned, ++rand->reseed_count);
ENTROPY_ACCUMULATE(ptr, last, void *, &entropy);
len = ptr - entropy;
if (rand->inited) {
Hash_DRBG_Reseed(&rand->ctx, entropy, len);
} else {
Hash_DRBG_Instantiate(&rand->ctx, entropy, len, NULL, 0);
rand->inited = 1;
}
}
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
{
xmpp_rand_t *out = xmpp_alloc(ctx, sizeof(*out));
if (out != NULL) {
memset(out, 0, sizeof(*out));
}
return out;
}
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand)
{
xmpp_free(ctx, rand);
}
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len)
{
int rc;
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
if (rc == RESEED_NEEDED) {
xmpp_rand_reseed(rand);
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
assert(rc == 0);
}
}
int xmpp_rand(xmpp_rand_t *rand)
{
int result;
xmpp_rand_bytes(rand, (unsigned char *)&result, sizeof(result));
return result;
}
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
{
size_t i;
size_t rand_len = len / 2;
#ifndef _MSC_VER
unsigned char rand_buf[rand_len];
#else
unsigned char *rand_buf = (unsigned char *)_alloca(rand_len);
#endif
/* current implementation returns printable HEX representation of
* a random buffer, however base64 encoding can be used instead;
* the only problem is that base64_encode() allocates memory and
* as result can fail.
*/
xmpp_rand_bytes(rand, rand_buf, rand_len);
for (i = 0; i < rand_len; ++i) {
xmpp_snprintf(output + i * 2, len, "%02x", rand_buf[i]);
len -= 2;
}
}

65
src/rand.h Normal file
View File

@@ -0,0 +1,65 @@
/* rand.h
* strophe XMPP client library -- pseudo-random number generator
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Pseudo-random number generator.
*/
#ifndef __LIBSTROPHE_RAND_H__
#define __LIBSTROPHE_RAND_H__
#include <stddef.h> /* size_t */
#include "strophe.h" /* xmpp_ctx_t */
typedef struct _xmpp_rand_t xmpp_rand_t;
/** Create new xmpp_rand_t object.
*
* @param ctx A Strophe context object
*
* @ingroup Random
*/
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
/** Destroy an xmpp_rand_t object.
*
* @param ctx A Strophe context object
*
* @ingroup Random
*/
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
/** Generate random integer
* Analogue of rand(3).
*
* @ingroup Random
*/
int xmpp_rand(xmpp_rand_t *rand);
/** Generate random bytes.
* Generates len bytes and stores them to the output buffer.
*
* @ingroup Random
*/
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
/** Generate a nonce that is printable randomized string.
* This function doesn't allocate memory and doesn't fail.
*
* @param output A buffer where a NULL-terminated string will be placed.
* The string will contain len-1 printable symbols.
* @param len Number of bytes reserved for the output string, including
* end of line '\0'.
*
* @ingroup Random
*/
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
#endif /* __LIBSTROPHE_RAND_H__ */

767
src/resolver.c Normal file
View File

@@ -0,0 +1,767 @@
/* resolver.h
* strophe XMPP client library -- DNS resolver
*
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* DNS resolver.
*/
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h> /* res_query */
#endif /* _WIN32 */
#include <string.h> /* strncpy */
#include "ostypes.h"
#include "snprintf.h"
#include "util.h" /* xmpp_min */
#include "resolver.h"
#define MESSAGE_HEADER_LEN 12
#define MESSAGE_RESPONSE 1
#define MESSAGE_T_SRV 33
#define MESSAGE_C_IN 1
struct message_header {
uint16_t id;
uint8_t octet2;
uint8_t octet3;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
};
#ifdef _WIN32
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len);
#endif /* _WIN32 */
/* the same as ntohs(), but receives pointer to the value */
static uint16_t xmpp_ntohs_ptr(const void *ptr)
{
const uint8_t *p = (const uint8_t *)ptr;
return (uint16_t)((p[0] << 8U) + p[1]);
}
static uint8_t message_header_qr(const struct message_header *header)
{
return (header->octet2 >> 7) & 1;
}
static uint8_t message_header_rcode(const struct message_header *header)
{
return header->octet3 & 0x0f;
}
/*
* Append a label or a dot to the target name with buffer overflow checks.
* Returns length of the non-truncated resulting string, may be bigger than
* name_max.
*/
static size_t message_name_append_safe(char *name, size_t name_len,
size_t name_max,
const char *tail, size_t tail_len)
{
size_t copy_len;
copy_len = name_max > name_len ? name_max - name_len : 0;
copy_len = xmpp_min(tail_len, copy_len);
if (copy_len > 0)
strncpy(&name[name_len], tail, copy_len);
return name_len + tail_len;
}
/* Returns length of the compressed name. This is NOT the same as strlen(). */
static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
unsigned buf_offset,
char *name, size_t name_max)
{
size_t name_len = 0;
unsigned i = buf_offset;
unsigned pointer;
unsigned rc;
unsigned char label_len;
while (1) {
if (i >= buf_len) return 0;
label_len = buf[i++];
if (label_len == 0) break;
/* Label */
if ((label_len & 0xc0) == 0) {
if (i + label_len - 1 >= buf_len) return 0;
if (name != NULL) {
name_len = message_name_append_safe(name, name_len, name_max,
(char *)&buf[i], label_len);
name_len = message_name_append_safe(name, name_len, name_max,
".", 1);
}
i += label_len;
/* Pointer */
} else if ((label_len & 0xc0) == 0xc0) {
if (i >= buf_len) return 0;
pointer = (label_len & 0x3f) << 8 | buf[i++];
if (name != NULL && name_len >= name_max && name_max > 0) {
/* We have filled the name buffer. Don't pass it recursively. */
name[name_max - 1] = '\0';
name = NULL;
name_max = 0;
}
rc = message_name_get(buf, buf_len, pointer,
name != NULL ? &name[name_len] : NULL,
name_max > name_len ? name_max - name_len : 0);
if (rc == 0) return 0;
/* Pointer is always the last. */
break;
/* The 10 and 01 combinations are reserved for future use. */
} else {
return 0;
}
}
if (label_len == 0) {
if (name_len == 0) name_len = 1;
/*
* At this point name_len is length of the resulting name,
* including '\0'. This value can be exported to allocate buffer
* of precise size.
*/
if (name != NULL && name_max > 0) {
/*
* Overwrite leading '.' with a '\0'. If the resulting name is
* bigger than name_max it is truncated.
*/
name[xmpp_min(name_len, name_max) - 1] = '\0';
}
}
return i - buf_offset;
}
static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
unsigned buf_offset)
{
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
}
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t * rr_head;
resolver_srv_rr_t * rr_current;
resolver_srv_rr_t * rr_next;
resolver_srv_rr_t * rr_prev;
int swap;
rr_head = *srv_rr_list;
if ((rr_head == NULL) || (rr_head->next == NULL)) {
/* Empty or single record list */
return;
}
do {
rr_prev = NULL;
rr_current = rr_head;
rr_next = rr_head->next;
swap = 0;
while (rr_next != NULL) {
/*
* RFC2052: A client MUST attempt to contact the target host
* with the lowest-numbered priority it can reach.
* RFC2052: When selecting a target host among the
* those that have the same priority, the chance of trying
* this one first SHOULD be proportional to its weight.
*/
if ((rr_current->priority > rr_next->priority) ||
(rr_current->priority == rr_next->priority &&
rr_current->weight < rr_next->weight))
{
/* Swap node */
swap = 1;
if (rr_prev != NULL) {
rr_prev->next = rr_next;
} else {
/* Swap head node */
rr_head = rr_next;
}
rr_current->next = rr_next->next;
rr_next->next = rr_current;
rr_prev = rr_next;
rr_next = rr_current->next;
} else {
/* Next node */
rr_prev = rr_current;
rr_current = rr_next;
rr_next = rr_next->next;
}
}
} while (swap != 0);
*srv_rr_list = rr_head;
}
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
if ((ptr) >= (len)) { \
if (*srv_rr_list != NULL) \
resolver_srv_free(ctx, *srv_rr_list); \
*srv_rr_list = NULL; \
return XMPP_DOMAIN_NOT_FOUND; \
} \
} while (0)
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list)
{
unsigned i;
unsigned j;
unsigned name_len;
unsigned rdlength;
uint16_t type;
uint16_t class;
struct message_header header;
resolver_srv_rr_t *rr;
*srv_rr_list = NULL;
if (len < MESSAGE_HEADER_LEN)
return XMPP_DOMAIN_NOT_FOUND;
header.id = xmpp_ntohs_ptr(&buf[0]);
header.octet2 = buf[2];
header.octet3 = buf[3];
header.qdcount = xmpp_ntohs_ptr(&buf[4]);
header.ancount = xmpp_ntohs_ptr(&buf[6]);
header.nscount = xmpp_ntohs_ptr(&buf[8]);
header.arcount = xmpp_ntohs_ptr(&buf[10]);
if (message_header_qr(&header) != MESSAGE_RESPONSE ||
message_header_rcode(&header) != 0)
{
return XMPP_DOMAIN_NOT_FOUND;
}
j = MESSAGE_HEADER_LEN;
/* skip question section */
for (i = 0; i < header.qdcount; ++i) {
BUF_OVERFLOW_CHECK(j, len);
name_len = message_name_len(buf, len, j);
/* error in name format */
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
j += name_len + 4;
}
for (i = 0; i < header.ancount; ++i) {
BUF_OVERFLOW_CHECK(j, len);
name_len = message_name_len(buf, len, j);
/* error in name format */
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
j += name_len;
BUF_OVERFLOW_CHECK(j + 16, len);
type = xmpp_ntohs_ptr(&buf[j]);
class = xmpp_ntohs_ptr(&buf[j + 2]);
rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
j += 10;
if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
rr = xmpp_alloc(ctx, sizeof(*rr));
rr->next = *srv_rr_list;
rr->priority = xmpp_ntohs_ptr(&buf[j]);
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
name_len = message_name_get(buf, len, j + 6, rr->target,
sizeof(rr->target));
if (name_len > 0)
*srv_rr_list = rr;
else
xmpp_free(ctx, rr); /* skip broken record */
}
j += rdlength;
}
resolver_srv_list_sort(srv_rr_list);
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
}
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list)
{
char fulldomain[2048];
unsigned char buf[65535];
int len;
int set = XMPP_DOMAIN_NOT_FOUND;
xmpp_snprintf(fulldomain, sizeof(fulldomain),
"_%s._%s.%s", service, proto, domain);
*srv_rr_list = NULL;
#ifdef _WIN32
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
if (set == XMPP_DOMAIN_FOUND)
return set;
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
#else /* _WIN32 */
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
#endif /* _WIN32 */
if (len > 0)
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
return set;
}
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
{
resolver_srv_rr_t *rr;
while (srv_rr_list != NULL) {
rr = srv_rr_list->next;
xmpp_free(ctx, srv_rr_list);
srv_rr_list = rr;
}
}
#ifdef _WIN32
/*******************************************************************************
* Next part was copied from sock.c and contains old win32 code.
*
* The idea is to get raw response from a name server and pass it to
* resolver_srv_lookup_buf(). In fact, resolver_win32_srv_query() replaces
* the call of res_query().
* Dnsapi code is moved to a separated function resolver_srv_win32_lookup() and
* changed to meet new API.
*
* XXX If the code is compiled it should work like before.
******************************************************************************/
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windns.h>
#include <Iphlpapi.h>
struct dnsquery_header
{
unsigned short id;
unsigned char qr;
unsigned char opcode;
unsigned char aa;
unsigned char tc;
unsigned char rd;
unsigned char ra;
unsigned char z;
unsigned char rcode;
unsigned short qdcount;
unsigned short ancount;
unsigned short nscount;
unsigned short arcount;
};
struct dnsquery_question
{
char qname[1024];
unsigned short qtype;
unsigned short qclass;
};
static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
/* assuming big endian */
*p++ = (num >> 8) & 0xff;
*p++ = (num) & 0xff;
*offset += 2;
}
static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
char *name)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
unsigned char *wordstart, *wordend;
wordstart = (unsigned char *)name;
while (*wordstart)
{
int len;
wordend = wordstart;
while (*wordend && *wordend != '.')
{
wordend++;
}
len = (int)(wordend - wordstart);
if (len > 0x3F)
{
len = 0x3F;
}
*p++ = len;
while (wordstart != wordend)
{
*p++ = *wordstart++;
}
if (*wordstart == '.')
{
wordstart++;
}
}
*p++ = '\0';
*offset += (int)(p - start);
}
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
{
unsigned char *p;
netbuf_add_16bitnum(buf, buflen, offset, header->id);
p = buf + *offset;
*p++ = ((header->qr & 0x01) << 7)
| ((header->opcode & 0x0F) << 3)
| ((header->aa & 0x01) << 2)
| ((header->tc & 0x01) << 1)
| ((header->rd & 0x01));
*p++ = ((header->ra & 0x01) << 7)
| ((header->z & 0x07) << 4)
| ((header->rcode & 0x0F));
*offset += 2;
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
}
static void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
{
netbuf_add_domain_name(buf, buflen, offset, question->qname);
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
}
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t *rr;
HINSTANCE hdnsapi = NULL;
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
if (pDnsQuery_A && pDnsRecordListFree) {
PDNS_RECORD dnsrecords = NULL;
DNS_STATUS error;
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
if (error == 0) {
PDNS_RECORD current = dnsrecords;
while (current) {
if (current->wType == DNS_TYPE_SRV) {
rr = xmpp_alloc(ctx, sizeof(*rr));
if (rr == NULL)
break;
rr->next = *srv_rr_list;
rr->port = current->Data.Srv.wPort;
rr->priority = current->Data.Srv.wPriority;
rr->weight = current->Data.Srv.wWeight;
xmpp_snprintf(rr->target, sizeof(rr->target), "%s",
current->Data.Srv.pNameTarget);
*srv_rr_list = rr;
}
current = current->pNext;
}
}
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
}
FreeLibrary(hdnsapi);
}
resolver_srv_list_sort(srv_rr_list);
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
}
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len)
{
int set = 0;
int insize = 0;
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
if (!set)
{
struct dnsquery_header header;
struct dnsquery_question question;
int offset = 0;
int addrlen;
sock_t sock;
struct sockaddr_in dnsaddr;
char dnsserverips[16][256];
int numdnsservers = 0;
int j;
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
if (!numdnsservers)
{
HINSTANCE hiphlpapi = NULL;
DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
{
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
if (pGetNetworkParams)
{
FIXED_INFO *fi;
ULONG len;
DWORD error;
char buffer[65535];
len = 65535;
fi = (FIXED_INFO *)buffer;
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
{
IP_ADDR_STRING *pias = &(fi->DnsServerList);
while (pias && numdnsservers < 16)
{
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
pias = pias->Next;
}
}
}
}
FreeLibrary(hiphlpapi);
}
/* Next, try getting the DNS server ips from the registry */
if (!numdnsservers)
{
HKEY search;
LONG error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
if (error != ERROR_SUCCESS)
{
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
}
if (error == ERROR_SUCCESS)
{
char name[512];
DWORD len = 512;
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
if (error != ERROR_SUCCESS)
{
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
}
if (error == ERROR_SUCCESS)
{
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
while (*end && !strchr(parse, *end))
{
end++;
}
start = end;
}
}
}
RegCloseKey(search);
}
if (!numdnsservers)
{
HKEY searchlist;
LONG error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
if (error == ERROR_SUCCESS)
{
unsigned int i;
DWORD numinterfaces = 0;
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
for (i = 0; i < numinterfaces; i++)
{
char name[512];
DWORD len = 512;
HKEY searchentry;
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
{
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
{
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
while (*end && !strchr(parse, *end))
{
end++;
}
start = end;
}
}
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
{
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
while (*end && !strchr(parse, *end))
{
end++;
}
start = end;
}
}
RegCloseKey(searchentry);
}
}
RegCloseKey(searchlist);
}
}
/* If we have a DNS server, use it */
if (numdnsservers)
{
ULONG nonblocking = 1;
int i;
memset(&header, 0, sizeof(header));
header.id = 12345; /* FIXME: Get a better id here */
header.rd = 1;
header.qdcount = 1;
netbuf_add_dnsquery_header(buf, (int)len, &offset, &header);
memset(&question, 0, sizeof(question));
strncpy(question.qname, fulldomain, 1024);
question.qtype = 33; /* SRV */
question.qclass = 1; /* INTERNET! */
netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
insize = 0;
for (i = 0; i < numdnsservers && insize <= 0; i++)
{
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ioctlsocket(sock, FIONBIO, &nonblocking);
memset(&dnsaddr, 0, sizeof(dnsaddr));
dnsaddr.sin_family = AF_INET;
dnsaddr.sin_port = htons(53);
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
addrlen = sizeof(dnsaddr);
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
for (j = 0; j < 50; j++)
{
insize = recvfrom(sock, (char *)buf, (int)len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
if (insize == SOCKET_ERROR)
{
if (sock_error() == WSAEWOULDBLOCK)
{
Sleep(100);
}
else
{
break;
}
}
else
{
break;
}
}
closesocket(sock);
}
set = insize > 0;
}
}
return set ? insize : -1;
}
#endif /* _WIN32 */

69
src/resolver.h Normal file
View File

@@ -0,0 +1,69 @@
/* resolver.h
* strophe XMPP client library -- DNS resolver
*
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* DNS resolver.
*/
#ifndef __LIBSTROPHE_RESOLVER_H__
#define __LIBSTROPHE_RESOLVER_H__
#include "ostypes.h"
#include "common.h"
typedef enum {
XMPP_DOMAIN_NOT_FOUND,
XMPP_DOMAIN_FOUND,
XMPP_DOMAIN_ALTDOMAIN
} xmpp_domain_state_t;
typedef struct resolver_srv_rr_struc {
uint16_t priority;
uint16_t weight;
uint16_t port;
char target[MAX_DOMAIN_LEN];
struct resolver_srv_rr_struc *next;
} resolver_srv_rr_t;
/** Perform lookup for RFC1035 message format.
* This function allocates all elements.
*
* @param ctx a Strophe context object
* @param buf message in RFC1035 format
* @param len length of the message
* @param srv_rr_list is the result
*
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
*/
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list);
/** Resolve SRV record.
*
* @param ctx a Strophe context object
* @param service service of the SRV record
* @param proto protocol of the SRV record
* @param domain resolving domain
* @param srv_rr_list is the result
*
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
*/
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list);
/** Release a list returned by resolver_srv_lookup() or
* resolver_srv_lookup_buf().
*
* @param ctx a Strophe context object
* @param srv_rr_list a list allocated by lookup functions
*/
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list);
#endif /* __LIBSTROPHE_RESOLVER_H__ */

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -26,15 +23,24 @@
#include "md5.h"
#include "sha1.h"
#include "scram.h"
#include "rand.h"
#include "util.h"
#ifdef _WIN32
#define strtok_r strtok_s
#endif
/* strtok_s() has appeared in visual studio 2005.
Use own implementation for older versions. */
#ifdef _MSC_VER
# if (_MSC_VER >= 1400)
# define strtok_r strtok_s
# else
# define strtok_r xmpp_strtok_r
# endif
#endif /* _MSC_VER */
/** generate authentication string for the SASL PLAIN mechanism */
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
int idlen, passlen;
size_t idlen, passlen;
size_t msglen;
char *result = NULL;
char *msg;
@@ -43,13 +49,14 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
idlen = strlen(authid);
passlen = strlen(password);
msg = xmpp_alloc(ctx, 2 + idlen + passlen);
msglen = 2 + idlen + passlen;
msg = xmpp_alloc(ctx, msglen);
if (msg != NULL) {
msg[0] = '\0';
memcpy(msg+1, authid, idlen);
msg[1+idlen] = '\0';
memcpy(msg+1+idlen+1, password, passlen);
result = base64_encode(ctx, (unsigned char *)msg, 2 + idlen + passlen);
result = xmpp_base64_encode(ctx, (unsigned char *)msg, msglen);
xmpp_free(ctx, msg);
}
@@ -75,7 +82,7 @@ static char *_make_string(xmpp_ctx_t *ctx, const char *s, const unsigned len)
static char *_make_quoted(xmpp_ctx_t *ctx, const char *s)
{
char *result;
int len = strlen(s);
size_t len = strlen(s);
result = xmpp_alloc(ctx, len + 3);
if (result != NULL) {
@@ -95,7 +102,7 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
char *key, *value;
unsigned char *s, *t;
text = base64_decode(ctx, msg, strlen(msg));
text = (unsigned char *)xmpp_base64_decode_str(ctx, msg, strlen(msg));
if (text == NULL) {
xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!");
return NULL;
@@ -221,6 +228,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
struct MD5Context MD5;
unsigned char digest[16], HA1[16], HA2[16];
char hex[32];
char cnonce[13];
/* our digest response is
Hex( KD( HEX(MD5(A1)),
@@ -253,10 +261,11 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
/* add our response fields */
hash_add(table, "username", xmpp_strdup(ctx, node));
/* TODO: generate a random cnonce */
hash_add(table, "cnonce", xmpp_strdup(ctx, "00DEADBEEF00"));
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
if (hash_get(table, "qop") == NULL)
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
memcpy(value, "xmpp/", 5);
memcpy(value+5, domain, strlen(domain));
@@ -347,7 +356,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
hash_release(table); /* also frees value strings */
/* reuse response for the base64 encode of our result */
response = base64_encode(ctx, (unsigned char *)result, strlen(result));
response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result));
xmpp_free(ctx, result);
return response;
@@ -363,7 +372,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
char *r = NULL;
char *s = NULL;
char *i = NULL;
char *sval;
unsigned char *sval;
size_t sval_len;
long ival;
char *tmp;
@@ -399,11 +408,10 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
goto out;
}
sval = (char *)base64_decode(ctx, s, strlen(s));
xmpp_base64_decode_bin(ctx, s, strlen(s), &sval, &sval_len);
if (!sval) {
goto out;
}
sval_len = base64_decoded_len(ctx, s, strlen(s));
ival = strtol(i, &saveptr, 10);
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
@@ -429,7 +437,7 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
sign[j] ^= key[j];
}
sign_b64 = base64_encode(ctx, sign, sizeof(sign));
sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
if (!sign_b64) {
goto out_response;
}
@@ -442,8 +450,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
strcat(response, sign_b64);
xmpp_free(ctx, sign_b64);
response_b64 = base64_encode(ctx, (unsigned char *)response,
strlen(response));
response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
strlen(response));
if (!response_b64) {
goto out_response;
}
@@ -459,257 +467,3 @@ out:
xmpp_free(ctx, tmp);
return result;
}
/** Base64 encoding routines. Implemented according to RFC 3548 */
/** map of all byte values to the base64 values, or to
'65' which indicates an invalid character. '=' is '64' */
static const char _base64_invcharmap[256] = {
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63,
52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65
};
/** map of all 6-bit values to their corresponding byte
in the base64 alphabet. Padding char is the value '64' */
static const char _base64_charmap[65] = {
'A','B','C','D', 'E','F','G','H',
'I','J','K','L', 'M','N','O','P',
'Q','R','S','T', 'U','V','W','X',
'Y','Z','a','b', 'c','d','e','f',
'g','h','i','j', 'k','l','m','n',
'o','p','q','r', 's','t','u','v',
'w','x','y','z', '0','1','2','3',
'4','5','6','7', '8','9','+','/',
'='
};
int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len)
{
/* encoded steam is 4 bytes for every three, rounded up */
return ((len + 2)/3) << 2;
}
char *base64_encode(xmpp_ctx_t *ctx,
const unsigned char * const buffer, const unsigned len)
{
int clen;
char *cbuf, *c;
uint32_t word, hextet;
int i;
clen = base64_encoded_len(ctx, len);
cbuf = xmpp_alloc(ctx, clen + 1);
if (cbuf != NULL) {
c = cbuf;
/* loop over data, turning every 3 bytes into 4 characters */
for (i = 0; i < len - 2; i += 3) {
word = buffer[i] << 16 | buffer[i+1] << 8 | buffer[i+2];
hextet = (word & 0x00FC0000) >> 18;
*c++ = _base64_charmap[hextet];
hextet = (word & 0x0003F000) >> 12;
*c++ = _base64_charmap[hextet];
hextet = (word & 0x00000FC0) >> 6;
*c++ = _base64_charmap[hextet];
hextet = (word & 0x000003F);
*c++ = _base64_charmap[hextet];
}
/* zero, one or two bytes left */
switch (len - i) {
case 0:
break;
case 1:
hextet = (buffer[len-1] & 0xFC) >> 2;
*c++ = _base64_charmap[hextet];
hextet = (buffer[len-1] & 0x03) << 4;
*c++ = _base64_charmap[hextet];
*c++ = _base64_charmap[64]; /* pad */
*c++ = _base64_charmap[64]; /* pad */
break;
case 2:
hextet = (buffer[len-2] & 0xFC) >> 2;
*c++ = _base64_charmap[hextet];
hextet = ((buffer[len-2] & 0x03) << 4) |
((buffer[len-1] & 0xF0) >> 4);
*c++ = _base64_charmap[hextet];
hextet = (buffer[len-1] & 0x0F) << 2;
*c++ = _base64_charmap[hextet];
*c++ = _base64_charmap[64]; /* pad */
break;
}
/* add a terminal null */
*c = '\0';
}
return cbuf;
}
int base64_decoded_len(xmpp_ctx_t *ctx,
const char * const buffer, const unsigned len)
{
int nudge;
int c;
/* count the padding characters for the remainder */
nudge = -1;
c = _base64_invcharmap[(int)buffer[len-1]];
if (c < 64) nudge = 0;
else if (c == 64) {
c = _base64_invcharmap[(int)buffer[len-2]];
if (c < 64) nudge = 1;
else if (c == 64) {
c = _base64_invcharmap[(int)buffer[len-3]];
if (c < 64) nudge = 2;
}
}
if (nudge < 0) return 0; /* reject bad coding */
/* decoded steam is 3 bytes for every four */
return 3 * (len >> 2) - nudge;
}
unsigned char *base64_decode(xmpp_ctx_t *ctx,
const char * const buffer, const unsigned len)
{
int dlen;
unsigned char *dbuf, *d;
uint32_t word, hextet;
int i;
/* len must be a multiple of 4 */
if (len & 0x03) return NULL;
dlen = base64_decoded_len(ctx, buffer, len);
dbuf = xmpp_alloc(ctx, dlen + 1);
if (dbuf != NULL) {
d = dbuf;
/* loop over each set of 4 characters, decoding 3 bytes */
for (i = 0; i < len - 3; i += 4) {
hextet = _base64_invcharmap[(int)buffer[i]];
if (hextet & 0xC0) break;
word = hextet << 18;
hextet = _base64_invcharmap[(int)buffer[i+1]];
if (hextet & 0xC0) break;
word |= hextet << 12;
hextet = _base64_invcharmap[(int)buffer[i+2]];
if (hextet & 0xC0) break;
word |= hextet << 6;
hextet = _base64_invcharmap[(int)buffer[i+3]];
if (hextet & 0xC0) break;
word |= hextet;
*d++ = (word & 0x00FF0000) >> 16;
*d++ = (word & 0x0000FF00) >> 8;
*d++ = (word & 0x000000FF);
}
if (hextet > 64) goto _base64_decode_error;
/* handle the remainder */
switch (dlen % 3) {
case 0:
/* nothing to do */
break;
case 1:
/* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(int)buffer[len-4]];
if (hextet & 0xC0) goto _base64_decode_error;
word = hextet << 2;
hextet = _base64_invcharmap[(int)buffer[len-3]];
if (hextet & 0xC0) goto _base64_decode_error;
word |= hextet >> 4;
*d++ = word & 0xFF;
hextet = _base64_invcharmap[(int)buffer[len-2]];
if (hextet != 64) goto _base64_decode_error;
hextet = _base64_invcharmap[(int)buffer[len-1]];
if (hextet != 64) goto _base64_decode_error;
break;
case 2:
/* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(int)buffer[len-4]];
if (hextet & 0xC0) goto _base64_decode_error;
word = hextet << 10;
hextet = _base64_invcharmap[(int)buffer[len-3]];
if (hextet & 0xC0) goto _base64_decode_error;
word |= hextet << 4;
hextet = _base64_invcharmap[(int)buffer[len-2]];
if (hextet & 0xC0) goto _base64_decode_error;
word |= hextet >> 2;
*d++ = (word & 0xFF00) >> 8;
*d++ = (word & 0x00FF);
hextet = _base64_invcharmap[(int)buffer[len-1]];
if (hextet != 64) goto _base64_decode_error;
break;
}
*d = '\0';
}
return dbuf;
_base64_decode_error:
/* invalid character; abort decoding! */
xmpp_free(ctx, dbuf);
return NULL;
}
/*** self tests ***/
#ifdef TEST
#include <stdio.h>
int test_charmap_identity(void)
{
int i, v, u;
for (i = 0; i < 65; i++) {
v = _base64_charmap[i];
if (v > 255) return 1;
u = _base64_invcharmap[v];
/* printf("map: %d -> %d -> %d\n", i, v, u); */
if (u != i) return 1;
}
return 0;
}
int test_charmap_range(void)
{
int i, v;
for (i = 64; i < 256; i++) {
v = _base64_invcharmap[i];
if (i < 64) return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
int ret = 0;
printf("testing charmap identity...");
ret = test_charmap_identity();
if (ret) return ret;
printf(" ok.\n");
printf("testing charmap range...");
ret = test_charmap_range();
if (ret) return ret;
printf(" ok.\n");
printf("no error\n");
return 0;
}
#endif /* TEST */

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -30,18 +27,4 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
const char *first_bare, const char *jid,
const char *password);
/** Base64 encoding routines. Implemented according to RFC 3548 */
int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len);
char *base64_encode(xmpp_ctx_t *ctx,
const unsigned char * const buffer, const unsigned len);
int base64_decoded_len(xmpp_ctx_t *ctx,
const char * const buffer, const unsigned len);
unsigned char *base64_decode(xmpp_ctx_t *ctx,
const char * const buffer, const unsigned len);
#endif /* _LIBXMPP_SASL_H__ */

View File

@@ -9,10 +9,7 @@
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This software is distributed under license and may not be copied,
* modified or distributed except as expressly authorized under the
* terms of the license contained in the file LICENSE.txt in this
* distribution.
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -27,64 +24,52 @@
#include "scram.h"
/* block size for HMAC */
#define BLOCK_SIZE 64
#if BLOCK_SIZE < SHA1_DIGEST_SIZE
#error BLOCK_SIZE must not be less than SHA1_DIGEST_SIZE
#endif
#define HMAC_BLOCK_SIZE 64
static const uint8_t ipad = 0x36;
static const uint8_t opad = 0x5C;
static void SHA1(const uint8_t* data, size_t len,
uint8_t digest[SHA1_DIGEST_SIZE])
static void crypto_HMAC_SHA1(const uint8_t *key, size_t key_len,
const uint8_t *text, size_t len,
uint8_t *digest)
{
SHA1_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, data, len);
SHA1_Final(&ctx, digest);
}
static void HMAC_SHA1(const uint8_t *key, size_t key_len,
const uint8_t *text, size_t len,
uint8_t digest[SHA1_DIGEST_SIZE])
{
uint8_t key_pad[BLOCK_SIZE];
uint8_t key_ipad[BLOCK_SIZE];
uint8_t key_opad[BLOCK_SIZE];
uint8_t key_pad[HMAC_BLOCK_SIZE];
uint8_t key_ipad[HMAC_BLOCK_SIZE];
uint8_t key_opad[HMAC_BLOCK_SIZE];
uint8_t sha_digest[SHA1_DIGEST_SIZE];
int i;
SHA1_CTX ctx;
memset(key_pad, 0, sizeof(key_pad));
if (key_len <= BLOCK_SIZE) {
if (key_len <= HMAC_BLOCK_SIZE) {
memcpy(key_pad, key, key_len);
} else {
/* according to RFC2104 */
SHA1(key, key_len, key_pad);
crypto_SHA1(key, key_len, key_pad);
}
for (i = 0; i < BLOCK_SIZE; i++) {
for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
key_ipad[i] = key_pad[i] ^ ipad;
key_opad[i] = key_pad[i] ^ opad;
}
SHA1_Init(&ctx);
SHA1_Update(&ctx, key_ipad, BLOCK_SIZE);
SHA1_Update(&ctx, text, len);
SHA1_Final(&ctx, sha_digest);
crypto_SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, key_ipad, HMAC_BLOCK_SIZE);
crypto_SHA1_Update(&ctx, text, len);
crypto_SHA1_Final(&ctx, sha_digest);
SHA1_Init(&ctx);
SHA1_Update(&ctx, key_opad, BLOCK_SIZE);
SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
SHA1_Final(&ctx, digest);
crypto_SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, key_opad, HMAC_BLOCK_SIZE);
crypto_SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
crypto_SHA1_Final(&ctx, digest);
}
static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i,
uint8_t digest[SHA1_DIGEST_SIZE])
uint8_t *digest)
{
int j, k;
int k;
uint32_t j;
uint8_t tmp[128];
static uint8_t int1[] = {0x0, 0x0, 0x0, 0x1};
@@ -101,11 +86,11 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
memcpy(&tmp[salt_len], int1, sizeof(int1));
/* 'text' for Hi is a 'key' for HMAC */
HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
crypto_HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
memcpy(tmp, digest, SHA1_DIGEST_SIZE);
for (j = 1; j < i; j++) {
HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
crypto_HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
digest[k] ^= tmp[k];
}
@@ -114,30 +99,30 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i,
uint8_t key[SHA1_DIGEST_SIZE])
uint8_t *key)
{
uint8_t salted[SHA1_DIGEST_SIZE];
/* XXX: Normalize(password) is omitted */
SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
strlen("Client Key"), key);
crypto_HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
strlen("Client Key"), key);
}
void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
const uint8_t *AuthMessage, size_t len,
uint8_t sign[SHA1_DIGEST_SIZE])
uint8_t *sign)
{
uint8_t stored[SHA1_DIGEST_SIZE];
SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
crypto_SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
crypto_HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
}
void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
uint8_t proof[SHA1_DIGEST_SIZE])
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
const uint8_t *ClientSignature,
uint8_t *proof)
{
int i;
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {

View File

@@ -6,10 +6,7 @@
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This software is distributed under license and may not be copied,
* modified or distributed except as expressly authorized under the
* terms of the license contained in the file LICENSE.txt in this
* distribution.
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -26,14 +23,14 @@
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i,
uint8_t key[SHA1_DIGEST_SIZE]);
uint8_t *key);
void SCRAM_SHA1_ClientSignature(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
const uint8_t *AuthMessage, size_t len,
uint8_t sign[SHA1_DIGEST_SIZE]);
uint8_t *sign);
void SCRAM_SHA1_ClientProof(const uint8_t ClientKey[SHA1_DIGEST_SIZE],
const uint8_t ClientSignature[SHA1_DIGEST_SIZE],
uint8_t proof[SHA1_DIGEST_SIZE]);
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
const uint8_t *ClientSignature,
uint8_t *proof);
#endif /* __LIBSTROPHE_SCRAM_H__ */

View File

@@ -70,39 +70,22 @@ use SHA1_ prefix for public api
move public api to sha1.h
*/
/*
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define SHA1HANDSOFF */
#include <stdio.h>
#include <string.h>
/* make sure the stdint.h types are available */
#include "ostypes.h"
#include "sha1.h"
/* Don't change user's data */
#define SHA1HANDSOFF
static uint32_t host_to_be(uint32_t i);
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
/* FIXME: can we do this in an endian-proof way? */
#ifdef WORDS_BIGENDIAN
#define blk0(i) block->l[i]
#else
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#endif
#define blk0(i) (block->l[i] = host_to_be(block->l[i]))
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
@@ -114,18 +97,26 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
#ifdef VERBOSE /* SAK */
void SHAPrintContext(SHA1_CTX *context, char *msg){
printf("%s (%d,%d) %x %x %x %x %x\n",
msg,
context->count[0], context->count[1],
context->state[0],
context->state[1],
context->state[2],
context->state[3],
context->state[4]);
static uint32_t host_to_be(uint32_t i)
{
#define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF))
#if defined(__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return i;
#elif defined(__LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
return le_to_be(i);
#else /* fallback to run-time check */
static const union {
uint32_t u;
unsigned char c;
} check = {1};
return check.c ? le_to_be(i) : i;
#endif
#undef le_to_be
}
#endif /* VERBOSE */
/* Hash a single 512-bit block. This is the core of the algorithm. */
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
@@ -187,7 +178,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
/* SHA1Init - Initialize new context */
void SHA1_Init(SHA1_CTX* context)
void crypto_SHA1_Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
@@ -200,14 +191,11 @@ void SHA1_Init(SHA1_CTX* context)
/* Run your data through this. */
void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
const size_t len)
{
size_t i, j;
#ifdef VERBOSE
SHAPrintContext(context, "before");
#endif
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29);
@@ -221,15 +209,11 @@ void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
#ifdef VERBOSE
SHAPrintContext(context, "after ");
#endif
}
/* Add padding and return the message digest. */
void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
{
uint32_t i;
uint8_t finalcount[8];
@@ -238,11 +222,11 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1_Update(context, (uint8_t *)"\200", 1);
crypto_SHA1_Update(context, (uint8_t *)"\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1_Update(context, (uint8_t *)"\0", 1);
crypto_SHA1_Update(context, (uint8_t *)"\0", 1);
}
SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
crypto_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
digest[i] = (uint8_t)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
@@ -259,119 +243,12 @@ void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
SHA1_Transform(context->state, context->buffer);
#endif
}
/*************************************************************/
#if 0
int main(int argc, char** argv)
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest)
{
int i, j;
SHA1_CTX context;
unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384];
FILE* file;
if (argc > 2) {
puts("Public domain SHA-1 implementation - by Steve Reid <sreid@sea-to-sky.net>");
puts("Modified for 16 bit environments 7/98 - by James H. Brown <jbrown@burgoyne.com>"); /* JHB */
puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
return(0);
}
if (argc < 2) {
file = stdin;
}
else {
if (!(file = fopen(argv[1], "rb"))) {
fputs("Unable to open file.", stderr);
return(-1);
}
}
SHA1_Init(&context);
while (!feof(file)) { /* note: what if ferror(file) */
i = fread(buffer, 1, 16384, file);
SHA1_Update(&context, buffer, i);
}
SHA1_Final(&context, digest);
fclose(file);
for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
for (j = 0; j < 4; j++) {
printf("%02X", digest[i*4+j]);
}
putchar(' ');
}
putchar('\n');
return(0); /* JHB */
SHA1_CTX ctx;
crypto_SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, data, len);
crypto_SHA1_Final(&ctx, digest);
}
#endif
/* self test */
#ifdef TEST
static char *test_data[] = {
"abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"A million repetitions of 'a'"};
static char *test_results[] = {
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"};
void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output)
{
int i,j;
char *c = output;
for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
for (j = 0; j < 4; j++) {
sprintf(c,"%02X", digest[i*4+j]);
c += 2;
}
sprintf(c, " ");
c += 1;
}
*(c - 1) = '\0';
}
int main(int argc, char** argv)
{
int k;
SHA1_CTX context;
uint8_t digest[20];
char output[80];
fprintf(stdout, "verifying SHA-1 implementation... ");
for (k = 0; k < 2; k++){
SHA1_Init(&context);
SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k]));
SHA1_Final(&context, digest);
digest_to_hex(digest, output);
if (strcmp(output, test_results[k])) {
fprintf(stdout, "FAIL\n");
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
fprintf(stderr,"\t%s returned\n", output);
fprintf(stderr,"\t%s is correct\n", test_results[k]);
return (1);
}
}
/* million 'a' vector we feed separately */
SHA1_Init(&context);
for (k = 0; k < 1000000; k++)
SHA1_Update(&context, (uint8_t*)"a", 1);
SHA1_Final(&context, digest);
digest_to_hex(digest, output);
if (strcmp(output, test_results[2])) {
fprintf(stdout, "FAIL\n");
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
fprintf(stderr,"\t%s returned\n", output);
fprintf(stderr,"\t%s is correct\n", test_results[2]);
return (1);
}
/* success */
fprintf(stdout, "ok\n");
return(0);
}
#endif /* TEST */

View File

@@ -5,8 +5,8 @@
* SHA-1 hash API.
*/
#ifndef __SHA1_H
#define __SHA1_H
#ifndef __LIBSTROPHE_SHA1_H__
#define __LIBSTROPHE_SHA1_H__
#ifdef __cplusplus
extern "C" {
@@ -23,12 +23,14 @@ typedef struct {
#define SHA1_DIGEST_SIZE 20
void SHA1_Init(SHA1_CTX* context);
void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);
void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);
void crypto_SHA1_Init(SHA1_CTX* context);
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
const size_t len);
void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest);
void crypto_SHA1(const uint8_t* data, size_t len, uint8_t* digest);
#ifdef __cplusplus
}
#endif
#endif /* __SHA1_H */
#endif /* __LIBSTROPHE_SHA1_H__ */

View File

@@ -64,49 +64,27 @@
/* JAM: changed declarations to xmpp_snprintf and xmpp_vsnprintf to
avoid namespace collision. */
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
#include "snprintf.h"
/* varargs declarations: */
#include <stdarg.h>
#define VA_LOCAL_DECL va_list ap
#define VA_START(f) va_start(ap, f)
#define VA_END va_end(ap)
#ifndef HAVE_VSNPRINTF
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
/* Define this as a fall through, HAVE_STDARG_H is probably already set */
#define HAVE_VARARGS_H
#define HAVE_STDARG_H /* JAM: set always */
/* varargs declarations: */
#if defined(HAVE_STDARG_H)
# include <stdarg.h>
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
# define VA_LOCAL_DECL va_list ap
# define VA_START(f) va_start(ap, f)
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
# define VA_END va_end(ap)
#else
# if defined(HAVE_VARARGS_H)
# include <varargs.h>
# undef HAVE_STDARGS
# define VA_LOCAL_DECL va_list ap
# define VA_START(f) va_start(ap) /* f is ignored! */
# define VA_SHIFT(v,t) v = va_arg(ap,t)
# define VA_END va_end(ap)
# else
/*XX ** NO VARARGS ** XX*/
# endif
#endif
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...);
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
static int dopr (char *buffer, size_t maxlen, const char *format,
va_list args);
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
@@ -308,6 +286,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break;
case 'X':
flags |= DP_F_UP;
//-fallthrough
case 'x':
flags |= DP_F_UNSIGNED;
if (cflags == DP_C_SHORT)
@@ -328,6 +307,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break;
case 'E':
flags |= DP_F_UP;
//-fallthrough
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
@@ -336,6 +316,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break;
case 'G':
flags |= DP_F_UP;
//-fallthrough
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, LDOUBLE);
@@ -397,7 +378,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break; /* some picky compilers need this */
}
}
if (buffer != NULL)
if (buffer != NULL && maxlen > 0)
{
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
@@ -725,10 +706,9 @@ static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
return 1;
}
#ifndef HAVE_VSNPRINTF
int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
if (str != NULL)
if (str != NULL && count > 0)
str[0] = 0;
return dopr(str, count, fmt, args);
}
@@ -736,104 +716,14 @@ int xmpp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
#ifndef HAVE_SNPRINTF
/* VARARGS3 */
#ifdef HAVE_STDARGS
int xmpp_snprintf (char *str,size_t count,const char *fmt,...)
#else
int xmpp_snprintf (va_alist) va_dcl
#endif
{
#ifndef HAVE_STDARGS
char *str;
size_t count;
char *fmt;
#endif
VA_LOCAL_DECL;
int total;
VA_START (fmt);
VA_SHIFT (str, char *);
VA_SHIFT (count, size_t );
VA_SHIFT (fmt, char *);
total = xmpp_vsnprintf(str, count, fmt, ap);
VA_END;
return total;
}
#endif /* !HAVE_SNPRINTF */
#ifdef TEST_SNPRINTF
#ifndef LONG_STRING
#define LONG_STRING 1024
#endif
int main (void)
{
char buf1[LONG_STRING];
char buf2[LONG_STRING];
char *fp_fmt[] = {
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%.1f",
NULL
};
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
NULL
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
int x, y;
int fail = 0;
int num = 0;
printf ("Testing xmpp_snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] != NULL ; x++)
for (y = 0; fp_nums[y] != 0 ; y++)
{
xmpp_snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
sprintf (buf2, fp_fmt[x], fp_nums[y]);
if (strcmp (buf1, buf2))
{
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
fp_fmt[x], buf1, buf2);
fail++;
}
num++;
}
for (x = 0; int_fmt[x] != NULL ; x++)
for (y = 0; int_nums[y] != 0 ; y++)
{
xmpp_snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
sprintf (buf2, int_fmt[x], int_nums[y]);
if (strcmp (buf1, buf2))
{
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
int_fmt[x], buf1, buf2);
fail++;
}
num++;
}
printf ("%d tests failed out of %d.\n", fail, num);
}
#endif /* SNPRINTF_TEST */
#endif /* !HAVE_SNPRINTF */

34
src/snprintf.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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
*/
/** @file
* Compatibility wrappers for OSes lacking snprintf(3) and/or vsnprintf(3).
*/
#ifndef __LIBSTROPHE_SNPRINTF_H__
#define __LIBSTROPHE_SNPRINTF_H__
#include <stddef.h>
#include <stdarg.h>
#if defined(HAVE_SNPRINTF) || defined(HAVE_VSNPRINTF)
#include <stdio.h>
#endif
#ifdef HAVE_SNPRINTF
#define xmpp_snprintf snprintf
#else
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...);
#endif
#ifdef HAVE_VSNPRINTF
#define xmpp_vsnprintf vsnprintf
#else
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg);
#endif
#endif /* __LIBSTROPHE_SNPRINTF_H__ */

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -24,24 +21,20 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windns.h>
#include <Iphlpapi.h>
#define snprintf _snprintf
#include <Mstcpip.h> /* tcp_keepalive */
#else
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/nameser.h>
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
#endif
#include <resolv.h>
#endif
#include "sock.h"
#include "snprintf.h"
void sock_initialize(void)
{
@@ -72,49 +65,90 @@ static int _in_progress(int error)
#ifdef _WIN32
return (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS);
#else
return (errno == EINPROGRESS);
return (error == EINPROGRESS);
#endif
}
sock_t sock_connect(const char * const host, const unsigned int port)
sock_t sock_connect(const char * const host, const unsigned short port)
{
sock_t sock;
char service[6];
struct addrinfo *res, *ainfo, hints;
int err;
sock = -1;
snprintf(service, 6, "%u", port);
xmpp_snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_family = AF_UNSPEC;
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif /* AI_ADDRCONFIG */
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(host, service, &hints, &res)) != 0)
return -1;
err = getaddrinfo(host, service, &hints, &res);
if (err != 0)
return -1;
ainfo = res;
while (ainfo) {
if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype,
ainfo->ai_protocol)) >= 0) {
sock_set_nonblocking(sock);
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock < 0)
continue;
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
if ((err == 0) || (err < 0 && _in_progress(sock_error())))
break;
}
ainfo = ainfo->ai_next;
err = sock_set_nonblocking(sock);
if (err == 0) {
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
if (err == 0 || _in_progress(sock_error()))
break;
}
sock_close(sock);
}
if (res) freeaddrinfo(res);
freeaddrinfo(res);
sock = ainfo == NULL ? -1 : sock;
return sock;
}
int sock_set_keepalive(const sock_t sock, int timeout, int interval)
{
int ret;
int optval = (timeout && interval) ? 1 : 0;
/* This function doesn't change maximum number of keepalive probes */
#ifdef _WIN32
struct tcp_keepalive ka;
DWORD dw = 0;
ka.onoff = optval;
ka.keepalivetime = timeout * 1000;
ka.keepaliveinterval = interval * 1000;
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw, NULL, NULL);
#else
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
if (ret < 0)
return ret;
if (optval) {
#ifdef TCP_KEEPIDLE
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout));
#elif defined(TCP_KEEPALIVE)
/* QNX receives `struct timeval' as argument, but it seems OSX does int */
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout, sizeof(timeout));
#endif /* TCP_KEEPIDLE */
if (ret < 0)
return ret;
#ifdef TCP_KEEPINTVL
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
if (ret < 0)
return ret;
#endif /* TCP_KEEPINTVL */
}
#endif /* _WIN32 */
return ret;
}
int sock_close(const sock_t sock)
{
#ifdef _WIN32
@@ -130,7 +164,13 @@ int sock_set_blocking(const sock_t sock)
u_long block = 0;
return ioctlsocket(sock, FIONBIO, &block);
#else
return fcntl(sock, F_SETFL, 0);
int rc;
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
}
return rc;
#endif
}
@@ -140,7 +180,13 @@ int sock_set_nonblocking(const sock_t sock)
u_long nonblock = 1;
return ioctlsocket(sock, FIONBIO, &nonblock);
#else
return fcntl(sock, F_SETFL, O_NONBLOCK);
int rc;
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
}
return rc;
#endif
}
@@ -158,7 +204,7 @@ int sock_is_recoverable(const int error)
{
#ifdef _WIN32
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
error == WSAEINPROGRESS);
error == WSAEINPROGRESS);
#else
return (error == EAGAIN || error == EINTR);
#endif
@@ -167,18 +213,18 @@ int sock_is_recoverable(const int error)
int sock_connect_error(const sock_t sock)
{
struct sockaddr sa;
unsigned len;
socklen_t len;
char temp;
sa.sa_family = AF_INET;
memset(&sa, 0, sizeof(sa));
sa.sa_family = AF_UNSPEC;
len = sizeof(sa);
/* we don't actually care about the peer name, we're just checking if
* we're connected or not */
if (getpeername(sock, &sa, &len) == 0)
{
return 0;
return 0;
}
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
@@ -194,720 +240,3 @@ int sock_connect_error(const sock_t sock)
return sock_error();
}
struct dnsquery_header
{
unsigned short id;
unsigned char qr;
unsigned char opcode;
unsigned char aa;
unsigned char tc;
unsigned char rd;
unsigned char ra;
unsigned char z;
unsigned char rcode;
unsigned short qdcount;
unsigned short ancount;
unsigned short nscount;
unsigned short arcount;
};
struct dnsquery_question
{
char qname[1024];
unsigned short qtype;
unsigned short qclass;
};
struct dnsquery_srvrdata
{
unsigned short priority;
unsigned short weight;
unsigned short port;
char target[1024];
};
struct dnsquery_resourcerecord
{
char name[1024];
unsigned short type;
unsigned short _class;
unsigned int ttl;
unsigned short rdlength;
struct dnsquery_srvrdata rdata;
};
void netbuf_add_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int num)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
/* assuming big endian */
*p++ = (num >> 24) & 0xff;
*p++ = (num >> 16) & 0xff;
*p++ = (num >> 8) & 0xff;
*p++ = (num) & 0xff;
*offset += 4;
}
void netbuf_get_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int *num)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
*num = 0;
/* assuming big endian */
*num |= (*p++) << 24;
*num |= (*p++) << 16;
*num |= (*p++) << 8;
*num |= (*p++);
*offset += 4;
}
void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
/* assuming big endian */
*p++ = (num >> 8) & 0xff;
*p++ = (num) & 0xff;
*offset += 2;
}
void netbuf_get_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short *num)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
*num = 0;
/* assuming big endian */
*num |= (*p++) << 8;
*num |= (*p++);
*offset += 2;
}
void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
char *name)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
unsigned char *wordstart, *wordend;
wordstart = (unsigned char *)name;
while (*wordstart)
{
int len;
wordend = wordstart;
while (*wordend && *wordend != '.')
{
wordend++;
}
len = (int)(wordend - wordstart);
if (len > 0x3F)
{
len = 0x3F;
}
*p++ = len;
while (wordstart != wordend)
{
*p++ = *wordstart++;
}
if (*wordstart == '.')
{
wordstart++;
}
}
*p++ = '\0';
*offset += p - start;
}
int calc_domain_name_size(unsigned char *buf, int buflen, int offset)
{
unsigned char *p = buf + offset;
int len = 0;
while (*p)
{
if ((*p & 0xC0) == 0xC0)
{
int newoffset = 0;
newoffset |= (*p++ & 0x3F) << 8;
newoffset |= *p;
p = buf + newoffset;
}
else
{
if (len)
{
len += 1;
}
len += *p;
p += *p + 1;
}
}
return len;
}
int netbuf_get_domain_name(unsigned char *buf, int buflen, int *offset, char *namebuf, int namebuflen)
{
unsigned char *start = buf + *offset;
unsigned char *p, *p2;
int *curroffset = offset;
int len = 0;
*namebuf = '\0';
/* measure length */
p = start;
while (*p)
{
if ((*p & 0xC0) == 0xC0)
{
int newoffset = 0;
newoffset |= (*p++ & 0x3F) << 8;
newoffset |= *p++;
p = buf + newoffset;
}
else
{
len += *p;
p += *p + 1;
}
}
if (namebuflen < len)
{
return len;
}
/* actually copy in name */
p = start;
p2 = (unsigned char *)namebuf;
while (*p)
{
if ((*p & 0xC0) == 0xC0)
{
int newoffset = 0;
newoffset |= (*p++ & 0x3F) << 8;
newoffset |= *p++;
if (curroffset)
{
*curroffset += (int)(p - start);
curroffset = NULL;
}
p = buf + newoffset;
}
else
{
int i, partlen;
if (*namebuf != '\0')
{
*p2++ = '.';
}
partlen = *p++;
for (i=0; i < partlen; i++)
{
*p2++ = *p++;
}
}
}
if (curroffset)
{
p++;
*curroffset += (int)(p - start);
curroffset = NULL;
}
*p2 = '\0';
return 0;
}
void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
{
unsigned char *p;
netbuf_add_16bitnum(buf, buflen, offset, header->id);
p = buf + *offset;
*p++ = ((header->qr & 0x01) << 7)
| ((header->opcode & 0x0F) << 3)
| ((header->aa & 0x01) << 2)
| ((header->tc & 0x01) << 1)
| ((header->rd & 0x01));
*p++ = ((header->ra & 0x01) << 7)
| ((header->z & 0x07) << 4)
| ((header->rcode & 0x0F));
*offset += 2;
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
}
void netbuf_get_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
{
unsigned char *p;
netbuf_get_16bitnum(buf, buflen, offset, &(header->id));
p = buf + *offset;
header->qr = (*p >> 7) & 0x01;
header->opcode = (*p >> 3) & 0x0F;
header->aa = (*p >> 2) & 0x01;
header->tc = (*p >> 1) & 0x01;
header->rd = (*p) & 0x01;
p++;
header->ra = (*p >> 7) & 0x01;
header->z = (*p >> 4) & 0x07;
header->rcode = (*p) & 0x0F;
p++;
*offset += 2;
netbuf_get_16bitnum(buf, buflen, offset, &(header->qdcount));
netbuf_get_16bitnum(buf, buflen, offset, &(header->ancount));
netbuf_get_16bitnum(buf, buflen, offset, &(header->nscount));
netbuf_get_16bitnum(buf, buflen, offset, &(header->arcount));
}
void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
{
netbuf_add_domain_name(buf, buflen, offset, question->qname);
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
}
void netbuf_get_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
{
netbuf_get_domain_name(buf, buflen, offset, question->qname, 1024);
netbuf_get_16bitnum(buf, buflen, offset, &(question->qtype));
netbuf_get_16bitnum(buf, buflen, offset, &(question->qclass));
}
void netbuf_get_dnsquery_srvrdata(unsigned char *buf, int buflen, int *offset, struct dnsquery_srvrdata *srvrdata)
{
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->priority));
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->weight));
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->port));
netbuf_get_domain_name(buf, buflen, offset, srvrdata->target, 1024);
}
void netbuf_get_dnsquery_resourcerecord(unsigned char *buf, int buflen, int *offset, struct dnsquery_resourcerecord *rr)
{
netbuf_get_domain_name(buf, buflen, offset, rr->name, 1024);
netbuf_get_16bitnum(buf, buflen, offset, &(rr->type));
netbuf_get_16bitnum(buf, buflen, offset, &(rr->_class));
netbuf_get_32bitnum(buf, buflen, offset, &(rr->ttl));
netbuf_get_16bitnum(buf, buflen, offset, &(rr->rdlength));
if (rr->type == 33) /* SRV */
{
int newoffset = *offset;
netbuf_get_dnsquery_srvrdata(buf, buflen, &newoffset, &(rr->rdata));
}
*offset += rr->rdlength;
}
int sock_srv_lookup(const char *service, const char *proto, const char *domain, char *resulttarget, int resulttargetlength, int *resultport)
{
int set = 0;
char fulldomain[2048];
snprintf(fulldomain, 2048, "_%s._%s.%s", service, proto, domain);
#ifdef _WIN32
/* try using dnsapi first */
if (!set)
{
HINSTANCE hdnsapi = NULL;
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
if (pDnsQuery_A && pDnsRecordListFree) {
PDNS_RECORD dnsrecords = NULL;
DNS_STATUS error;
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
if (error == 0) {
PDNS_RECORD current = dnsrecords;
while (current) {
if (current->wType == DNS_TYPE_SRV) {
snprintf(resulttarget, resulttargetlength, "%s", current->Data.Srv.pNameTarget);
*resultport = current->Data.Srv.wPort;
set = 1;
current = NULL;
} else {
current = current->pNext;
}
}
}
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
}
FreeLibrary(hdnsapi);
}
}
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
if (!set)
{
unsigned char buf[65536];
struct dnsquery_header header;
struct dnsquery_question question;
int offset = 0;
int addrlen;
sock_t sock;
struct sockaddr_in dnsaddr;
char dnsserverips[16][256];
int numdnsservers = 0;
int j;
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
if (!numdnsservers)
{
HINSTANCE hiphlpapi = NULL;
DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
{
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
if (pGetNetworkParams)
{
FIXED_INFO *fi;
ULONG len;
DWORD error;
char buffer[65535];
len = 65535;
fi = buffer;
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
{
IP_ADDR_STRING *pias = &(fi->DnsServerList);
while (pias && numdnsservers < 16)
{
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
pias = pias->Next;
}
}
}
}
FreeLibrary(hiphlpapi);
}
/* Next, try getting the DNS server ips from the registry */
if (!numdnsservers)
{
HKEY search;
LONG error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
if (error != ERROR_SUCCESS)
{
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
}
if (error == ERROR_SUCCESS)
{
char name[512];
DWORD len = 512;
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
if (error != ERROR_SUCCESS)
{
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
}
if (error == ERROR_SUCCESS)
{
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
while (*end && !strchr(parse, *end))
{
end++;
}
start = end;
}
}
}
RegCloseKey(search);
}
if (!numdnsservers)
{
HKEY searchlist;
LONG error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
if (error == ERROR_SUCCESS)
{
unsigned int i;
DWORD numinterfaces = 0;
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
for (i = 0; i < numinterfaces; i++)
{
char name[512];
DWORD len = 512;
HKEY searchentry;
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
{
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
{
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
while (*end && !strchr(parse, *end))
{
end++;
}
start = end;
}
}
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
{
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
while (*end && !strchr(parse, *end))
{
end++;
}
start = end;
}
}
RegCloseKey(searchentry);
}
}
RegCloseKey(searchlist);
}
}
/* If we have a DNS server, use it */
if (numdnsservers)
{
ULONG nonblocking = 1;
int i;
int insize;
memset(&header, 0, sizeof(header));
header.id = 12345; /* FIXME: Get a better id here */
header.rd = 1;
header.qdcount = 1;
netbuf_add_dnsquery_header(buf, 65536, &offset, &header);
memset(&question, 0, sizeof(question));
strncpy(question.qname, fulldomain, 1024);
question.qtype = 33; /* SRV */
question.qclass = 1; /* INTERNET! */
netbuf_add_dnsquery_question(buf, 65536, &offset, &question);
insize = 0;
for (i = 0; i < numdnsservers && insize <= 0; i++)
{
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ioctlsocket(sock, FIONBIO, &nonblocking);
memset(&dnsaddr, 0, sizeof(dnsaddr));
dnsaddr.sin_family = AF_INET;
dnsaddr.sin_port = htons(53);
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
addrlen = sizeof(dnsaddr);
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
for (j = 0; j < 50; j++)
{
insize = recvfrom(sock, (char *)buf, 65536, 0, (struct sockaddr *)&dnsaddr, &addrlen);
if (insize == SOCKET_ERROR)
{
if (sock_error() == WSAEWOULDBLOCK)
{
Sleep(100);
}
else
{
break;
}
}
else
{
break;
}
}
closesocket(sock);
}
offset = insize;
if (offset > 0)
{
int len = offset;
int i;
struct dnsquery_header header;
struct dnsquery_question question;
struct dnsquery_resourcerecord rr;
offset = 0;
netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
for (i = 0; i < header.qdcount; i++)
{
netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
}
for (i = 0; i < header.ancount; i++)
{
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
if (rr.type == 33)
{
struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
snprintf(resulttarget, resulttargetlength, "%s", srvrdata->target);
*resultport = srvrdata->port;
set = 1;
}
}
for (i = 0; i < header.ancount; i++)
{
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
}
}
}
}
#else
if (!set) {
unsigned char buf[65535];
int len;
if ((len = res_query(fulldomain, C_IN, T_SRV, buf, 65535)) > 0) {
int offset;
int i;
struct dnsquery_header header;
struct dnsquery_question question;
struct dnsquery_resourcerecord rr;
offset = 0;
netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
for (i = 0; i < header.qdcount; i++) {
netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
}
for (i = 0; i < header.ancount; i++) {
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
if (rr.type == 33) {
struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
snprintf(resulttarget, resulttargetlength, "%s",
srvrdata->target);
*resultport = srvrdata->port;
set = 1;
}
}
for (i = 0; i < header.ancount; i++) {
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
}
}
}
#endif
if (!set)
{
snprintf(resulttarget, resulttargetlength, "%s", domain);
*resultport = 5222;
return 0;
}
return 1;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -33,7 +30,7 @@ void sock_shutdown(void);
int sock_error(void);
sock_t sock_connect(const char * const host, const unsigned int port);
sock_t sock_connect(const char * const host, const unsigned short port);
int sock_close(const sock_t sock);
int sock_set_blocking(const sock_t sock);
@@ -43,9 +40,6 @@ int sock_write(const sock_t sock, const void * const buff, const size_t len);
int sock_is_recoverable(const int error);
/* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(const sock_t sock);
int sock_srv_lookup(const char *service, const char *proto,
const char *domain, char *resulttarget,
int resulttargetlength, int *resultport);
int sock_set_keepalive(const sock_t sock, int timeout, int interval);
#endif /* __LIBSTROPHE_SOCK_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,119 +0,0 @@
/* thread.c
** strophe XMPP client library -- thread abstraction
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
*/
/** @file
* Thread absraction.
*/
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "strophe.h"
#include "common.h"
#include "thread.h"
struct _mutex_t {
const xmpp_ctx_t *ctx;
#ifdef _WIN32
HANDLE mutex;
#else
pthread_mutex_t *mutex;
#endif
};
/* mutex functions */
mutex_t *mutex_create(const xmpp_ctx_t * ctx)
{
mutex_t *mutex;
mutex = xmpp_alloc(ctx, sizeof(mutex_t));
if (mutex) {
mutex->ctx = ctx;
#ifdef _WIN32
mutex->mutex = CreateMutex(NULL, FALSE, NULL);
#else
mutex->mutex = xmpp_alloc(ctx, sizeof(pthread_mutex_t));
if (mutex->mutex)
if (pthread_mutex_init(mutex->mutex, NULL) != 0) {
xmpp_free(ctx, mutex->mutex);
mutex->mutex = NULL;
}
#endif
if (!mutex->mutex) {
xmpp_free(ctx, mutex);
mutex = NULL;
}
}
return mutex;
}
int mutex_destroy(mutex_t *mutex)
{
int ret = 1;
const xmpp_ctx_t *ctx;
#ifdef _WIN32
if (mutex->mutex)
ret = CloseHandle(mutex->mutex);
#else
if (mutex->mutex)
ret = pthread_mutex_destroy(mutex->mutex) == 0;
#endif
ctx = mutex->ctx;
xmpp_free(ctx, mutex);
return ret;
}
int mutex_lock(mutex_t *mutex)
{
int ret;
#ifdef _WIN32
ret = WaitForSingleObject(mutex->mutex, INFINITE) == 0;
#else
ret = pthread_mutex_lock(mutex->mutex) == 0;
#endif
return ret;
}
int mutex_trylock(mutex_t *mutex)
{
/* TODO */
return 0;
}
int mutex_unlock(mutex_t *mutex)
{
int ret;
#ifdef _WIN32
ret = ReleaseMutex(mutex->mutex);
#else
ret = pthread_mutex_unlock(mutex->mutex) == 0;
#endif
return ret;
}

View File

@@ -1,43 +0,0 @@
/* thread.h
** strophe XMPP client library -- thread abstraction header
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
*/
/** @file
* Threading abstraction API.
*/
#ifndef __LIBSTROPHE_THREAD_H__
#define __LIBSTROPHE_THREAD_H__
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "strophe.h"
typedef struct _mutex_t mutex_t;
/* mutex functions */
mutex_t *mutex_create(const xmpp_ctx_t *ctx);
int mutex_destroy(mutex_t *mutex);
int mutex_lock(mutex_t *mutex);
int mutex_trylock(mutex_t *mutex);
int mutex_unlock(mutex_t *mutex);
#endif /* __LIBSTROPHE_THREAD_H__ */

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -27,7 +24,7 @@ typedef struct _tls tls_t;
void tls_initialize(void);
void tls_shutdown(void);
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock);
tls_t *tls_new(xmpp_conn_t *conn);
void tls_free(tls_t *tls);
int tls_set_credentials(tls_t *tls, const char *cafilename);

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -36,7 +33,7 @@ void tls_shutdown(void)
return;
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
/* always fail */
return NULL;

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -22,11 +19,15 @@
#include "tls.h"
#include "sock.h"
/* FIXME this shouldn't be a constant string */
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
struct _tls {
xmpp_ctx_t *ctx; /* do we need this? */
sock_t sock;
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
int lasterror;
};
void tls_initialize(void)
@@ -45,25 +46,22 @@ void tls_shutdown(void)
gnutls_global_deinit();
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(ctx, sizeof(tls_t));
const int cert_type_priority[3] = { GNUTLS_CRT_X509,
GNUTLS_CRT_OPENPGP, 0 };
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) {
tls->ctx = ctx;
tls->sock = sock;
gnutls_init(&tls->session, GNUTLS_CLIENT);
tls->ctx = conn->ctx;
tls->sock = conn->sock;
gnutls_init(&tls->session, GNUTLS_CLIENT);
gnutls_certificate_allocate_credentials(&tls->cred);
gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, CAFILE);
gnutls_set_default_priority(tls->session);
gnutls_certificate_type_set_priority(tls->session, cert_type_priority);
gnutls_set_default_priority(tls->session);
/* fixme: this may require setting a callback on win32? */
gnutls_transport_set_ptr(tls->session,
(gnutls_transport_ptr_t)sock);
/* fixme: this may require setting a callback on win32? */
gnutls_transport_set_int(tls->session, conn->sock);
}
return tls;
@@ -82,29 +80,39 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
/* set trusted credentials -- takes a .pem filename */
err = gnutls_certificate_set_x509_trust_file(tls->cred,
cafilename, GNUTLS_X509_FMT_PEM);
if (err < 0) return err;
cafilename, GNUTLS_X509_FMT_PEM);
if (err >= 0) {
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred);
}
tls->lasterror = err;
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred);
return err;
return err == GNUTLS_E_SUCCESS;
}
int tls_start(tls_t *tls)
{
return gnutls_handshake(tls->session);
sock_set_blocking(tls->sock);
tls->lasterror = gnutls_handshake(tls->session);
sock_set_nonblocking(tls->sock);
return tls->lasterror == GNUTLS_E_SUCCESS;
}
int tls_stop(tls_t *tls)
{
return gnutls_bye(tls->session, GNUTLS_SHUT_RDWR);
tls->lasterror = gnutls_bye(tls->session, GNUTLS_SHUT_RDWR);
return tls->lasterror == GNUTLS_E_SUCCESS;
}
int tls_error(tls_t *tls)
{
/* todo: some kind of error polling/dump */
return 0;
return tls->lasterror;
}
int tls_is_recoverable(int error)
{
return !gnutls_error_is_fatal(error);
}
int tls_pending(tls_t *tls)
@@ -117,6 +125,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
int ret;
ret = gnutls_record_recv(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
return ret;
}
@@ -126,7 +135,12 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
int ret;
ret = gnutls_record_send(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
return ret;
}
int tls_clear_pending_write(tls_t *tls)
{
return 0;
}

View File

@@ -6,16 +6,14 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* TLS implementation with OpenSSL.
*/
#include <errno.h> /* EINTR */
#include <string.h>
#ifndef _WIN32
@@ -25,6 +23,9 @@
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/x509v3.h>
#include "common.h"
#include "tls.h"
@@ -38,15 +39,46 @@ struct _tls {
int lasterror;
};
enum {
TLS_SHUTDOWN_MAX_RETRIES = 10,
TLS_TIMEOUT_SEC = 0,
TLS_TIMEOUT_USEC = 100000,
};
static void _tls_sock_wait(tls_t *tls, int error);
static void _tls_set_error(tls_t *tls, int error);
static void _tls_log_error(xmpp_ctx_t *ctx);
void tls_initialize(void)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
SSL_load_error_strings();
#else
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif
}
void tls_shutdown(void)
{
return;
/*
* FIXME: Don't free global tables, program or other libraries may use
* openssl after libstrophe finalization. Maybe better leak some fixed
* memory rather than cause random crashes of the main program.
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_COMP_free_compression_methods();
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
ERR_remove_state(0);
#else
ERR_remove_thread_state(NULL);
#endif
#endif
}
int tls_error(tls_t *tls)
@@ -54,34 +86,69 @@ int tls_error(tls_t *tls)
return tls->lasterror;
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(ctx, sizeof(*tls));
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
int mode;
if (tls) {
int ret;
memset(tls, 0, sizeof(*tls));
memset(tls, 0, sizeof(*tls));
tls->ctx = ctx;
tls->sock = sock;
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
tls->ctx = conn->ctx;
tls->sock = conn->sock;
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (tls->ssl_ctx == NULL)
goto err;
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
SSL_CTX_set_mode (tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_verify (tls->ssl_ctx, SSL_VERIFY_NONE, NULL);
/* Enable bug workarounds. */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL);
tls->ssl = SSL_new(tls->ssl_ctx);
/* Disable insecure SSL/TLS versions. */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv2); /* DROWN */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
ret = SSL_set_fd(tls->ssl, sock);
if (ret <= 0) {
tls->lasterror = SSL_get_error(tls->ssl, ret);
tls_error(tls);
tls_free(tls);
tls = NULL;
}
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
tls->ssl = SSL_new(tls->ssl_ctx);
if (tls->ssl == NULL)
goto err_free_ctx;
/* Trust server's certificate when user sets the flag explicitly. */
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
SSL_set_verify(tls->ssl, mode, 0);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl);
/*
* Allow only complete wildcards. RFC 6125 discourages wildcard usage
* completely, and lists internationalized domain names as a reason
* against partial wildcards.
* See https://tools.ietf.org/html/rfc6125#section-7.2 for more information.
*/
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, conn->domain, 0);
#endif
ret = SSL_set_fd(tls->ssl, conn->sock);
if (ret <= 0)
goto err_free_ssl;
}
return tls;
err_free_ssl:
SSL_free(tls->ssl);
err_free_ctx:
SSL_CTX_free(tls->ssl_ctx);
err:
xmpp_free(conn->ctx, tls);
_tls_log_error(conn->ctx);
return NULL;
}
void tls_free(tls_t *tls)
@@ -89,7 +156,6 @@ void tls_free(tls_t *tls)
SSL_free(tls->ssl);
SSL_CTX_free(tls->ssl_ctx);
xmpp_free(tls->ctx, tls);
return;
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
@@ -99,57 +165,69 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
int tls_start(tls_t *tls)
{
int ret = -1;
int error;
int ret;
long x509_res;
/* Since we're non-blocking, loop the connect call until it
succeeds or fails */
while (ret == -1) {
ret = SSL_connect(tls->ssl);
while (1) {
ret = SSL_connect(tls->ssl);
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
/* wait for something to happen on the sock before looping back */
if (ret == -1) {
fd_set fds;
struct timeval tv;
if (ret == -1 && tls_is_recoverable(error)) {
/* wait for something to happen on the sock before looping back */
_tls_sock_wait(tls, error);
continue;
}
tv.tv_sec = 0;
tv.tv_usec = 1000;
FD_ZERO(&fds);
FD_SET(tls->sock, &fds);
select(tls->sock + 1, &fds, &fds, NULL, &tv);
}
/* success or fatal error */
break;
}
if (ret <= 0) {
tls->lasterror = SSL_get_error(tls->ssl, ret);
return 0;
}
return 1;
x509_res = SSL_get_verify_result(tls->ssl);
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
x509_res == X509_V_OK ? "passed" : "FAILED");
_tls_set_error(tls, error);
return ret <= 0 ? 0 : 1;
}
int tls_stop(tls_t *tls)
{
int retries = 0;
int error;
int ret;
ret = SSL_shutdown(tls->ssl);
if (ret <= 0) {
tls->lasterror = SSL_get_error(tls->ssl, ret);
return 0;
while (1) {
++retries;
ret = SSL_shutdown(tls->ssl);
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
if (ret == 1 || !tls_is_recoverable(error) ||
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
break;
}
_tls_sock_wait(tls, error);
}
if (error == SSL_ERROR_SYSCALL && errno == 0) {
/*
* Handle special case when peer closes connection instead of
* proper shutdown.
*/
error = 0;
ret = 1;
}
_tls_set_error(tls, error);
return 1;
return ret <= 0 ? 0 : 1;
}
int tls_is_recoverable(int error)
{
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ
|| error == SSL_ERROR_WANT_WRITE
|| error == SSL_ERROR_WANT_CONNECT
|| error == SSL_ERROR_WANT_ACCEPT);
|| error == SSL_ERROR_WANT_WRITE
|| error == SSL_ERROR_WANT_CONNECT
|| error == SSL_ERROR_WANT_ACCEPT);
}
int tls_pending(tls_t *tls)
@@ -159,22 +237,20 @@ int tls_pending(tls_t *tls)
int tls_read(tls_t *tls, void * const buff, const size_t len)
{
int ret = SSL_read(tls->ssl, buff, len);
int ret;
if (ret <= 0) {
tls->lasterror = SSL_get_error(tls->ssl, ret);
}
ret = SSL_read(tls->ssl, buff, len);
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
return ret;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
{
int ret = SSL_write(tls->ssl, buff, len);
int ret;
if (ret <= 0) {
tls->lasterror = SSL_get_error(tls->ssl, ret);
}
ret = SSL_write(tls->ssl, buff, len);
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
return ret;
}
@@ -183,3 +259,51 @@ int tls_clear_pending_write(tls_t *tls)
{
return 0;
}
static void _tls_sock_wait(tls_t *tls, int error)
{
struct timeval tv;
fd_set rfds;
fd_set wfds;
int nfds;
int ret;
if (error == SSL_ERROR_NONE) return;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
if (error == SSL_ERROR_WANT_READ)
FD_SET(tls->sock, &rfds);
if (error == SSL_ERROR_WANT_WRITE)
FD_SET(tls->sock, &wfds);
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) ?
tls->sock + 1 : 0;
do {
tv.tv_sec = TLS_TIMEOUT_SEC;
tv.tv_usec = TLS_TIMEOUT_USEC;
ret = select(nfds, &rfds, &wfds, NULL, &tv);
} while (ret == -1 && errno == EINTR);
}
static void _tls_set_error(tls_t *tls, int error)
{
if (error != 0 && !tls_is_recoverable(error)) {
xmpp_debug(tls->ctx, "tls", "error=%d errno=%d", error, errno);
_tls_log_error(tls->ctx);
}
tls->lasterror = error;
}
static void _tls_log_error(xmpp_ctx_t *ctx)
{
unsigned long e;
char buf[256];
do {
e = ERR_get_error();
if (e != 0) {
ERR_error_string_n(e, buf, sizeof(buf));
xmpp_debug(ctx, "tls", "%s", buf);
}
} while (e != 0);
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -26,6 +23,7 @@
struct _tls {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
sock_t sock;
HANDLE hsec32;
@@ -63,8 +61,10 @@ void tls_shutdown(void)
return;
}
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
tls_t *tls_new(xmpp_conn_t *conn)
{
xmpp_ctx_t *ctx = conn->ctx;
sock_t sock = conn->sock;
tls_t *tls;
PSecurityFunctionTable (*pInitSecurityInterface)(void);
SCHANNEL_CRED scred;
@@ -95,6 +95,7 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
memset(tls, 0, sizeof(*tls));
tls->ctx = ctx;
tls->conn = conn;
tls->sock = sock;
if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
@@ -128,10 +129,16 @@ tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
memset(&scred, 0, sizeof(scred));
scred.dwVersion = SCHANNEL_CRED_VERSION;
/*scred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;*/
/* Remote server closes connection with forced RC4.
The below lines are commented to leave default system configuration */
#if 0
/* Something down the line doesn't like AES, so force it to RC4 */
algs[0] = CALG_RC4;
scred.cSupportedAlgs = 1;
scred.palgSupportedAlgs = algs;
#else
(void)algs;
#endif
ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);
@@ -213,24 +220,10 @@ int tls_start(tls_t *tls)
SecBuffer sbin[2], sbout[1];
SECURITY_STATUS ret;
int sent;
char *name = NULL;
char *name;
/* search the ctx's conns for our sock, and use the domain there as our
* name */
{
xmpp_connlist_t *listentry = tls->ctx->connlist;
while (listentry) {
xmpp_conn_t *conn = listentry->conn;
if (conn->sock == tls->sock) {
name = strdup(conn->domain);
listentry = NULL;
} else {
listentry = listentry->next;
}
}
}
/* use the domain there as our name */
name = tls->conn->domain;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
| ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
@@ -357,6 +350,7 @@ int tls_start(tls_t *tls)
if (ret != SEC_E_OK) {
tls->lasterror = ret;
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
return 0;
}
@@ -566,7 +560,6 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
{
SecBufferDesc sbdenc;
SecBuffer sbenc[4];
unsigned char *sendbuffer;
const unsigned char *p = buff;
int sent = 0, ret, remain = len;

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -58,6 +55,28 @@ char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s)
return copy;
}
/** strtok_r(3) implementation.
* This function has appeared in POSIX.1-2001, but not in C standard.
* For example, visual studio older than 2005 doesn't provide strtok_r()
* nor strtok_s().
*/
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
{
size_t len;
s = s ? s : *saveptr;
len = strspn(s, delim);
s += len;
if (*s == '\0')
return NULL;
len = strcspn(s, delim);
*saveptr = s[len] == '\0' ? &s[len] : &s[len + 1];
s[len] = '\0';
return s;
}
/** Return an integer based time stamp.
* This function uses gettimeofday or timeGetTime (on Win32 platforms) to
* compute an integer based time stamp. This is used internally by the

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -21,6 +18,12 @@
#include "ostypes.h"
/* TODO evaluate x and y only once */
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
/* string functions */
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
/* timing functions */
uint64_t time_stamp(void);
uint64_t time_elapsed(uint64_t t1, uint64_t t2);

73
src/uuid.c Normal file
View File

@@ -0,0 +1,73 @@
/* uuid.c
* strophe XMPP client library -- UUID generation
*
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Generation of UUID version 4 according to RFC4122.
*/
#include "strophe.h"
#include "common.h"
#include "rand.h"
/** @def XMPP_UUID_LEN
* UUID length in string representation excluding '\0'.
*/
#define XMPP_UUID_LEN 36
/** Generate UUID version 4 in pre-allocated buffer.
*
* @param ctx a Strophe context object
* @param uuid pre-allocated buffer of size (XMPP_UUID_LEN + 1)
*/
static void crypto_uuid_gen(xmpp_ctx_t *ctx, char *uuid)
{
unsigned char buf[16];
int i = 0; /* uuid iterator */
int j = 0; /* buf iterator */
static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
xmpp_rand_bytes(ctx->rand, buf, sizeof(buf));
buf[8] &= 0x3f;
buf[8] |= 0x80;
buf[6] &= 0x0f;
buf[6] |= 0x40;
while (i < XMPP_UUID_LEN) {
if (i == 8 || i == 13 || i == 18 || i == 23)
uuid[i++] = '-';
else {
uuid[i++] = hex[buf[j] >> 4];
uuid[i++] = hex[buf[j] & 0x0f];
++j;
}
}
uuid[XMPP_UUID_LEN] = '\0';
}
/** Generate UUID version 4.
* This function allocates memory for the resulting string and must be freed
* with xmpp_free().
*
* @param ctx a Strophe context object
*
* @return ASCIIZ string
*/
char *xmpp_uuid_gen(xmpp_ctx_t *ctx)
{
char *uuid;
uuid = xmpp_alloc(ctx, XMPP_UUID_LEN + 1);
if (uuid != NULL) {
crypto_uuid_gen(ctx, uuid);
}
return uuid;
}

178
strophe.h
View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This software is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -19,12 +16,12 @@
#ifndef __LIBSTROPHE_STROPHE_H__
#define __LIBSTROPHE_STROPHE_H__
#include <stddef.h> /* size_t */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* namespace defines */
/** @def XMPP_NS_CLIENT
* Namespace definition for 'jabber:client'.
@@ -118,9 +115,13 @@ typedef struct _xmpp_log_t xmpp_log_t;
typedef struct _xmpp_ctx_t xmpp_ctx_t;
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log);
const xmpp_log_t * const log);
void xmpp_ctx_free(xmpp_ctx_t * const ctx);
/* free some blocks returned by other APIs, for example the
buffer you get from xmpp_stanza_to_text */
void xmpp_free(const xmpp_ctx_t * const ctx, void *p);
struct _xmpp_mem_t {
void *(*alloc)(const size_t size, void * const userdata);
void (*free)(void *p, void * const userdata);
@@ -149,7 +150,6 @@ typedef void (*xmpp_log_handler)(void * const userdata,
struct _xmpp_log_t {
xmpp_log_handler handler;
void *userdata;
/* mutex_t lock; */
};
/* return a default logger filtering at a given level */
@@ -161,9 +161,19 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level);
typedef struct _xmpp_conn_t xmpp_conn_t;
typedef struct _xmpp_stanza_t xmpp_stanza_t;
/* connection flags */
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
#define XMPP_CONN_FLAG_MANDATORY_TLS (1UL << 1)
#define XMPP_CONN_FLAG_LEGACY_SSL (1UL << 2)
/** @def XMPP_CONN_FLAG_TRUST_TLS
* Trust server's certificate even if it is invalid.
*/
#define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3)
/* connect callback */
typedef enum {
XMPP_CONN_CONNECT,
XMPP_CONN_RAW_CONNECT,
XMPP_CONN_DISCONNECT,
XMPP_CONN_FAIL
} xmpp_conn_event_t;
@@ -207,17 +217,22 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
xmpp_stream_error_t * const stream_error,
void * const userdata);
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
xmpp_conn_t * xmpp_conn_clone(xmpp_conn_t * const conn);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
int xmpp_conn_release(xmpp_conn_t * const conn);
long xmpp_conn_get_flags(const xmpp_conn_t * const conn);
int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn);
void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid);
const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn);
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass);
xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t * const conn);
void xmpp_conn_disable_tls(xmpp_conn_t * const conn);
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
int xmpp_connect_client(xmpp_conn_t * const conn,
const char * const altdomain,
@@ -225,9 +240,20 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
xmpp_conn_handler callback,
void * const userdata);
/*
int xmpp_connect_component(conn, name)
*/
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
unsigned short port, xmpp_conn_handler callback,
void * const userdata);
int xmpp_connect_raw(xmpp_conn_t * const conn,
const char * const altdomain,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata);
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn);
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
size_t attributes_len);
int xmpp_conn_tls_start(xmpp_conn_t * const conn);
void xmpp_disconnect(xmpp_conn_t * const conn);
void xmpp_send(xmpp_conn_t * const conn,
@@ -279,28 +305,24 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
*/
/** stanzas **/
/* stanzas */
/** allocate an initialize a blank stanza */
/* allocate and initialize a blank stanza */
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx);
/** clone a stanza */
/* clone a stanza */
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza);
/** copies a stanza and all children */
xmpp_stanza_t * xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
/* copies a stanza and all children */
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
/** free a stanza object and it's contents */
/* free a stanza object and it's contents */
int xmpp_stanza_release(xmpp_stanza_t * const stanza);
/** free some blocks returned by other APIs, for example the
buffer you get from xmpp_stanza_to_text **/
void xmpp_free(const xmpp_ctx_t * const ctx, void *p);
int xmpp_stanza_is_text(xmpp_stanza_t * const stanza);
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza);
/** marshall a stanza into text for transmission or display **/
/* marshall a stanza into text for transmission or display */
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
char ** const buf, size_t * const buflen);
@@ -310,18 +332,18 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char * const ns);
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name);
char * xmpp_stanza_get_ns(xmpp_stanza_t * const stanza);
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name);
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza);
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
const char **attr, int attrlen);
/* concatenate all child text nodes. this function
* returns a string that must be freed by the caller */
char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza);
char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza);
char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns);
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
/* set_attribute adds/replaces attributes */
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const key,
@@ -333,39 +355,85 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char * const text,
const size_t size);
int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
const char * const name);
/* common stanza helpers */
char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
const char * const id);
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
const char * const type);
/* unimplemented
int xmpp_stanza_set_to();
int xmpp_stanza_set_from();
*/
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza);
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns);
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, const char * const id);
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, const char * const type);
int xmpp_stanza_set_to(xmpp_stanza_t * const stanza, const char * const to);
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza, const char * const from);
/* allocate and initialize a stanza in reply to another */
/* unimplemented
xmpp_stanza_t *xmpp_stanza_reply(const xmpp_stanza_t *stanza);
*/
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza);
/* stanza subclasses */
/* unimplemented
void xmpp_message_new();
void xmpp_message_get_body();
void xmpp_message_set_body();
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
const char * const to, const char * const id);
char *xmpp_message_get_body(xmpp_stanza_t *msg);
int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
void xmpp_iq_new();
void xmpp_presence_new();
*/
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
const char * const id);
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
const char * const text);
/* jid */
/* these return new strings that must be xmpp_free()'d */
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
const char *domain,
const char *resource);
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid);
char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid);
/* event loop */
/** event loop **/
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout);
void xmpp_run(xmpp_ctx_t *ctx);
void xmpp_stop(xmpp_ctx_t *ctx);
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout);
/* UUID */
char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
/* SHA1 */
/** @def XMPP_SHA1_DIGEST_SIZE
* Size of the SHA1 message digest.
*/
#define XMPP_SHA1_DIGEST_SIZE 20
typedef struct _xmpp_sha1_t xmpp_sha1_t;
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
void xmpp_sha1_digest(const unsigned char *data, size_t len,
unsigned char *digest);
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx);
void xmpp_sha1_free(xmpp_sha1_t *sha1);
void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len);
void xmpp_sha1_final(xmpp_sha1_t *sha1);
char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen);
char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1);
void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest);
/* Base64 */
char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len);
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
unsigned char **out, size_t *outlen);
#ifdef __cplusplus
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
@@ -24,112 +21,112 @@
namespace XMPP {
class Context {
private:
xmpp_mem_t m_mem;
xmpp_log_t m_log;
xmpp_ctx_t *m_ctx;
xmpp_mem_t m_mem;
xmpp_log_t m_log;
xmpp_ctx_t *m_ctx;
public:
Context();
virtual ~Context();
Context();
virtual ~Context();
virtual void *alloc(const size_t size);
virtual void *realloc(void *p, const size_t size);
virtual void free(void *p);
virtual void log(const xmpp_log_level_t level,
const char * const area,
const char * const msg);
virtual void *alloc(const size_t size);
virtual void *realloc(void *p, const size_t size);
virtual void free(void *p);
virtual void log(const xmpp_log_level_t level,
const char * const area,
const char * const msg);
xmpp_ctx_t *getContext();
xmpp_ctx_t *getContext();
private:
static void *callAlloc(const size_t size, void * const userdata);
static void *callRealloc(void *p, const size_t size,
void * const userdata);
static void callFree(void *p, void * const userdata);
static void callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
static void *callAlloc(const size_t size, void * const userdata);
static void *callRealloc(void *p, const size_t size,
void * const userdata);
static void callFree(void *p, void * const userdata);
static void callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
};
class Stanza {
private:
Context *m_ctx;
xmpp_stanza_t *m_stanza;
Context *m_ctx;
xmpp_stanza_t *m_stanza;
void *operator new(size_t size, Context *ctx);
void operator delete(void *p);
Stanza(Context *ctx);
virtual ~Stanza();
void *operator new(size_t size, Context *ctx);
void operator delete(void *p);
Stanza(Context *ctx);
virtual ~Stanza();
public:
static Stanza *create(Context *ctx);
void release();
Stanza *clone();
Stanza *copy();
int toText(const char ** const buf, size_t * const buflen);
Stanza *getChildren();
Stanza *getChildByName(const char * const name);
Stanza *getNext();
static Stanza *create(Context *ctx);
void release();
Stanza *clone();
Stanza *copy();
int toText(const char ** const buf, size_t * const buflen);
Stanza *getChildren();
Stanza *getChildByName(const char * const name);
Stanza *getNext();
char *getAttribute(const char * const name);
char *getNamespace();
char *getText();
char *getName();
void addChild(Stanza *child);
void setNamespace(const char * const ns);
void setAttribute(const char * const key, const char * const value);
void setName(const char * const name);
void setText(const char * const text);
void setText(const char * const text, const size_t size);
char *getType();
char *getId();
char *getTo();
char *getFrom();
void setType(const char * const type);
void setId(const char * const id);
void setTo(const char * const to);
void setFrom(const char * const from);
char *getNamespace();
char *getText();
char *getName();
void addChild(Stanza *child);
void setNamespace(const char * const ns);
void setAttribute(const char * const key, const char * const value);
void setName(const char * const name);
void setText(const char * const text);
void setText(const char * const text, const size_t size);
char *getType();
char *getId();
char *getTo();
char *getFrom();
void setType(const char * const type);
void setId(const char * const id);
void setTo(const char * const to);
void setFrom(const char * const from);
};
class Connection {
private:
Context *m_ctx;
xmpp_conn_t *conn;
Context *m_ctx;
xmpp_conn_t *conn;
void *operator new(size_t size, Context *ctx);
Connection(Context *ctx);
void *operator new(size_t size, Context *ctx);
Connection(Context *ctx);
public:
static Connection *create(Context *ctx);
virtual ~Connection();
Connection *clone();
void operator delete(void *p);
static Connection *create(Context *ctx);
virtual ~Connection();
Connection *clone();
void operator delete(void *p);
const char *getJID();
void setJID(const char * const jid);
const char *getPass();
void setPass(const char * const pass);
bool connectClient(const char * const domain,
xmpp_conn_handler callback,
void * const userdata);
void disconnect();
void send(Stanza *stanza);
const char *getJID();
void setJID(const char * const jid);
const char *getPass();
void setPass(const char * const pass);
bool connectClient(const char * const domain,
xmpp_conn_handler callback,
void * const userdata);
void disconnect();
void send(Stanza *stanza);
void addTimedHandler(xmpp_timed_handler handler,
const unsigned long perdio,
void * const userdata);
void deleteTimedHandler(xmpp_timed_handler handler);
void addHandler(xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void deleteHandler(xmpp_handler handler);
void addIdHandler(xmpp_handler handler,
const char * const id,
void * const userdata);
void deleteIdHandler(xmpp_handler handler);
void addTimedHandler(xmpp_timed_handler handler,
const unsigned long perdio,
void * const userdata);
void deleteTimedHandler(xmpp_timed_handler handler);
void addHandler(xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void deleteHandler(xmpp_handler handler);
void addIdHandler(xmpp_handler handler,
const char * const id,
void * const userdata);
void deleteIdHandler(xmpp_handler handler);
};
}

View File

@@ -6,45 +6,50 @@
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <check.h>
#include <strophe.h>
#include "strophe.h"
#include "parser.h"
#include "test.h"
START_TEST(create_destroy)
#define fail_unless(expr) do { \
int result = (expr); \
if (!result) { \
printf("%s:%d: Assertion failed: %s\n", \
__FILE__, __LINE__, #expr); \
exit(1); \
} \
} while (0)
static void create_destroy(void)
{
xmpp_ctx_t *ctx;
parser_t *parser;
ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, NULL, NULL, NULL, NULL);
fail_unless(parser != NULL, "Parser creation failed.");
fail_unless(parser != NULL);
parser_free(parser);
xmpp_ctx_free(ctx);
}
END_TEST
int cbtest_got_start = 0;
void cbtest_handle_start(char *name, char **attrs, void *userdata)
{
if (strcmp(name, "stream:stream") == 0)
if (strcmp(name, "stream") == 0)
cbtest_got_start = 1;
}
int cbtest_got_end = 0;
void cbtest_handle_end(char *name, void *userdata)
{
if (strcmp(name, "stream:stream") == 0)
if (strcmp(name, "stream") == 0)
cbtest_got_end = 1;
}
@@ -55,7 +60,7 @@ void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
cbtest_got_stanza = 1;
}
START_TEST(callbacks)
static void callbacks(void)
{
xmpp_ctx_t *ctx;
parser_t *parser;
@@ -67,9 +72,12 @@ START_TEST(callbacks)
cbtest_handle_end,
cbtest_handle_stanza, NULL);
ret = parser_feed(parser, "<stream:stream>", 15);
ret = parser_feed(parser, "<stream>", 8);
fail_unless(ret != 0);
ret = parser_feed(parser, "<message/>", 10);
parser_feed(parser, "</stream:stream>", 16);
fail_unless(ret != 0);
ret = parser_feed(parser, "</stream>", 9);
fail_unless(ret != 0);
fail_unless(cbtest_got_start == 1);
fail_unless(cbtest_got_end == 1);
@@ -78,16 +86,18 @@ START_TEST(callbacks)
parser_free(parser);
xmpp_ctx_free(ctx);
}
END_TEST
Suite *parser_suite(void)
int main()
{
Suite *s = suite_create("Parser");
TCase *tc_core = tcase_create("Core");
tcase_add_test(tc_core, create_destroy);
tcase_add_test(tc_core, callbacks);
suite_add_tcase(s, tc_core);
return s;
}
printf("XML parser tests.\n");
TEST_MAIN
printf("create-destroy: ");
create_destroy();
printf("ok\n");
printf("callbacks: ");
callbacks();
printf("ok\n");
return 0;
}

90
tests/res_query_dump.c Normal file
View File

@@ -0,0 +1,90 @@
/* res_query_dump.c
* Simple program to dump res_query(3) response
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* Linux and OSX:
* gcc -o res_query_dump tests/res_query_dump.c -lresolv
* *BSD:
* gcc -o res_query_dump tests/res_query_dump.c
* QNX:
* gcc -o res_query_dump tests/res_query_dump.c -lsocket
* Solaris:
* gcc -o res_query_dump tests/res_query_dump.c -lresolv -lsocket -lnsl
*/
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#ifndef T_SRV
#define T_SRV 33
#endif /* T_SRV */
#ifndef C_IN
#define C_IN 1
#endif /* C_IN */
#define STEP 10
int main(int argc, char **argv)
{
unsigned char buf[65536];
char fulldomain[2048];
char *service = "xmpp-client";
char *proto = "tcp";
char *domain = NULL;
int len;
int i;
int j;
if (argc < 2) {
fprintf(stderr, "%s: argument missed\n", argc > 0 ? argv[0] : "$0");
fprintf(stderr, "Usage: %s <domain>\n", argc > 0 ? argv[0] : "$0");
return 1;
}
domain = argv[1];
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s",
service, proto, domain);
errno = 0;
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));
if (len < 0) {
fprintf(stderr, "res_query(): Error occurred (errno=%d)\n", errno);
}
if (len == 0) {
fprintf(stderr, "res_query(): Empty result\n");
}
if (len > 0) {
printf("/* res_query(\"%s\", C_IN, T_SRV, ...) */\n", fulldomain);
printf("static const unsigned char data[] = {\n");
for (i = 0; i < len; i += STEP) {
printf(" ");
for (j = i; j < len && j < i + STEP; ++j) {
printf(" 0x%02x,", buf[j]);
}
for (j = len; j < i + STEP; ++j) {
printf(" ");
}
printf(" // ");
for (j = i; j < len && j < i + STEP; ++j) {
printf("%c", isprint(buf[j]) ? buf[j] : '.');
}
printf("\n");
}
printf("};\n");
}
return len <= 0;
}

54
tests/test.c Normal file
View File

@@ -0,0 +1,54 @@
/* test.c
* strophe XMPP client library -- common routines for tests
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <string.h>
#include "test.h"
static uint8_t char_to_bin(char c)
{
return c <= '9' ? (uint8_t)(c - '0') :
c <= 'Z' ? (uint8_t)(c - 'A' + 10) :
(uint8_t)(c - 'a' + 10);
}
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len)
{
size_t len = strlen(hex);
size_t i;
assert(len % 2 == 0);
for (i = 0; i < len / 2; ++i) {
bin[i] = char_to_bin(hex[i * 2]) * 16 + char_to_bin(hex[i * 2 + 1]);
}
*bin_len = len / 2;
}
const char *test_bin_to_hex(const uint8_t *bin, size_t len)
{
static char buf[2048];
size_t i;
static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
assert(ARRAY_SIZE(buf) > len * 2);
for (i = 0; i < len; ++i) {
buf[i * 2] = hex[(bin[i] >> 4) & 0x0f];
buf[i * 2 + 1] = hex[bin[i] & 0x0f];
}
buf[len * 2] = '\0';
return buf;
}

View File

@@ -1,16 +1,69 @@
/* test.h
** libstrophe XMPP client library -- common routines for tests
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#ifndef __LIBSTROPHE_TEST_H__
#define __LIBSTROPHE_TEST_H__
#define TEST_MAIN \
int main(int argc, char **argv) {\
int num_failed;\
Suite *s = parser_suite();\
SRunner *sr = srunner_create(s);\
srunner_run_all(sr, CK_NORMAL);\
num_failed = srunner_ntests_failed(sr);\
srunner_free(sr);\
return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\
}\
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "ostypes.h"
#define TEST_MAIN \
int main(int argc, char **argv) { \
int num_failed; \
Suite *s = parser_suite(); \
SRunner *sr = srunner_create(s); \
srunner_run_all(sr, CK_NORMAL); \
num_failed = srunner_ntests_failed(sr); \
srunner_free(sr); \
return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; \
}
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#define COMPARE(v1, v2) \
do { \
const char *__v1 = v1; \
const char *__v2 = v2; \
if (strcmp(__v1, __v2) != 0) { \
printf("%s differs!\n" \
"expected: %s\n" \
"got: %s\n", \
#v1, __v1, __v2); \
exit(1); \
} \
} while (0)
#define COMPARE_BUF(v1, len1, v2, len2) \
do { \
const uint8_t *__v1 = (uint8_t *)(v1); \
const uint8_t *__v2 = (uint8_t *)(v2); \
size_t __len1 = len1; \
size_t __len2 = len2; \
if (__len1 != __len2 || \
memcmp(__v1, __v2, __len1) != 0) \
{ \
printf("%s differs!\n", #v1); \
printf("expected: 0x%s\n", \
test_bin_to_hex(__v1, __len1)); \
printf("got: 0x%s\n", \
test_bin_to_hex(__v2, __len2)); \
exit(1); \
} \
} while (0)
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len);
const char *test_bin_to_hex(const uint8_t *bin, size_t len);
#endif /* __LIBSTROPHE_TEST_H__ */

View File

@@ -1,151 +1,178 @@
/* test_base64.c
** libstrophe XMPP client library -- test routines for the base64 codec
**
** Copyright (C) 2005-2009 Collecta, Inc.
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
#include "sasl.h"
static const unsigned char text_1[] = "How now brown cow?";
static const char base64_1[] = "SG93IG5vdyBicm93biBjb3c/";
static const unsigned char text_2[] = {0x14,0xfb,0x9c,0x03,0xd9,0x7e,0x00};
static const char base64_2[] = "FPucA9l+";
static const unsigned char text_3[] =
"From rest and sleep, which but thy pictures be, "
"Much pleasure; then from thee much more must flow, "
"And soonest our best men with thee do go, "
"Rest of their bones, and soul's delivery.";
static const char base64_3[] =
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
"dWwncyBkZWxpdmVyeS4=";
static const unsigned char text_4[] =
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
#include "test.h"
static const unsigned char test_2_raw[] =
{0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e, 0x00};
static const unsigned char test_4_raw[] =
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
static const char base64_4[] = "1i8nSX7d89VBvBvp3+mzCA==";
static const char text_5[] =
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess";
static const char base64_5[] =
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz";
int test_encode(xmpp_ctx_t *ctx)
{
char *result;
result = base64_encode(ctx, text_1, strlen(text_1));
if (result == NULL) return 2;
if (strlen(result) != strlen(base64_1)) return 1;
if (strncmp(base64_1, result, strlen(base64_1))) return 1;
xmpp_free(ctx,result);
static const struct {
char *raw;
char *base64;
} tests[] = {
{
.raw = "How now brown cow?",
.base64 = "SG93IG5vdyBicm93biBjb3c/",
},
{
.raw = (char *)test_2_raw,
.base64 = "FPucA9l+",
},
{
.raw =
"From rest and sleep, which but thy pictures be, "
"Much pleasure; then from thee much more must flow, "
"And soonest our best men with thee do go, "
"Rest of their bones, and soul's delivery.",
.base64 =
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
"dWwncyBkZWxpdmVyeS4=",
},
{
.raw = (char *)test_4_raw,
.base64 = "1i8nSX7d89VBvBvp3+mzCA==",
},
{
.raw =
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
.base64 =
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz",
},
result = base64_encode(ctx, text_2, strlen(text_2));
if (result == NULL) return 2;
if (strlen(result) != strlen(base64_2)) return 1;
if (strncmp(base64_2, result, strlen(base64_2))) return 1;
xmpp_free(ctx,result);
result = base64_encode(ctx, text_3, strlen(text_3));
if (result == NULL) return 2;
if (strlen(result) != strlen(base64_3)) return 1;
if (strncmp(base64_3, result, strlen(base64_3))) return 1;
xmpp_free(ctx,result);
result = base64_encode(ctx, text_4, strlen(text_4));
if (result == NULL) return 2;
if (strlen(result) != strlen(base64_4)) return 1;
if (strncmp(base64_4, result, strlen(base64_4))) return 1;
xmpp_free(ctx,result);
result = base64_encode(ctx, text_5, strlen(text_5));
if (result == NULL) return 2;
if (strlen(result) != strlen(base64_5)) return 1;
if (strncmp(base64_5, result, strlen(base64_5))) return 1;
xmpp_free(ctx,result);
return 0;
}
int test_decode(xmpp_ctx_t *ctx)
{
unsigned char *result;
result = base64_decode(ctx, base64_1, strlen(base64_1));
if (result == NULL) return 2;
if (strlen(result) != strlen(text_1)) return 1;
if (strncmp(text_1, result, strlen(text_1))) return 1;
xmpp_free(ctx,result);
result = base64_decode(ctx, base64_2, strlen(base64_2));
if (result == NULL) return 2;
if (strlen(result) != strlen(text_2)) return 1;
if (strncmp(text_2, result, strlen(text_2))) return 1;
xmpp_free(ctx,result);
result = base64_decode(ctx, base64_3, strlen(base64_3));
if (result == NULL) return 2;
if (strlen(result) != strlen(text_3)) return 1;
if (strncmp(text_3, result, strlen(text_3))) return 1;
xmpp_free(ctx,result);
result = base64_decode(ctx, base64_4, strlen(base64_4));
if (result == NULL) return 2;
if (strlen(result) != strlen(text_4)) return 1;
if (strncmp(text_4, result, strlen(text_4))) return 1;
xmpp_free(ctx,result);
result = base64_decode(ctx, base64_5, strlen(base64_5));
if (result == NULL) return 2;
if (strlen(result) != strlen(text_5)) return 1;
if (strncmp(text_5, result, strlen(text_5))) return 1;
xmpp_free(ctx,result);
return 0;
}
/* RFC4648 test vectors */
{
.raw = "",
.base64 = "",
},
{
.raw = "f",
.base64 = "Zg==",
},
{
.raw = "fo",
.base64 = "Zm8=",
},
{
.raw = "foo",
.base64 = "Zm9v",
},
{
.raw = "foob",
.base64 = "Zm9vYg==",
},
{
.raw = "fooba",
.base64 = "Zm9vYmE=",
},
{
.raw = "foobar",
.base64 = "Zm9vYmFy",
},
};
static const unsigned char bin_data[] = {
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
0x6d, 0x00,
};
int main(int argc, char *argv[])
{
xmpp_ctx_t *ctx;
int ret;
unsigned char *udec;
char *dec;
char *enc;
size_t len, i;
printf("BASE64 tests.\n");
printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) printf("failed to create context\n");
if (ctx == NULL) return -1;
printf("ok.\n");
if (ctx == NULL) {
fprintf(stderr, "failed to create context\n");
return 1;
}
printf("testing encode... ");
ret = test_encode(ctx);
if (ret) printf("base64_encode failed!\n");
if (ret) return ret;
printf("ok.\n");
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
printf("Test #%d: ", (int)i + 1);
enc = xmpp_base64_encode(ctx, (unsigned char *)tests[i].raw,
strlen(tests[i].raw));
assert(enc != NULL);
COMPARE(tests[i].base64, enc);
xmpp_free(ctx, enc);
printf("testing decode... ");
ret = test_decode(ctx);
if (ret) printf("base64_decode failed!\n");
if (ret) return ret;
printf("ok.\n");
dec = xmpp_base64_decode_str(ctx, tests[i].base64,
strlen(tests[i].base64));
assert(dec != NULL);
COMPARE_BUF(tests[i].raw, strlen(tests[i].raw), dec, strlen(dec));
xmpp_free(ctx, dec);
printf("ok\n");
}
printf("Test with binary data: ");
enc = xmpp_base64_encode(ctx, bin_data, sizeof(bin_data));
assert(enc != NULL);
xmpp_base64_decode_bin(ctx, enc, strlen(enc), &udec, &len);
assert(udec != NULL);
assert(len != 0);
assert(len == sizeof(bin_data));
COMPARE_BUF(bin_data, sizeof(bin_data), udec, len);
xmpp_free(ctx, udec);
xmpp_free(ctx, enc);
printf("ok\n");
printf("freeing context... ");
xmpp_ctx_free(ctx);
printf("ok.\n");
return ret;
return 0;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>
@@ -97,6 +94,8 @@ int main(int argc, char **argv)
if (!(log_called && mem_alloc_called && mem_realloc_called &&
mem_free_called))
return 1;
if (mem_alloc_called != mem_free_called)
return 1;
return 0;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdlib.h>
@@ -79,6 +76,18 @@ int main(int argc, char **argv)
return 1;
}
/* test replacing old values */
for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[0], (void*)values[i]);
if (err) return err;
if (hash_num_keys(table) != nkeys) return 1;
result = hash_get(table, keys[0]);
if (result == NULL) return 1;
if (strcmp(result, values[i]) != 0) return 1;
}
/* restore value for the 1st key */
hash_add(table, keys[0], (void*)values[0]);
/* test cloning */
clone = hash_clone(table);

View File

@@ -1,15 +1,12 @@
/* test_base64.c
/* test_jid.c
** libstrophe XMPP client library -- test routines for the jid utils
**
** Copyright (C) 2005-2009 Collecta, Inc.
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>
@@ -23,56 +20,74 @@ static const char jid2[] = "anyone@example.com/hullo";
static const char jid3[] = "manic.porter@xyz.net/frob";
static const char jid4[] = "domain.tld";
static const char *_s(const char *s)
{
return s == NULL ? "<NULL>" : s;
}
int test_jid(xmpp_ctx_t *ctx)
{
char *bare;
char *node;
char *domain;
char *resource;
bare = xmpp_jid_bare(ctx, jid1);
node = xmpp_jid_node(ctx, jid1);
domain = xmpp_jid_domain(ctx, jid1);
resource = xmpp_jid_resource(ctx, jid1);
printf("jid '%s' parsed to %s, %s, %s\n",
jid1, node, domain, resource);
if (strcmp(node, "foo")) return 1;
if (strcmp(domain, "bar.com")) return 1;
jid1, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1;
if (node == NULL || strcmp(node, "foo")) return 1;
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid2);
node = xmpp_jid_node(ctx, jid2);
domain = xmpp_jid_domain(ctx, jid2);
resource = xmpp_jid_resource(ctx, jid2);
printf("jid '%s' parsed to %s, %s, %s\n",
jid2, node, domain, resource);
if (strcmp(node, "anyone")) return 1;
if (strcmp(domain, "example.com")) return 1;
if (strcmp(resource, "hullo")) return 1;
jid2, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1;
if (node == NULL || strcmp(node, "anyone")) return 1;
if (domain == NULL || strcmp(domain, "example.com")) return 1;
if (resource == NULL || strcmp(resource, "hullo")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3);
node = xmpp_jid_node(ctx, jid3);
domain = xmpp_jid_domain(ctx, jid3);
resource = xmpp_jid_resource(ctx, jid3);
printf("jid '%s' parsed to %s, %s, %s\n",
jid3, node, domain, resource);
if (strcmp(node, "manic.porter")) return 1;
if (strcmp(domain, "xyz.net")) return 1;
if (strcmp(resource, "frob")) return 1;
jid3, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1;
if (node == NULL || strcmp(node, "manic.porter")) return 1;
if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
if (resource == NULL || strcmp(resource, "frob")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4);
node = xmpp_jid_node(ctx, jid4);
domain = xmpp_jid_domain(ctx, jid4);
resource = xmpp_jid_resource(ctx, jid4);
printf("jid '%s' parsed to %s, %s, %s\n",
jid4, node, domain, resource);
jid4, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
if (node != NULL) return 1;
if (strcmp(domain, "domain.tld")) return 1;
if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
@@ -102,23 +117,23 @@ int main(int argc, char *argv[])
xmpp_ctx_t *ctx;
int ret;
printf("allocating context... ");
printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) printf("failed to create context\n");
if (ctx == NULL) return -1;
printf("ok.\n");
printf("testing jid routines... ");
printf("testing jid routines...\n");
ret = test_jid(ctx);
if (ret) printf("failed!\n");
if (ret) printf("testing jid routines... failed!\n");
if (ret) return ret;
printf("ok.\n");
printf("testing jid routines... ok.\n");
printf("testing jid new routines... ");
printf("testing jid new routines...\n");
ret = test_jid_new(ctx);
if (ret) printf("failed!\n");
if (ret) printf("testing jid new routines... failed!\n");
if (ret) return ret;
printf("ok.\n");
printf("testing jid new routines... ok.\n");
printf("freeing context... ");
xmpp_ctx_free(ctx);

77
tests/test_md5.c Normal file
View File

@@ -0,0 +1,77 @@
/* test_md5.c
* strophe XMPP client library -- test vectors for MD5
*
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* gcc -o test_md5 -I./src tests/test_md5.c tests/test.c src/md5.c */
#include <stdio.h>
#include <string.h>
#include "test.h"
#include "md5.h"
/*
* Test vectors for MD5 (RFC1321).
*/
static const struct {
const char *data;
const char *md5;
} tests[] = {
{
.data = "",
.md5 = "d41d8cd98f00b204e9800998ecf8427e",
},
{
.data = "a",
.md5 = "0cc175b9c0f1b6a831c399e269772661",
},
{
.data = "abc",
.md5 = "900150983cd24fb0d6963f7d28e17f72",
},
{
.data = "message digest",
.md5 = "f96b697d7cb7938d525a2f31aaf161d0",
},
{
.data = "abcdefghijklmnopqrstuvwxyz",
.md5 = "c3fcd3d76192e4007dfb496cca67e13b",
},
{
.data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
"fghijklmnopqrstuvwxyz0123456789",
.md5 = "d174ab98d277d9f5a5611c2c9f419d9f",
},
{
.data = "1234567890123456789012345678901"
"2345678901234567890123456789012"
"345678901234567890",
.md5 = "57edf4a22be3c955ac49da2e2107b67a",
},
};
int main(int argc, char **argv)
{
struct MD5Context ctx;
unsigned char digest[16];
size_t i;
printf("MD5 tests.\n");
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
printf("Test #%zu: ", i + 1);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *)tests[i].data, strlen(tests[i].data));
MD5Final(digest, &ctx);
COMPARE(tests[i].md5, test_bin_to_hex(digest, sizeof(digest)));
printf("ok\n");
}
return 0;
}

145
tests/test_rand.c Normal file
View File

@@ -0,0 +1,145 @@
/* check_rand.c
* strophe XMPP client library -- test vectors for Hash_DRBG
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* gcc -o test_rand -I./src tests/test_rand.c tests/test.c src/sha1.c */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
/* include rand.c to access private structures and functions */
#include "rand.c"
/* stubs to build test without whole libstrophe */
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) {
return NULL;
}
void xmpp_free(const xmpp_ctx_t * const ctx, void *p) { }
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...) {
return 0;
}
uint64_t time_stamp(void) {
return 0;
}
static struct {
const char *entropy_input;
const char *nonce;
size_t returned_bytes;
/* after instantiate */
const char *V1;
const char *C1;
/* after first generate */
const char *V2;
const char *C2;
/* after second generate */
const char *V3;
const char *C3;
const char *output;
} test_vectors[] = {
{
.entropy_input = "136cf1c174e5a09f66b962d994396525",
.nonce = "fff1c6645f19231f",
.returned_bytes = 80,
.V1 = "a884a83fa40bcf730e7395dd5800ea7101b48"
"77aaa29da9b7bc0bd2bd052b9b4022f83bae3"
"8064134a233835845fdd1442bf3a0221bdc8",
.C1 = "4977fb1268c1f6286b5b3969d416fb8ca7e4e"
"aab7fd2edefc239202baa033f8b44e9145148"
"ad24ce83d597176a0bacc84c99246f15e088",
.V2 = "f1fca3520ccdc59b79cecf472c17e5fda9997"
"22629fcc88b3df9dd577a55f93f47189892b1"
"8e1c5f39dfc077ae256588eecec7bbd0323c",
.C2 = "4977fb1268c1f6286b5b3969d416fb8ca7e4e"
"aab7fd2edefc239202baa033f8b44e9145148"
"ad24ce83d597176a0bacc84c99246f15e088",
.V3 = "3b749e64758fbbc3e52a08b1002ee18a517e5"
"cd1a9cfb67b0032fd83245938ca8c01add770"
"68515bde248c75adea10bbaaf0bc18e66a2c",
.C3 = "4977fb1268c1f6286b5b3969d416fb8ca7e4e"
"aab7fd2edefc239202baa033f8b44e9145148"
"ad24ce83d597176a0bacc84c99246f15e088",
.output = "0e28130fa5ca11edd3293ca26fdb8ae1810611f7"
"8715082ed3841e7486f16677b28e33ffe0b93d98"
"ba57ba358c1343ab2a26b4eb7940f5bc63938464"
"1ee80a25140331076268bd1ce702ad534dda0ed8",
},
{
.entropy_input = "dfed69b08902fcfb795d5d35dbe23f6b",
.nonce = "37258e820432e392",
.returned_bytes = 80,
.V1 = "2708022f0f6d13cd8bc139ceb86ee237ee124"
"e17029ac4f053d41526285599d4eac5029972"
"7d83a0df0d5fa9824d5f14d7e7e9c8bdb165",
.C1 = "fdb1a827c30e436c997261da6dc31ae7c27ee"
"28e5c29b2ee0ca57b44ab78b7b0d1e8b459ba"
"7285f5d93abf218d16d834a803c2330321cd",
.V2 = "24b9aa56d27b573a25339ba92631fd1fb0913"
"0a55ec477de6079906ad3ce5185bcadb7b047"
"627060f80afb8529c18b46567e6b79dffb01",
.C2 = "fdb1a827c30e436c997261da6dc31ae7c27ee"
"28e5c29b2ee0ca57b44ab78b7b0d1e8b459ba"
"7285f5d93abf218d16d834a803c2330321cd",
.V3 = "226b527e95899aa6bea5fd8393f5180773101"
"333baee2acc6d1f0baf7f4709368e966c945c"
"d4a0d86093183375443379b09c08e4381fa8",
.C3 = "fdb1a827c30e436c997261da6dc31ae7c27ee"
"28e5c29b2ee0ca57b44ab78b7b0d1e8b459ba"
"7285f5d93abf218d16d834a803c2330321cd",
.output = "adcb8e2cbbc5957d538a20db18b5e7fe350a90a2"
"01359fab9e0f154c53aa146bc6af1fcc7ff8f330"
"b8d9f3d7b038488ba627e6fa21d0147377b13404"
"22b22634b412dac69ac82c35b5fb411a4e42a133",
},
};
int main()
{
size_t i;
uint8_t entropy_input[1024];
size_t entropy_input_len;
uint8_t nonce[1024];
size_t nonce_len;
uint8_t output[1024];
Hash_DRBG_CTX ctx;
printf("Hash_DRBG tests.\n");
for (i = 0; i < ARRAY_SIZE(test_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
test_hex_to_bin(test_vectors[i].entropy_input, entropy_input,
&entropy_input_len);
test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len);
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len,
nonce, nonce_len);
COMPARE(test_vectors[i].V1, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
COMPARE(test_vectors[i].C1, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
assert(ctx.reseed_counter == 1);
Hash_DRBG_Generate(&ctx, output, test_vectors[i].returned_bytes);
COMPARE(test_vectors[i].V2, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
COMPARE(test_vectors[i].C2, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
assert(ctx.reseed_counter == 2);
Hash_DRBG_Generate(&ctx, output, test_vectors[i].returned_bytes);
COMPARE(test_vectors[i].V3, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
COMPARE(test_vectors[i].C3, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
COMPARE(test_vectors[i].output,
test_bin_to_hex(output, test_vectors[i].returned_bytes));
assert(ctx.reseed_counter == 3);
printf("ok\n");
}
return 0;
}

256
tests/test_resolver.c Normal file
View File

@@ -0,0 +1,256 @@
/* test_resolver.c
* strophe XMPP client library -- tests for resolver
*
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <stdio.h>
#include "strophe.h"
#include "rand.h"
#include "resolver.h"
#include "test.h"
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
static const unsigned char data1[] = {
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x61, 0x62, 0x62, 0x65, 0x72, 0x04, 0x6b, 0x69,
0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01,
0x00, 0x00, 0x00, 0x3b, 0x00, 0x16, 0x00, 0x01,
0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62,
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76,
0x02, 0x75, 0x61, 0x00,
};
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) */
static const unsigned char data2[] = {
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
0x6f, 0x72, 0x67, 0x00, 0xc0, 0x0c, 0x00, 0x21,
0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c,
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68,
0x65, 0x72, 0x6d, 0x65, 0x73, 0x32, 0x76, 0x36,
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
0x6f, 0x72, 0x67, 0x00,
};
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
static const unsigned char data3[] = {
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
0x6d, 0x00,
};
/* res_query("_xmpp-client._tcp.jabber.calyxinstitute.org", C_IN, T_SRV, ...) */
static const unsigned char data4[] = {
0x8d, 0x58, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // .X........
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, 0x61, // .jabber.ca
0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, // lyxinstitu
0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, // te.org..!.
0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, // ....!.....
0x83, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x14, 0x66, 0x10, // ........f.
0x69, 0x6a, 0x65, 0x65, 0x79, 0x6e, 0x72, 0x63, 0x36, 0x78, // ijeeynrc6x
0x32, 0x75, 0x79, 0x35, 0x6f, 0x62, 0x05, 0x6f, 0x6e, 0x69, // 2uy5ob.oni
0x6f, 0x6e, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, // on....!...
0x00, 0x03, 0x83, 0x00, 0x21, 0x00, 0x05, 0x00, 0x01, 0x14, // ....!.....
0x66, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x0e, 0x63, // f.jabber.c
0x61, 0x6c, 0x79, 0x78, 0x69, 0x6e, 0x73, 0x74, 0x69, 0x74, // alyxinstit
0x75, 0x74, 0x65, 0x03, 0x6f, 0x72, 0x67, 0x00, // ute.org.
};
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) with pointers */
static const unsigned char data5[] = {
0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // ..........
0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, // ..._xmpp-c
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, // lient._tcp
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, // .jabber.or
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, // g..!.....!
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x12, 0x00, 0x1f, // ..........
0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
0x73, 0x32, 0x76, 0x36, 0xc0, 0x1e, 0xc0, 0x0c, 0x00, 0x21, // s2v6.....!
0x00, 0x01, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x10, 0x00, 0x1e, // ..........
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, // ...f.herme
0x73, 0x32, 0xc0, 0x1e, // s2..
};
/* hacked data2 with two empty-string targets. */
static const unsigned char data6[] = {
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
0x00, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x03, 0x83, 0x00, 0x08, 0x00, 0x1f, 0x00,
0x1e, 0x14, 0x66, 0xc0, 0x40,
};
static const struct {
const unsigned char *data;
size_t len;
char *target;
unsigned short port;
int target_nr;
} tests[] = {
{
.data = data1,
.len = sizeof(data1),
.target = "jabber.kiev.ua",
.port = 5222,
.target_nr = 1,
},
{
.data = data2,
.len = sizeof(data2),
.target = "hermes2.jabber.org",
.port = 5222,
.target_nr = 2,
},
{
.data = data3,
.len = sizeof(data3),
.target = "xmpp.l.google.com",
.port = 5222,
.target_nr = 5,
},
{
.data = data4,
.len = sizeof(data4),
.target = "ijeeynrc6x2uy5ob.onion",
.port = 5222,
.target_nr = 2,
},
{
.data = data5,
.len = sizeof(data5),
.target = "hermes2.jabber.org",
.port = 5222,
.target_nr = 2,
},
{
.data = data6,
.len = sizeof(data6),
.target = "",
.port = 5222,
.target_nr = 2,
},
};
static int srv_rr_list_len(resolver_srv_rr_t *list)
{
int nr;
for (nr = 0; list != NULL; ++nr, list = list->next);
return nr;
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_rand_t *rand;
resolver_srv_rr_t *srv_rr_list;
char *domain;
unsigned char *buf;
unsigned short port;
size_t i;
int ret;
ctx = xmpp_ctx_new(NULL, NULL);
assert(ctx != NULL);
printf("resolver_srv_lookup_buf() tests.\n");
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
printf("Test #%zu: ", i + 1);
ret = resolver_srv_lookup_buf(ctx, tests[i].data, tests[i].len,
&srv_rr_list);
assert(ret == XMPP_DOMAIN_FOUND);
assert(srv_rr_list != NULL);
if (tests[i].target_nr != srv_rr_list_len(srv_rr_list)) {
printf("fail! got %d targets, but should be %d\n",
srv_rr_list_len(srv_rr_list), tests[i].target_nr);
return 1;
}
/* check only 1st result */
domain = srv_rr_list->target;
port = srv_rr_list->port;
COMPARE(tests[i].target, domain);
if (tests[i].port != port) {
printf("fail! got port=%u, but should be %u\n",
(unsigned)port, (unsigned)tests[i].port);
return 1;
}
printf("ok\n");
resolver_srv_free(ctx, srv_rr_list);
}
/*
* The next test case must not crash and is supposed to be checked
* under valgrind.
*/
printf("Test of a broken message: ");
rand = xmpp_rand_new(ctx);
assert(rand != NULL);
assert(sizeof(data2) > 64);
buf = xmpp_alloc(ctx, sizeof(data2));
assert(buf != NULL);
memcpy(buf, data2, 64);
xmpp_rand_bytes(rand, &buf[64], sizeof(data2) - 64);
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
resolver_srv_free(ctx, srv_rr_list);
xmpp_free(ctx, buf);
xmpp_rand_free(ctx, rand);
printf("ok\n");
xmpp_ctx_free(ctx);
return 0;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>

142
tests/test_scram.c Normal file
View File

@@ -0,0 +1,142 @@
/* test_scram.c
* strophe XMPP client library -- test vectors for SCRAM-SHA1
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/* gcc -o test_scram -I./src tests/test_scram.c tests/test.c src/sha1.c */
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
/* include scram.c to access static functions */
#include "scram.c"
/*
* Test vectors for derivation function (RFC6070).
*/
static const struct {
char *P; /* text */
char *S; /* salt */
size_t P_len;
size_t S_len;
uint32_t c; /* i */
char *DK; /* resulting digest */
} df_vectors[] = {
{
.P = "password",
.S = "salt",
.P_len = 8,
.S_len = 4,
.c = 1,
.DK = "0c60c80f961f0e71f3a9b524af6012062fe037a6",
},
{
.P = "password",
.S = "salt",
.P_len = 8,
.S_len = 4,
.c = 2,
.DK = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
},
{
.P = "password",
.S = "salt",
.P_len = 8,
.S_len = 4,
.c = 4096,
.DK = "4b007901b765489abead49d926f721d065a429c1",
},
};
static void test_df(void)
{
size_t i;
const char *s;
uint8_t dk[SHA1_DIGEST_SIZE];
printf("Derivation function tests (SCRAM_SHA1_Hi).\n");
for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
SCRAM_SHA1_Hi((uint8_t *)df_vectors[i].P, df_vectors[i].P_len,
(uint8_t *)df_vectors[i].S, df_vectors[i].S_len,
df_vectors[i].c, dk);
s = test_bin_to_hex(dk, sizeof(dk));
COMPARE(df_vectors[i].DK, s);
printf("ok\n");
}
}
/* RFC6120 */
static const struct {
char *password;
char *initial;
char *challenge;
char *response;
char *salt;
uint32_t i;
char *sign;
} scram_vectors[] = {
{
.password = "r0m30myr0m30",
.initial = "n,,n=juliet,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AA",
.challenge = "r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de6-9c30"
"-b51b3808c59e,s=NjhkYTM0MDgtNGY0Zi00NjdmLTkxMmUtNDlmNTNmN"
"DNkMDMz,i=4096",
.response = "c=biws,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de"
"6-9c30-b51b3808c59e",
.salt = "36386461333430382d346634662d34363766"
"2d393132652d343966353366343364303333",
.i = 4096,
.sign = "500e7bb4cfd2be90130641f6157b345835ef258c",
},
};
static void test_scram(void)
{
uint8_t key[SHA1_DIGEST_SIZE];
uint8_t sign[SHA1_DIGEST_SIZE];
uint8_t salt[256];
size_t salt_len;
char auth[512];
const char *s;
size_t i;
int j;
printf("SCRAM_SHA1_ClientKey and SCRAM_SHA1_ClientSignature tests.\n");
for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
snprintf(auth, sizeof(auth), "%s,%s,%s",
scram_vectors[i].initial + 3, scram_vectors[i].challenge,
scram_vectors[i].response);
test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len);
SCRAM_SHA1_ClientKey((uint8_t *)scram_vectors[i].password,
strlen(scram_vectors[i].password),
salt, salt_len, scram_vectors[i].i, key);
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
sign[j] ^= key[j];
}
s = test_bin_to_hex(sign, SHA1_DIGEST_SIZE);
COMPARE(scram_vectors[i].sign, s);
printf("ok\n");
}
}
int main(int argc, char **argv)
{
test_df();
test_scram();
return 0;
}

95
tests/test_sha1.c Normal file
View File

@@ -0,0 +1,95 @@
/* Tests for Steve Reid's public domain SHA-1 implementation */
/* This file is in the public domain */
/* gcc -o test_sha1 -I./src tests/test_sha1.c src/sha1.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sha1.h"
#include "test.h"
/* Test Vectors (from FIPS PUB 180-1) */
static char *test_data[] = {
"abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"A million repetitions of 'a'",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
static char *test_results[] = {
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F",
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"};
static void digest_to_hex(const uint8_t *digest, char *output)
{
int i,j;
char *c = output;
for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
for (j = 0; j < 4; j++) {
sprintf(c,"%02X", digest[i*4+j]);
c += 2;
}
sprintf(c, " ");
c += 1;
}
*(c - 1) = '\0';
}
int main(int argc, char** argv)
{
int k;
SHA1_CTX context;
uint8_t digest[20];
char output[80];
char *copy;
fprintf(stdout, "verifying SHA-1 implementation... ");
for (k = 0; k < ARRAY_SIZE(test_data); k++){
if (k == 2) {
/* this case will be checked below */
continue;
}
copy = strdup(test_data[k]);
crypto_SHA1_Init(&context);
crypto_SHA1_Update(&context, (uint8_t*)test_data[k],
strlen(test_data[k]));
crypto_SHA1_Final(&context, digest);
digest_to_hex(digest, output);
if (strcmp(output, test_results[k])) {
fprintf(stdout, "FAIL\n");
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
fprintf(stderr,"\t%s returned\n", output);
fprintf(stderr,"\t%s is correct\n", test_results[k]);
return (1);
}
if (strcmp(copy, test_data[k])) {
fprintf(stdout, "FAIL\n");
fprintf(stdout, "* original string was changed by SHA1\n");
return (1);
}
free(copy);
}
/* million 'a' vector we feed separately */
crypto_SHA1_Init(&context);
for (k = 0; k < 1000000; k++)
crypto_SHA1_Update(&context, (uint8_t*)"a", 1);
crypto_SHA1_Final(&context, digest);
digest_to_hex(digest, output);
if (strcmp(output, test_results[2])) {
fprintf(stdout, "FAIL\n");
fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
fprintf(stderr,"\t%s returned\n", output);
fprintf(stderr,"\t%s is correct\n", test_results[2]);
return (1);
}
/* success */
fprintf(stdout, "ok\n");
return(0);
}

91
tests/test_snprintf.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* 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
*/
#include <stdio.h>
#include <string.h>
#undef HAVE_VSNPRINTF
#undef HAVE_SNPRINTF
#include "snprintf.c"
#ifndef LONG_STRING
#define LONG_STRING 1024
#endif
int main (void)
{
char buf1[LONG_STRING];
char buf2[LONG_STRING];
char *fp_fmt[] = {
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%.1f",
NULL
};
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
"0x%x",
"0x%04x",
NULL
};
long int_nums[] = { -1, 134, 91340, 341, 0203, 0x76543210, 0};
int x, y;
int fail = 0;
int num = 0;
printf ("Testing xmpp_snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] != NULL ; x++)
for (y = 0; fp_nums[y] != 0 ; y++)
{
xmpp_snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
sprintf (buf2, fp_fmt[x], fp_nums[y]);
if (strcmp (buf1, buf2))
{
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
fp_fmt[x], buf1, buf2);
fail++;
}
num++;
}
for (x = 0; int_fmt[x] != NULL ; x++)
for (y = 0; int_nums[y] != 0 ; y++)
{
xmpp_snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
sprintf (buf2, int_fmt[x], int_nums[y]);
if (strcmp (buf1, buf2))
{
printf("xmpp_snprintf doesn't match Format: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
int_fmt[x], buf1, buf2);
fail++;
}
num++;
}
printf ("%d tests failed out of %d.\n", fail, num);
return fail != 0 ? 1 : 0;
}

View File

@@ -6,10 +6,7 @@
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>

126
tests/test_string.c Normal file
View File

@@ -0,0 +1,126 @@
/* test_string.c
* strophe XMPP client library -- tests for re-implemented string functions
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
#include "util.h"
#include "test.h" /* ARRAY_SIZE */
/* strtok_s() has appeared in visual studio 2005.
Use own implementation for older versions. */
#ifdef _MSC_VER
# if (_MSC_VER >= 1400)
# define strtok_r strtok_s
# else
# define strtok_r xmpp_strtok_r
# endif
#endif /* _MSC_VER */
static int test_strtok_r(void)
{
const char *test = "-abc-=-def--";
char *s1, *s2, *sub1, *sub2;
char *sp1, *sp2;
s1 = strdup(test);
s2 = strdup(test);
assert(strcmp(s1, s2) == 0);
sub1 = strtok_r(s1, "-", &sp1);
sub2 = xmpp_strtok_r(s2, "-", &sp2);
if (strcmp(sub1, sub2) != 0) {
printf("1st token is '%s', must be '%s'\n", sub2, sub1);
return -1;
}
sub1 = strtok_r(NULL, "-=", &sp1);
sub2 = xmpp_strtok_r(NULL, "-=", &sp2);
if (strcmp(sub1, sub2) != 0) {
printf("2nd token is '%s', must be '%s'\n", sub2, sub1);
return -1;
}
sub1 = strtok_r(NULL, "-", &sp1);
sub2 = xmpp_strtok_r(NULL, "-", &sp2);
if (sub1 != sub2) {
printf("3rd call returns %p instead of NULL\n", sub2);
return -1;
}
free(s1);
free(s2);
return 0;
}
static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
{
char *s1, *s2;
int rc = 0;
s1 = strdup(s);
s2 = xmpp_strdup(ctx, s);
if (!s1 || !s2 || strcmp(s1, s2) != 0) {
rc = -1;
printf("strdup: '%s', xmpp_strdup: '%s'\n",
s1 ? s1 : "<NULL>", s2 ? s2 : "<NULL>");
}
free(s1);
if (s2)
xmpp_free(ctx, s2);
return rc;
}
static int test_strdup(void)
{
xmpp_ctx_t *ctx;
size_t i;
int rc = 0;
static const char *tests[] = { "", "\0", "test", "s p a c e", "\n\r" };
ctx = xmpp_ctx_new(NULL, NULL);
assert(ctx != NULL);
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
rc = test_strdup_one(ctx, tests[i]);
if (rc != 0)
break;
}
xmpp_ctx_free(ctx);
return rc;
}
int main()
{
int rc;
printf("xmpp_strtok_r() tests... ");
rc = test_strtok_r();
if (rc != 0)
return 1;
printf("ok\n");
printf("xmpp_strdup() tests... ");
rc = test_strdup();
if (rc != 0)
return 1;
printf("ok\n");
return 0;
}

View File

@@ -1,195 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="active example"
ProjectGUID="{FB499990-F569-426A-9215-5B013D94B70C}"
RootNamespace="active"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\examples\active.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,195 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="basic example"
ProjectGUID="{7BD355D0-941D-4630-B82F-1FB43A971440}"
RootNamespace="basic"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\examples\basic.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,195 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="bot example"
ProjectGUID="{DEE25458-271F-4F9A-8979-C460C64B49C8}"
RootNamespace="bot"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\examples\bot.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,288 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="expat"
ProjectGUID="{AAFBC1E9-6192-46AE-95BC-642DCB20D361}"
RootNamespace="expat"
TargetFrameworkVersion="0"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;COMPILED_FROM_DSP;_LIB"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
PrecompiledHeaderFile=".\Debug/expat_static.pch"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="Debug\libexpatMTD.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/expat_static.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release_static"
IntermediateDirectory=".\Release_static"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=".\Release_static/expat_static.pch"
AssemblerListingLocation=".\Release_static/"
ObjectFile=".\Release_static/"
ProgramDataBaseFileName=".\Release_static/"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="Release_static\libexpatMT.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Release_static/expat_static.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath="..\expat\lib\xmlparse.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\expat\lib\xmlrole.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\expat\lib\xmltok.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath="..\expat\lib\ascii.h"
>
</File>
<File
RelativePath="..\expat\lib\asciitab.h"
>
</File>
<File
RelativePath="..\expat\lib\expat.h"
>
</File>
<File
RelativePath="..\expat\lib\expat_external.h"
>
</File>
<File
RelativePath="..\expat\lib\iasciitab.h"
>
</File>
<File
RelativePath="..\expat\lib\internal.h"
>
</File>
<File
RelativePath="..\expat\lib\latin1tab.h"
>
</File>
<File
RelativePath="..\expat\lib\nametab.h"
>
</File>
<File
RelativePath="..\expat\lib\utf8tab.h"
>
</File>
<File
RelativePath="..\expat\lib\xmlrole.h"
>
</File>
<File
RelativePath="..\expat\lib\xmltok.h"
>
</File>
<File
RelativePath="..\expat\lib\xmltok_impl.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,66 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libstrophe", "libstrophe.vcproj", "{659E3B17-B1BF-4D3B-94E6-438F85EBC410}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "active example", "active.vcproj", "{FB499990-F569-426A-9215-5B013D94B70C}"
ProjectSection(ProjectDependencies) = postProject
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic example", "basic.vcproj", "{7BD355D0-941D-4630-B82F-1FB43A971440}"
ProjectSection(ProjectDependencies) = postProject
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bot example", "bot.vcproj", "{DEE25458-271F-4F9A-8979-C460C64B49C8}"
ProjectSection(ProjectDependencies) = postProject
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "roster example", "roster.vcproj", "{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}"
ProjectSection(ProjectDependencies) = postProject
{659E3B17-B1BF-4D3B-94E6-438F85EBC410} = {659E3B17-B1BF-4D3B-94E6-438F85EBC410}
{AAFBC1E9-6192-46AE-95BC-642DCB20D361} = {AAFBC1E9-6192-46AE-95BC-642DCB20D361}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "expat.vcproj", "{AAFBC1E9-6192-46AE-95BC-642DCB20D361}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Debug|Win32.ActiveCfg = Debug|Win32
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Debug|Win32.Build.0 = Debug|Win32
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Release|Win32.ActiveCfg = Release|Win32
{659E3B17-B1BF-4D3B-94E6-438F85EBC410}.Release|Win32.Build.0 = Release|Win32
{FB499990-F569-426A-9215-5B013D94B70C}.Debug|Win32.ActiveCfg = Debug|Win32
{FB499990-F569-426A-9215-5B013D94B70C}.Debug|Win32.Build.0 = Debug|Win32
{FB499990-F569-426A-9215-5B013D94B70C}.Release|Win32.ActiveCfg = Release|Win32
{FB499990-F569-426A-9215-5B013D94B70C}.Release|Win32.Build.0 = Release|Win32
{7BD355D0-941D-4630-B82F-1FB43A971440}.Debug|Win32.ActiveCfg = Debug|Win32
{7BD355D0-941D-4630-B82F-1FB43A971440}.Debug|Win32.Build.0 = Debug|Win32
{7BD355D0-941D-4630-B82F-1FB43A971440}.Release|Win32.ActiveCfg = Release|Win32
{7BD355D0-941D-4630-B82F-1FB43A971440}.Release|Win32.Build.0 = Release|Win32
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Debug|Win32.ActiveCfg = Debug|Win32
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Debug|Win32.Build.0 = Debug|Win32
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Release|Win32.ActiveCfg = Release|Win32
{DEE25458-271F-4F9A-8979-C460C64B49C8}.Release|Win32.Build.0 = Release|Win32
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Debug|Win32.ActiveCfg = Debug|Win32
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Debug|Win32.Build.0 = Debug|Win32
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Release|Win32.ActiveCfg = Release|Win32
{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}.Release|Win32.Build.0 = Release|Win32
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Debug|Win32.ActiveCfg = Debug|Win32
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Debug|Win32.Build.0 = Debug|Win32
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Release|Win32.ActiveCfg = Release|Win32
{AAFBC1E9-6192-46AE-95BC-642DCB20D361}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,276 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="libstrophe"
ProjectGUID="{659E3B17-B1BF-4D3B-94E6-438F85EBC410}"
RootNamespace="libstrophe"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../;../expat/lib"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;XML_STATIC"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\src\auth.c"
>
</File>
<File
RelativePath="..\src\conn.c"
>
</File>
<File
RelativePath="..\src\ctx.c"
>
</File>
<File
RelativePath="..\src\event.c"
>
</File>
<File
RelativePath="..\src\handler.c"
>
</File>
<File
RelativePath="..\src\hash.c"
>
</File>
<File
RelativePath="..\src\jid.c"
>
</File>
<File
RelativePath="..\src\md5.c"
>
</File>
<File
RelativePath="..\src\parser.c"
>
</File>
<File
RelativePath="..\src\sasl.c"
>
</File>
<File
RelativePath="..\src\sha1.c"
>
</File>
<File
RelativePath="..\src\snprintf.c"
>
</File>
<File
RelativePath="..\src\sock.c"
>
</File>
<File
RelativePath="..\src\stanza.c"
>
</File>
<File
RelativePath="..\src\thread.c"
>
</File>
<File
RelativePath="..\src\tls_schannel.c"
>
</File>
<File
RelativePath="..\src\util.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\src\common.h"
>
</File>
<File
RelativePath="..\src\hash.h"
>
</File>
<File
RelativePath="..\src\md5.h"
>
</File>
<File
RelativePath="..\src\ostypes.h"
>
</File>
<File
RelativePath="..\src\sasl.h"
>
</File>
<File
RelativePath="..\src\sha1.h"
>
</File>
<File
RelativePath="..\src\sock.h"
>
</File>
<File
RelativePath="..\src\thread.h"
>
</File>
<File
RelativePath="..\src\tls.h"
>
</File>
<File
RelativePath="..\src\util.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,195 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="roster example"
ProjectGUID="{5F6591E0-3FAD-45AE-80CF-A47C1F8BA2CC}"
RootNamespace="rosterexample"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\examples\roster.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>