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/event.c
ADDED
@@ -0,0 +1,351 @@
|
|
1
|
+
/* event.c
|
2
|
+
** strophe XMPP client library -- event loop and management
|
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
|
+
* Event loop and management.
|
17
|
+
*/
|
18
|
+
|
19
|
+
/** @defgroup EventLoop Event loop
|
20
|
+
* These functions manage the Strophe event loop.
|
21
|
+
*
|
22
|
+
* Simple tools can use xmpp_run() and xmpp_stop() to manage the life
|
23
|
+
* cycle of the program. A common idiom is to set up a few initial
|
24
|
+
* event handers, call xmpp_run(), and then respond and react to
|
25
|
+
* events as they come in. At some point, one of the handlers will
|
26
|
+
* call xmpp_stop() to quit the event loop which leads to the program
|
27
|
+
* terminating.
|
28
|
+
*
|
29
|
+
* More complex programs will have their own event loops, and should
|
30
|
+
* ensure that xmpp_run_once() is called regularly from there. For
|
31
|
+
* example, a GUI program will already include an event loop to
|
32
|
+
* process UI events from users, and xmpp_run_once() would be called
|
33
|
+
* from an idle function.
|
34
|
+
*/
|
35
|
+
|
36
|
+
#include <stdio.h>
|
37
|
+
#include <stdlib.h>
|
38
|
+
#include <string.h>
|
39
|
+
|
40
|
+
#ifndef _WIN32
|
41
|
+
#include <sys/select.h>
|
42
|
+
#include <errno.h>
|
43
|
+
#else
|
44
|
+
#include <winsock2.h>
|
45
|
+
#define ETIMEDOUT WSAETIMEDOUT
|
46
|
+
#define ECONNRESET WSAECONNRESET
|
47
|
+
#define ECONNABORTED WSAECONNABORTED
|
48
|
+
#endif
|
49
|
+
|
50
|
+
#include "strophe.h"
|
51
|
+
#include "common.h"
|
52
|
+
|
53
|
+
#ifndef DEFAULT_TIMEOUT
|
54
|
+
/** @def DEFAULT_TIMEOUT
|
55
|
+
* The default timeout in milliseconds for the event loop.
|
56
|
+
* This is set to 1 millisecond.
|
57
|
+
*/
|
58
|
+
#define DEFAULT_TIMEOUT 1
|
59
|
+
#endif
|
60
|
+
|
61
|
+
/** Run the event loop once.
|
62
|
+
* This function will run send any data that has been queued by
|
63
|
+
* xmpp_send and related functions and run through the Strophe even
|
64
|
+
* loop a single time, and will not wait more than timeout
|
65
|
+
* milliseconds for events. This is provided to support integration
|
66
|
+
* with event loops outside the library, and if used, should be
|
67
|
+
* called regularly to achieve low latency event handling.
|
68
|
+
*
|
69
|
+
* @param ctx a Strophe context object
|
70
|
+
* @param timeout time to wait for events in milliseconds
|
71
|
+
*
|
72
|
+
* @ingroup EventLoop
|
73
|
+
*/
|
74
|
+
int xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
75
|
+
{
|
76
|
+
xmpp_connlist_t *connitem;
|
77
|
+
xmpp_conn_t *conn;
|
78
|
+
fd_set rfds, wfds;
|
79
|
+
sock_t max = 0;
|
80
|
+
int ret;
|
81
|
+
struct timeval tv;
|
82
|
+
xmpp_send_queue_t *sq, *tsq;
|
83
|
+
int towrite;
|
84
|
+
char buf[4096];
|
85
|
+
uint64_t next;
|
86
|
+
|
87
|
+
if (ctx->loop_status == XMPP_LOOP_QUIT) return -2;
|
88
|
+
ctx->loop_status = XMPP_LOOP_RUNNING;
|
89
|
+
|
90
|
+
/* send queued data */
|
91
|
+
connitem = ctx->connlist;
|
92
|
+
while (connitem) {
|
93
|
+
conn = connitem->conn;
|
94
|
+
if (conn->state != XMPP_STATE_CONNECTED) {
|
95
|
+
connitem = connitem->next;
|
96
|
+
continue;
|
97
|
+
}
|
98
|
+
|
99
|
+
/* if we're running tls, there may be some remaining data waiting to
|
100
|
+
* be sent, so push that out */
|
101
|
+
if (conn->tls) {
|
102
|
+
ret = tls_clear_pending_write(conn->tls);
|
103
|
+
|
104
|
+
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
105
|
+
/* an error occured */
|
106
|
+
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
|
107
|
+
conn->error = ECONNABORTED;
|
108
|
+
conn_disconnect(conn);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
/* write all data from the send queue to the socket */
|
113
|
+
sq = conn->send_queue_head;
|
114
|
+
while (sq) {
|
115
|
+
towrite = sq->len - sq->written;
|
116
|
+
|
117
|
+
if (conn->tls) {
|
118
|
+
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
|
119
|
+
|
120
|
+
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
121
|
+
/* an error occured */
|
122
|
+
conn->error = tls_error(conn->tls);
|
123
|
+
break;
|
124
|
+
} else if (ret < towrite) {
|
125
|
+
/* not all data could be sent now */
|
126
|
+
if (ret >= 0) sq->written += ret;
|
127
|
+
break;
|
128
|
+
}
|
129
|
+
|
130
|
+
} else {
|
131
|
+
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
132
|
+
|
133
|
+
if (ret < 0 && !sock_is_recoverable(sock_error())) {
|
134
|
+
/* an error occured */
|
135
|
+
conn->error = sock_error();
|
136
|
+
break;
|
137
|
+
} else if (ret < towrite) {
|
138
|
+
/* not all data could be sent now */
|
139
|
+
if (ret >= 0) sq->written += ret;
|
140
|
+
break;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
/* all data for this queue item written, delete and move on */
|
145
|
+
xmpp_free(ctx, sq->data);
|
146
|
+
tsq = sq;
|
147
|
+
sq = sq->next;
|
148
|
+
xmpp_free(ctx, tsq);
|
149
|
+
|
150
|
+
/* pop the top item */
|
151
|
+
conn->send_queue_head = sq;
|
152
|
+
/* if we've sent everything update the tail */
|
153
|
+
if (!sq) conn->send_queue_tail = NULL;
|
154
|
+
}
|
155
|
+
|
156
|
+
/* tear down connection on error */
|
157
|
+
if (conn->error) {
|
158
|
+
/* FIXME: need to tear down send queues and random other things
|
159
|
+
* maybe this should be abstracted */
|
160
|
+
xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting.");
|
161
|
+
conn->error = ECONNABORTED;
|
162
|
+
conn_disconnect(conn);
|
163
|
+
}
|
164
|
+
|
165
|
+
connitem = connitem->next;
|
166
|
+
}
|
167
|
+
|
168
|
+
/* reset parsers if needed */
|
169
|
+
for (connitem = ctx->connlist; connitem; connitem = connitem->next) {
|
170
|
+
if (connitem->conn->reset_parser)
|
171
|
+
parser_reset(connitem->conn);
|
172
|
+
}
|
173
|
+
|
174
|
+
|
175
|
+
/* fire any ready timed handlers, then
|
176
|
+
make sure we don't wait past the time when timed handlers need
|
177
|
+
to be called */
|
178
|
+
next = handler_fire_timed(ctx);
|
179
|
+
|
180
|
+
long usec = ((next < timeout) ? next : timeout) * 1000;
|
181
|
+
tv.tv_sec = usec / 1000000;
|
182
|
+
tv.tv_usec = usec % 1000000;
|
183
|
+
|
184
|
+
FD_ZERO(&rfds);
|
185
|
+
FD_ZERO(&wfds);
|
186
|
+
|
187
|
+
/* find events to watch */
|
188
|
+
connitem = ctx->connlist;
|
189
|
+
while (connitem) {
|
190
|
+
conn = connitem->conn;
|
191
|
+
|
192
|
+
switch (conn->state) {
|
193
|
+
case XMPP_STATE_CONNECTING:
|
194
|
+
/* connect has been called and we're waiting for it to complete */
|
195
|
+
/* connection will give us write or error events */
|
196
|
+
|
197
|
+
/* make sure the timeout hasn't expired */
|
198
|
+
if (time_elapsed(conn->timeout_stamp, time_stamp()) <=
|
199
|
+
conn->connect_timeout)
|
200
|
+
FD_SET(conn->sock, &wfds);
|
201
|
+
else {
|
202
|
+
conn->error = ETIMEDOUT;
|
203
|
+
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
|
204
|
+
conn_disconnect(conn);
|
205
|
+
}
|
206
|
+
break;
|
207
|
+
case XMPP_STATE_CONNECTED:
|
208
|
+
FD_SET(conn->sock, &rfds);
|
209
|
+
break;
|
210
|
+
case XMPP_STATE_DISCONNECTED:
|
211
|
+
/* do nothing */
|
212
|
+
default:
|
213
|
+
break;
|
214
|
+
}
|
215
|
+
|
216
|
+
if (conn->sock > max) max = conn->sock;
|
217
|
+
|
218
|
+
connitem = connitem->next;
|
219
|
+
}
|
220
|
+
|
221
|
+
/* check for events */
|
222
|
+
ret = select(max + 1, &rfds, &wfds, NULL, &tv);
|
223
|
+
|
224
|
+
/* select errored */
|
225
|
+
if (ret < 0) {
|
226
|
+
if (!sock_is_recoverable(sock_error())) {
|
227
|
+
xmpp_error(ctx, "xmpp", "event watcher internal error %d",
|
228
|
+
sock_error());
|
229
|
+
conn->error = sock_error();
|
230
|
+
return -1;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
/* no events happened */
|
235
|
+
if (ret == 0) {
|
236
|
+
conn->error = ETIMEDOUT;
|
237
|
+
return 1;
|
238
|
+
}
|
239
|
+
|
240
|
+
/* process events */
|
241
|
+
connitem = ctx->connlist;
|
242
|
+
while (connitem) {
|
243
|
+
conn = connitem->conn;
|
244
|
+
|
245
|
+
switch (conn->state) {
|
246
|
+
case XMPP_STATE_CONNECTING:
|
247
|
+
if (FD_ISSET(conn->sock, &wfds)) {
|
248
|
+
/* connection complete */
|
249
|
+
|
250
|
+
/* check for error */
|
251
|
+
conn->error = sock_connect_error(conn->sock);
|
252
|
+
if (conn->error != 0) {
|
253
|
+
/* connection failed */
|
254
|
+
xmpp_debug(ctx, "xmpp", "connection failed");
|
255
|
+
conn_disconnect(conn);
|
256
|
+
break;
|
257
|
+
}
|
258
|
+
|
259
|
+
conn->state = XMPP_STATE_CONNECTED;
|
260
|
+
xmpp_debug(ctx, "xmpp", "connection successful");
|
261
|
+
|
262
|
+
|
263
|
+
/* send stream init */
|
264
|
+
conn_open_stream(conn);
|
265
|
+
}
|
266
|
+
|
267
|
+
break;
|
268
|
+
case XMPP_STATE_CONNECTED:
|
269
|
+
if (FD_ISSET(conn->sock, &rfds)) {
|
270
|
+
if (conn->tls) {
|
271
|
+
ret = tls_read(conn->tls, buf, 4096);
|
272
|
+
} else {
|
273
|
+
ret = sock_read(conn->sock, buf, 4096);
|
274
|
+
}
|
275
|
+
|
276
|
+
if (ret > 0) {
|
277
|
+
ret = XML_Parse(conn->parser, buf, ret, 0);
|
278
|
+
if (!ret) {
|
279
|
+
/* parse error, we need to shut down */
|
280
|
+
/* FIXME */
|
281
|
+
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
|
282
|
+
conn -> error = -1;
|
283
|
+
conn_disconnect(conn);
|
284
|
+
}
|
285
|
+
} else {
|
286
|
+
if (conn->tls) {
|
287
|
+
if (!tls_is_recoverable(tls_error(conn->tls)))
|
288
|
+
{
|
289
|
+
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls));
|
290
|
+
conn->error = tls_error(conn->tls);
|
291
|
+
conn_disconnect(conn);
|
292
|
+
}
|
293
|
+
} else {
|
294
|
+
/* return of 0 means socket closed by server */
|
295
|
+
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
|
296
|
+
conn->error = ECONNRESET;
|
297
|
+
conn_disconnect(conn);
|
298
|
+
}
|
299
|
+
}
|
300
|
+
}
|
301
|
+
|
302
|
+
break;
|
303
|
+
case XMPP_STATE_DISCONNECTED:
|
304
|
+
/* do nothing */
|
305
|
+
default:
|
306
|
+
break;
|
307
|
+
}
|
308
|
+
|
309
|
+
connitem = connitem->next;
|
310
|
+
}
|
311
|
+
|
312
|
+
/* fire any ready handlers */
|
313
|
+
handler_fire_timed(ctx);
|
314
|
+
return 0;
|
315
|
+
}
|
316
|
+
|
317
|
+
/** Start the event loop.
|
318
|
+
* This function continuously calls xmpp_run_once and does not return
|
319
|
+
* until xmpp_stop has been called.
|
320
|
+
*
|
321
|
+
* @param ctx a Strophe context object
|
322
|
+
*
|
323
|
+
* @ingroup EventLoop
|
324
|
+
*/
|
325
|
+
void xmpp_run(xmpp_ctx_t *ctx)
|
326
|
+
{
|
327
|
+
if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) return;
|
328
|
+
|
329
|
+
ctx->loop_status = XMPP_LOOP_RUNNING;
|
330
|
+
while (ctx->loop_status == XMPP_LOOP_RUNNING) {
|
331
|
+
xmpp_run_once(ctx, DEFAULT_TIMEOUT);
|
332
|
+
}
|
333
|
+
|
334
|
+
xmpp_debug(ctx, "event", "Event loop completed.");
|
335
|
+
}
|
336
|
+
|
337
|
+
/** Stop the event loop.
|
338
|
+
* This will stop the event loop after the current iteration and cause
|
339
|
+
* xmpp_run to exit.
|
340
|
+
*
|
341
|
+
* @param ctx a Strophe context object
|
342
|
+
*
|
343
|
+
* @ingroup EventLoop
|
344
|
+
*/
|
345
|
+
void xmpp_stop(xmpp_ctx_t *ctx)
|
346
|
+
{
|
347
|
+
xmpp_debug(ctx, "event", "Stopping event loop.");
|
348
|
+
|
349
|
+
if (ctx->loop_status == XMPP_LOOP_RUNNING)
|
350
|
+
ctx->loop_status = XMPP_LOOP_QUIT;
|
351
|
+
}
|
data/ext/extconf.rb
ADDED