stropheruby 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +9 -0
- data/History.txt +4 -0
- data/Manifest.txt +40 -0
- data/PostInstall.txt +4 -0
- data/README.txt +28 -0
- data/Rakefile +21 -0
- data/examples/xmpp_client.rb +77 -0
- data/ext/auth.c +990 -0
- data/ext/common.h +287 -0
- data/ext/conn.c +611 -0
- data/ext/ctx.c +416 -0
- data/ext/event.c +351 -0
- data/ext/extconf.rb +8 -0
- data/ext/handler.c +592 -0
- data/ext/hash.c +278 -0
- data/ext/hash.h +64 -0
- data/ext/jid.c +177 -0
- data/ext/md5.c +289 -0
- data/ext/md5.h +41 -0
- data/ext/ostypes.h +27 -0
- data/ext/parser.c +208 -0
- data/ext/sasl.c +614 -0
- data/ext/sasl.h +44 -0
- data/ext/sha1.c +389 -0
- data/ext/sha1.h +31 -0
- data/ext/snprintf.c +839 -0
- data/ext/sock.c +911 -0
- data/ext/sock.h +51 -0
- data/ext/stanza.c +908 -0
- data/ext/strophe.h +372 -0
- data/ext/strophe_ruby.c +721 -0
- data/ext/thread.c +119 -0
- data/ext/thread.h +43 -0
- data/ext/tls.h +46 -0
- data/ext/tls_dummy.c +89 -0
- data/ext/util.c +107 -0
- data/ext/util.h +32 -0
- data/lib/strophe_ruby.rb +6 -0
- data/test/test_helper.rb +3 -0
- data/test/test_strophe_ruby.rb +11 -0
- data/test/test_strophe_ruby_extn.rb +9 -0
- metadata +111 -0
data/ext/conn.c
ADDED
@@ -0,0 +1,611 @@
|
|
1
|
+
/* conn.c
|
2
|
+
** strophe XMPP client library -- connection object functions
|
3
|
+
**
|
4
|
+
** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
|
5
|
+
**
|
6
|
+
** This software is provided AS-IS with no warranty, either express
|
7
|
+
** or implied.
|
8
|
+
**
|
9
|
+
** This software is distributed under license and may not be copied,
|
10
|
+
** modified or distributed except as expressly authorized under the
|
11
|
+
** terms of the license contained in the file LICENSE.txt in this
|
12
|
+
** distribution.
|
13
|
+
*/
|
14
|
+
|
15
|
+
/** @file
|
16
|
+
* Connection management.
|
17
|
+
*/
|
18
|
+
|
19
|
+
/** @defgroup Connections Connection management
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <stdio.h>
|
23
|
+
#include <stdlib.h>
|
24
|
+
#include <string.h>
|
25
|
+
|
26
|
+
#include "strophe.h"
|
27
|
+
#include "common.h"
|
28
|
+
#include "util.h"
|
29
|
+
|
30
|
+
#ifndef DEFAULT_SEND_QUEUE_MAX
|
31
|
+
/** @def DEFAULT_SEND_QUEUE_MAX
|
32
|
+
* The default maximum send queue size. This is currently unused.
|
33
|
+
*/
|
34
|
+
#define DEFAULT_SEND_QUEUE_MAX 64
|
35
|
+
#endif
|
36
|
+
#ifndef DISCONNECT_TIMEOUT
|
37
|
+
/** @def DISCONNECT_TIMEOUT
|
38
|
+
* The time to wait (in milliseconds) for graceful disconnection to
|
39
|
+
* complete before the connection is reset. The default is 2 seconds.
|
40
|
+
*/
|
41
|
+
#define DISCONNECT_TIMEOUT 2000 /* 2 seconds */
|
42
|
+
#endif
|
43
|
+
#ifndef CONNECT_TIMEOUT
|
44
|
+
/** @def CONNECT_TIMEOUT
|
45
|
+
* The time to wait (in milliseconds) for a connection attempt to succeed
|
46
|
+
* or error. The default is 5 seconds.
|
47
|
+
*/
|
48
|
+
#define CONNECT_TIMEOUT 5000 /* 5 seconds */
|
49
|
+
#endif
|
50
|
+
|
51
|
+
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
52
|
+
void * const userdata);
|
53
|
+
|
54
|
+
/** Create a new Strophe connection object.
|
55
|
+
*
|
56
|
+
* @param ctx a Strophe context object
|
57
|
+
*
|
58
|
+
* @return a Strophe connection object or NULL on an error
|
59
|
+
*
|
60
|
+
* @ingroup Connections
|
61
|
+
*/
|
62
|
+
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
63
|
+
{
|
64
|
+
xmpp_conn_t *conn = NULL;
|
65
|
+
xmpp_connlist_t *tail, *item;
|
66
|
+
|
67
|
+
if (ctx == NULL) return NULL;
|
68
|
+
conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
|
69
|
+
|
70
|
+
if (conn != NULL) {
|
71
|
+
conn->ctx = ctx;
|
72
|
+
|
73
|
+
conn->type = XMPP_UNKNOWN;
|
74
|
+
conn->sock = -1;
|
75
|
+
conn->tls = NULL;
|
76
|
+
conn->timeout_stamp = 0;
|
77
|
+
conn->error = 0;
|
78
|
+
conn->stream_error = NULL;
|
79
|
+
|
80
|
+
/* default send parameters */
|
81
|
+
conn->blocking_send = 0;
|
82
|
+
conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
|
83
|
+
conn->send_queue_len = 0;
|
84
|
+
conn->send_queue_head = NULL;
|
85
|
+
conn->send_queue_tail = NULL;
|
86
|
+
|
87
|
+
/* default timeouts */
|
88
|
+
conn->connect_timeout = CONNECT_TIMEOUT;
|
89
|
+
|
90
|
+
conn->lang = xmpp_strdup(conn->ctx, "en");
|
91
|
+
if (!conn->lang) {
|
92
|
+
xmpp_free(conn->ctx, conn);
|
93
|
+
return NULL;
|
94
|
+
}
|
95
|
+
conn->domain = NULL;
|
96
|
+
conn->jid = NULL;
|
97
|
+
conn->pass = NULL;
|
98
|
+
conn->stream_id = NULL;
|
99
|
+
|
100
|
+
conn->tls_support = 0;
|
101
|
+
conn->tls_failed = 0;
|
102
|
+
conn->sasl_support = 0;
|
103
|
+
|
104
|
+
conn->bind_required = 0;
|
105
|
+
conn->session_required = 0;
|
106
|
+
|
107
|
+
conn->parser = NULL;
|
108
|
+
conn->stanza = NULL;
|
109
|
+
parser_prepare_reset(conn, auth_handle_open);
|
110
|
+
|
111
|
+
conn->authenticated = 0;
|
112
|
+
conn->conn_handler = NULL;
|
113
|
+
conn->userdata = NULL;
|
114
|
+
conn->timed_handlers = NULL;
|
115
|
+
/* we own (and will free) the hash values */
|
116
|
+
conn->id_handlers = hash_new(conn->ctx, 32, NULL);
|
117
|
+
conn->handlers = NULL;
|
118
|
+
|
119
|
+
/* give the caller a reference to connection */
|
120
|
+
conn->ref = 1;
|
121
|
+
|
122
|
+
/* add connection to ctx->connlist */
|
123
|
+
tail = conn->ctx->connlist;
|
124
|
+
while (tail && tail->next) tail = tail->next;
|
125
|
+
|
126
|
+
item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t));
|
127
|
+
if (!item) {
|
128
|
+
xmpp_error(conn->ctx, "xmpp", "failed to allocate memory");
|
129
|
+
xmpp_free(conn->ctx, conn->lang);
|
130
|
+
XML_ParserFree(conn->parser);
|
131
|
+
xmpp_free(conn->ctx, conn);
|
132
|
+
conn = NULL;
|
133
|
+
} else {
|
134
|
+
item->conn = conn;
|
135
|
+
item->next = NULL;
|
136
|
+
|
137
|
+
if (tail) tail->next = item;
|
138
|
+
else conn->ctx->connlist = item;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
return conn;
|
143
|
+
}
|
144
|
+
|
145
|
+
/** Clone a Strophe connection object.
|
146
|
+
*
|
147
|
+
* @param conn a Strophe connection object
|
148
|
+
*
|
149
|
+
* @return the same conn object passed in with its reference count
|
150
|
+
* incremented by 1
|
151
|
+
*
|
152
|
+
* @ingroup Connections
|
153
|
+
*/
|
154
|
+
xmpp_conn_t * xmpp_conn_clone(xmpp_conn_t * const conn)
|
155
|
+
{
|
156
|
+
conn->ref++;
|
157
|
+
return conn;
|
158
|
+
}
|
159
|
+
|
160
|
+
/** Release a Strophe connection object.
|
161
|
+
* Decrement the reference count by one for a connection, freeing the
|
162
|
+
* connection object if the count reaches 0.
|
163
|
+
*
|
164
|
+
* @param conn a Strophe connection object
|
165
|
+
*
|
166
|
+
* @return TRUE if the connection object was freed and FALSE otherwise
|
167
|
+
*
|
168
|
+
* @ingroup Connections
|
169
|
+
*/
|
170
|
+
int xmpp_conn_release(xmpp_conn_t * const conn)
|
171
|
+
{
|
172
|
+
xmpp_ctx_t *ctx;
|
173
|
+
xmpp_connlist_t *item, *prev;
|
174
|
+
xmpp_handlist_t *hlitem, *thli;
|
175
|
+
hash_iterator_t *iter;
|
176
|
+
const char *key;
|
177
|
+
int released = 0;
|
178
|
+
|
179
|
+
if (conn->ref > 1)
|
180
|
+
conn->ref--;
|
181
|
+
else {
|
182
|
+
ctx = conn->ctx;
|
183
|
+
|
184
|
+
/* remove connection from context's connlist */
|
185
|
+
if (ctx->connlist->conn == conn) {
|
186
|
+
item = ctx->connlist;
|
187
|
+
ctx->connlist = item->next;
|
188
|
+
xmpp_free(ctx, item);
|
189
|
+
} else {
|
190
|
+
prev = NULL;
|
191
|
+
item = ctx->connlist;
|
192
|
+
while (item && item->conn != conn) {
|
193
|
+
prev = item;
|
194
|
+
item = item->next;
|
195
|
+
}
|
196
|
+
|
197
|
+
if (!item) {
|
198
|
+
xmpp_error(ctx, "xmpp", "Connection not in context's list\n");
|
199
|
+
} else {
|
200
|
+
prev->next = item->next;
|
201
|
+
xmpp_free(ctx, item);
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
/* free handler stuff
|
206
|
+
* note that userdata is the responsibility of the client
|
207
|
+
* and the handler pointers don't need to be freed since they
|
208
|
+
* are pointers to functions */
|
209
|
+
|
210
|
+
hlitem = conn->timed_handlers;
|
211
|
+
while (hlitem) {
|
212
|
+
thli = hlitem;
|
213
|
+
hlitem = hlitem->next;
|
214
|
+
|
215
|
+
xmpp_free(ctx, thli);
|
216
|
+
}
|
217
|
+
|
218
|
+
/* id handlers
|
219
|
+
* we have to traverse the hash table freeing list elements
|
220
|
+
* then release the hash table */
|
221
|
+
iter = hash_iter_new(conn->id_handlers);
|
222
|
+
while ((key = hash_iter_next(iter))) {
|
223
|
+
hlitem = (xmpp_handlist_t *)hash_get(conn->id_handlers, key);
|
224
|
+
while (hlitem) {
|
225
|
+
thli = hlitem;
|
226
|
+
hlitem = hlitem->next;
|
227
|
+
xmpp_free(conn->ctx, thli->id);
|
228
|
+
xmpp_free(conn->ctx, thli);
|
229
|
+
}
|
230
|
+
}
|
231
|
+
hash_iter_release(iter);
|
232
|
+
hash_release(conn->id_handlers);
|
233
|
+
|
234
|
+
hlitem = conn->handlers;
|
235
|
+
while (hlitem) {
|
236
|
+
thli = hlitem;
|
237
|
+
hlitem = hlitem->next;
|
238
|
+
|
239
|
+
if (thli->ns) xmpp_free(ctx, thli->ns);
|
240
|
+
if (thli->name) xmpp_free(ctx, thli->name);
|
241
|
+
if (thli->type) xmpp_free(ctx, thli->type);
|
242
|
+
xmpp_free(ctx, thli);
|
243
|
+
}
|
244
|
+
|
245
|
+
if (conn->stream_error) {
|
246
|
+
xmpp_stanza_release(conn->stream_error->stanza);
|
247
|
+
if (conn->stream_error->text)
|
248
|
+
xmpp_free(ctx, conn->stream_error->text);
|
249
|
+
xmpp_free(ctx, conn->stream_error);
|
250
|
+
}
|
251
|
+
|
252
|
+
XML_ParserFree(conn->parser);
|
253
|
+
|
254
|
+
if (conn->domain) xmpp_free(ctx, conn->domain);
|
255
|
+
if (conn->jid) xmpp_free(ctx, conn->jid);
|
256
|
+
if (conn->pass) xmpp_free(ctx, conn->pass);
|
257
|
+
if (conn->stream_id) xmpp_free(ctx, conn->stream_id);
|
258
|
+
xmpp_free(ctx, conn);
|
259
|
+
released = 1;
|
260
|
+
}
|
261
|
+
|
262
|
+
return released;
|
263
|
+
}
|
264
|
+
|
265
|
+
/** Get the JID which is or will be bound to the connection.
|
266
|
+
*
|
267
|
+
* @param conn a Strophe connection object
|
268
|
+
*
|
269
|
+
* @return a string containing the full JID or NULL if it has not been set
|
270
|
+
*
|
271
|
+
* @ingroup Connections
|
272
|
+
*/
|
273
|
+
const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn)
|
274
|
+
{
|
275
|
+
return conn->jid;
|
276
|
+
}
|
277
|
+
|
278
|
+
/** Set the JID of the user that will be bound to the connection.
|
279
|
+
* If any JID was previously set, it will be discarded. This should not be
|
280
|
+
* be used after a connection is created. The function will make a copy of
|
281
|
+
* the JID string. If the supllied JID is missing the node, SASL
|
282
|
+
* ANONYMOUS authentication will be used.
|
283
|
+
*
|
284
|
+
* @param conn a Strophe connection object
|
285
|
+
* @param jid a full or bare JID
|
286
|
+
*
|
287
|
+
* @ingroup Connections
|
288
|
+
*/
|
289
|
+
void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid)
|
290
|
+
{
|
291
|
+
if (conn->jid) xmpp_free(conn->ctx, conn->jid);
|
292
|
+
conn->jid = xmpp_strdup(conn->ctx, jid);
|
293
|
+
}
|
294
|
+
|
295
|
+
/** Get the password used for authentication of a connection.
|
296
|
+
*
|
297
|
+
* @param conn a Strophe connection object
|
298
|
+
*
|
299
|
+
* @return a string containing the password or NULL if it has not been set
|
300
|
+
*
|
301
|
+
* @ingroup Connections
|
302
|
+
*/
|
303
|
+
const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn)
|
304
|
+
{
|
305
|
+
return conn->pass;
|
306
|
+
}
|
307
|
+
|
308
|
+
/** Set the password used to authenticate the connection.
|
309
|
+
* If any password was previously set, it will be discarded. The function
|
310
|
+
* will make a copy of the password string.
|
311
|
+
*
|
312
|
+
* @param conn a Strophe connection object
|
313
|
+
* @param pass the password
|
314
|
+
*
|
315
|
+
* @ingroup Connections
|
316
|
+
*/
|
317
|
+
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass)
|
318
|
+
{
|
319
|
+
if (conn->pass) xmpp_free(conn->ctx, conn->pass);
|
320
|
+
conn->pass = xmpp_strdup(conn->ctx, pass);
|
321
|
+
}
|
322
|
+
|
323
|
+
/** Get the strophe context that the connection is associated with.
|
324
|
+
* @param conn a Strophe connection object
|
325
|
+
*
|
326
|
+
* @return a Strophe context
|
327
|
+
*
|
328
|
+
* @ingroup Connections
|
329
|
+
*/
|
330
|
+
xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn)
|
331
|
+
{
|
332
|
+
return conn->ctx;
|
333
|
+
}
|
334
|
+
|
335
|
+
/** Initiate a connection to the XMPP server.
|
336
|
+
* This function returns immediately after starting the connection
|
337
|
+
* process to the XMPP server, and notifiations of connection state changes
|
338
|
+
* will be sent to the callback function. The domain and port to connect to
|
339
|
+
* are usually determined by an SRV lookup for the xmpp-client service at
|
340
|
+
* the domain specified in the JID. If SRV lookup fails, altdomain and
|
341
|
+
* altport will be used instead if specified.
|
342
|
+
*
|
343
|
+
* @param conn a Strophe connection object
|
344
|
+
* @param altdomain a string with domain to use if SRV lookup fails. If this
|
345
|
+
* is NULL, the domain from the JID will be used.
|
346
|
+
* @param altport an integer port number to use if SRV lookup fails. If this
|
347
|
+
* is 0, the default port (5222) will be assumed.
|
348
|
+
* @param callback a xmpp_conn_handler callback function that will receive
|
349
|
+
* notifications of connection status
|
350
|
+
* @param userdata an opaque data pointer that will be passed to the callback
|
351
|
+
*
|
352
|
+
* @return 0 on success and -1 on an error
|
353
|
+
*
|
354
|
+
* @ingroup Connections
|
355
|
+
*/
|
356
|
+
int xmpp_connect_client(xmpp_conn_t * const conn,
|
357
|
+
const char * const altdomain,
|
358
|
+
unsigned short altport,
|
359
|
+
xmpp_conn_handler callback,
|
360
|
+
void * const userdata)
|
361
|
+
{
|
362
|
+
char connectdomain[2048];
|
363
|
+
int connectport;
|
364
|
+
char *domain;
|
365
|
+
|
366
|
+
conn->type = XMPP_CLIENT;
|
367
|
+
|
368
|
+
conn->domain = xmpp_jid_domain(conn->ctx, conn->jid);
|
369
|
+
if (!conn->domain) return -1;
|
370
|
+
|
371
|
+
if (!sock_srv_lookup("xmpp-client", "tcp", conn->domain, connectdomain, 2048, &connectport))
|
372
|
+
{
|
373
|
+
xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed.");
|
374
|
+
if (!altdomain)
|
375
|
+
domain = conn->domain;
|
376
|
+
else
|
377
|
+
domain = altdomain;
|
378
|
+
xmpp_debug(conn->ctx, "xmpp", "Using alternate domain %s, port %d", altdomain, altport);
|
379
|
+
strcpy(connectdomain, domain);
|
380
|
+
connectport = altport ? altport : 5222;
|
381
|
+
}
|
382
|
+
conn->sock = sock_connect(connectdomain, connectport);
|
383
|
+
if (conn->sock == -1) return -1;
|
384
|
+
|
385
|
+
/* setup handler */
|
386
|
+
conn->conn_handler = callback;
|
387
|
+
conn->userdata = userdata;
|
388
|
+
|
389
|
+
/* FIXME: it could happen that the connect returns immediately as
|
390
|
+
* successful, though this is pretty unlikely. This would be a little
|
391
|
+
* hard to fix, since we'd have to detect and fire off the callback
|
392
|
+
* from within the event loop */
|
393
|
+
|
394
|
+
conn->state = XMPP_STATE_CONNECTING;
|
395
|
+
conn->timeout_stamp = time_stamp();
|
396
|
+
xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", connectdomain);
|
397
|
+
|
398
|
+
return 0;
|
399
|
+
}
|
400
|
+
|
401
|
+
/** Cleanly disconnect the connection.
|
402
|
+
* This function is only called by the stream parser when </stream:stream>
|
403
|
+
* is received, and it not intended to be called by code outside of Strophe.
|
404
|
+
*
|
405
|
+
* @param conn a Strophe connection object
|
406
|
+
*/
|
407
|
+
void conn_disconnect_clean(xmpp_conn_t * const conn)
|
408
|
+
{
|
409
|
+
/* remove the timed handler */
|
410
|
+
xmpp_timed_handler_delete(conn, _disconnect_cleanup);
|
411
|
+
conn->error = -4;
|
412
|
+
conn_disconnect(conn);
|
413
|
+
}
|
414
|
+
|
415
|
+
/** Disconnect from the XMPP server.
|
416
|
+
* This function immediately disconnects from the XMPP server, and should
|
417
|
+
* not be used outside of the Strophe library.
|
418
|
+
*
|
419
|
+
* @param conn a Strophe connection object
|
420
|
+
*/
|
421
|
+
void conn_disconnect(xmpp_conn_t * const conn)
|
422
|
+
{
|
423
|
+
xmpp_debug(conn->ctx, "xmpp", "Closing socket.");
|
424
|
+
conn->state = XMPP_STATE_DISCONNECTED;
|
425
|
+
if (conn->tls) {
|
426
|
+
tls_stop(conn->tls);
|
427
|
+
tls_free(conn->tls);
|
428
|
+
conn->tls = NULL;
|
429
|
+
}
|
430
|
+
|
431
|
+
sock_close(conn->sock);
|
432
|
+
/* fire off connection handler */
|
433
|
+
if (NULL != conn->conn_handler) {
|
434
|
+
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
|
435
|
+
conn->stream_error, conn->userdata);
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
/* timed handler for cleanup if normal disconnect procedure takes too long */
|
440
|
+
static int _disconnect_cleanup(xmpp_conn_t * const conn,
|
441
|
+
void * const userdata)
|
442
|
+
{
|
443
|
+
xmpp_debug(conn->ctx, "xmpp",
|
444
|
+
"disconnection forced by cleanup timeout");
|
445
|
+
conn->error = -5;
|
446
|
+
conn_disconnect(conn);
|
447
|
+
|
448
|
+
return 0;
|
449
|
+
}
|
450
|
+
|
451
|
+
/** Initiate termination of the connection to the XMPP server.
|
452
|
+
* This function starts the disconnection sequence by sending
|
453
|
+
* </stream:stream> to the XMPP server. This function will do nothing
|
454
|
+
* if the connection state is CONNECTING or CONNECTED.
|
455
|
+
*
|
456
|
+
* @param conn a Strophe connection object
|
457
|
+
*
|
458
|
+
* @ingroup Connections
|
459
|
+
*/
|
460
|
+
void xmpp_disconnect(xmpp_conn_t * const conn)
|
461
|
+
{
|
462
|
+
if (conn->state != XMPP_STATE_CONNECTING &&
|
463
|
+
conn->state != XMPP_STATE_CONNECTED)
|
464
|
+
return;
|
465
|
+
|
466
|
+
/* close the stream */
|
467
|
+
xmpp_send_raw_string(conn, "</stream:stream>");
|
468
|
+
|
469
|
+
/* setup timed handler in case disconnect takes too long */
|
470
|
+
handler_add_timed(conn, _disconnect_cleanup,
|
471
|
+
DISCONNECT_TIMEOUT, NULL);
|
472
|
+
}
|
473
|
+
|
474
|
+
/** Send a raw string to the XMPP server.
|
475
|
+
* This function is a convenience function to send raw string data to the
|
476
|
+
* XMPP server. It is used by Strophe to send short messages instead of
|
477
|
+
* building up an XML stanza with DOM methods. This should be used with care
|
478
|
+
* as it does not validate the data; invalid data may result in immediate
|
479
|
+
* stream termination by the XMPP server.
|
480
|
+
*
|
481
|
+
* @param conn a Strophe connection object
|
482
|
+
* @param fmt a printf-style format string followed by a variable list of
|
483
|
+
* arguments to format
|
484
|
+
*/
|
485
|
+
void xmpp_send_raw_string(xmpp_conn_t * const conn,
|
486
|
+
const char * const fmt, ...)
|
487
|
+
{
|
488
|
+
va_list ap;
|
489
|
+
size_t len;
|
490
|
+
char buf[1024]; /* small buffer for common case */
|
491
|
+
char *bigbuf;
|
492
|
+
|
493
|
+
va_start(ap, fmt);
|
494
|
+
len = xmpp_vsnprintf(buf, 1024, fmt, ap);
|
495
|
+
va_end(ap);
|
496
|
+
|
497
|
+
if (len >= 1024) {
|
498
|
+
/* we need more space for this data, so we allocate a big
|
499
|
+
* enough buffer and print to that */
|
500
|
+
len++; /* account for trailing \0 */
|
501
|
+
bigbuf = xmpp_alloc(conn->ctx, len);
|
502
|
+
if (!bigbuf) {
|
503
|
+
xmpp_debug(conn->ctx, "xmpp", "Could not allocate memory for send_raw_string");
|
504
|
+
return;
|
505
|
+
}
|
506
|
+
va_start(ap, fmt);
|
507
|
+
xmpp_vsnprintf(bigbuf, len, fmt, ap);
|
508
|
+
va_end(ap);
|
509
|
+
|
510
|
+
xmpp_debug(conn->ctx, "conn", "SENT: %s", bigbuf);
|
511
|
+
|
512
|
+
/* len - 1 so we don't send trailing \0 */
|
513
|
+
xmpp_send_raw(conn, bigbuf, len - 1);
|
514
|
+
|
515
|
+
xmpp_free(conn->ctx, bigbuf);
|
516
|
+
} else {
|
517
|
+
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
518
|
+
|
519
|
+
xmpp_send_raw(conn, buf, len);
|
520
|
+
}
|
521
|
+
}
|
522
|
+
|
523
|
+
/** Send raw bytes to the XMPP server.
|
524
|
+
* This function is a convenience function to send raw bytes to the
|
525
|
+
* XMPP server. It is usedly primarly by xmpp_send_raw_string. This
|
526
|
+
* function should be used with care as it does not validate the bytes and
|
527
|
+
* invalid data may result in stream termination by the XMPP server.
|
528
|
+
*
|
529
|
+
* @param conn a Strophe connection object
|
530
|
+
* @param data a buffer of raw bytes
|
531
|
+
* @param len the length of the data in the buffer
|
532
|
+
*/
|
533
|
+
void xmpp_send_raw(xmpp_conn_t * const conn,
|
534
|
+
const char * const data, const size_t len)
|
535
|
+
{
|
536
|
+
xmpp_send_queue_t *item;
|
537
|
+
|
538
|
+
if (conn->state != XMPP_STATE_CONNECTED) return;
|
539
|
+
|
540
|
+
/* create send queue item for queue */
|
541
|
+
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
|
542
|
+
if (!item) return;
|
543
|
+
|
544
|
+
item->data = xmpp_alloc(conn->ctx, len);
|
545
|
+
if (!item->data) {
|
546
|
+
xmpp_free(conn->ctx, item);
|
547
|
+
return;
|
548
|
+
}
|
549
|
+
memcpy(item->data, data, len);
|
550
|
+
item->len = len;
|
551
|
+
item->next = NULL;
|
552
|
+
item->written = 0;
|
553
|
+
|
554
|
+
/* add item to the send queue */
|
555
|
+
if (!conn->send_queue_tail) {
|
556
|
+
/* first item, set head and tail */
|
557
|
+
conn->send_queue_head = item;
|
558
|
+
conn->send_queue_tail = item;
|
559
|
+
} else {
|
560
|
+
/* add to the tail */
|
561
|
+
conn->send_queue_tail->next = item;
|
562
|
+
conn->send_queue_tail = item;
|
563
|
+
}
|
564
|
+
conn->send_queue_len++;
|
565
|
+
}
|
566
|
+
|
567
|
+
/** Send an XML stanza to the XMPP server.
|
568
|
+
* This is the main way to send data to the XMPP server. The function will
|
569
|
+
* terminate without action if the connection state is not CONNECTED.
|
570
|
+
*
|
571
|
+
* @param conn a Strophe connection object
|
572
|
+
* @param stanza a Strophe stanza object
|
573
|
+
*
|
574
|
+
* @ingroup Connections
|
575
|
+
*/
|
576
|
+
void xmpp_send(xmpp_conn_t * const conn,
|
577
|
+
xmpp_stanza_t * const stanza)
|
578
|
+
{
|
579
|
+
char *buf;
|
580
|
+
size_t len;
|
581
|
+
int ret;
|
582
|
+
|
583
|
+
if (conn->state == XMPP_STATE_CONNECTED) {
|
584
|
+
if ((ret = xmpp_stanza_to_text(stanza, &buf, &len)) == 0) {
|
585
|
+
xmpp_send_raw(conn, buf, len);
|
586
|
+
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
587
|
+
xmpp_free(conn->ctx, buf);
|
588
|
+
}
|
589
|
+
}
|
590
|
+
}
|
591
|
+
|
592
|
+
/** Send the opening <stream:stream> tag to the server.
|
593
|
+
* This function is used by Strophe to begin an XMPP stream. It should
|
594
|
+
* not be used outside of the library.
|
595
|
+
*
|
596
|
+
* @param conn a Strophe connection object
|
597
|
+
*/
|
598
|
+
void conn_open_stream(xmpp_conn_t * const conn)
|
599
|
+
{
|
600
|
+
xmpp_send_raw_string(conn,
|
601
|
+
"<?xml version=\"1.0\"?>" \
|
602
|
+
"<stream:stream to=\"%s\" " \
|
603
|
+
"xml:lang=\"%s\" " \
|
604
|
+
"version=\"1.0\" " \
|
605
|
+
"xmlns=\"%s\" " \
|
606
|
+
"xmlns:stream=\"%s\">",
|
607
|
+
conn->domain,
|
608
|
+
conn->lang,
|
609
|
+
conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : XMPP_NS_COMPONENT,
|
610
|
+
XMPP_NS_STREAMS);
|
611
|
+
}
|