1 /*
2 * libDingaLing XMPP Jingle Library
3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4 *
5 * Version: MPL 1.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is libDingaLing XMPP Jingle Library
18 *
19 * The Initial Developer of the Original Code is
20 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Anthony Minessale II <anthm@freeswitch.org>
27 *
28 * libdingaling.c -- Main Library Code
29 *
30 * QMOD: XMPP Video Signaling + Presentation (video-v1 & camera-v1)
31 *
32 */
33
34
35 #ifndef _MSC_VER
36 #include <config.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <time.h>
42 #endif
43
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <assert.h>
48 #include <ctype.h>
49 #include <fcntl.h>
50 #include <iksemel.h>
51 #include <apr.h>
52 #include <apr_network_io.h>
53 #include <apr_errno.h>
54 #include <apr_general.h>
55 #include <apr_thread_proc.h>
56 #include <apr_thread_mutex.h>
57 #include <apr_thread_cond.h>
58 #include <apr_thread_rwlock.h>
59 #include <apr_file_io.h>
60 #include <apr_poll.h>
61 #include <apr_dso.h>
62 #include <apr_hash.h>
63 #include <apr_strings.h>
64 #include <apr_network_io.h>
65 #include <apr_poll.h>
66 #include <apr_queue.h>
67 #include <apr_uuid.h>
68 #include <apr_strmatch.h>
69 #define APR_WANT_STDIO
70 #define APR_WANT_STRFUNC
71 #include <apr_want.h>
72 #include <apr_env.h>
73
74 #include "ldl_compat.h"
75 #include "libdingaling.h"
76 #include "sha1.h"
77
78 #ifdef _MSC_VER
79 #include <io.h>
80 #pragma warning(disable:4127 4706)
81 #endif
82
83 #define microsleep(x) apr_sleep(x * 1000)
84 #define LDL_CAPS_VER "1.0.0.1"
85
86 static int opt_timeout = 30;
87
88 static void sha1_hash(char *out, unsigned char *in, unsigned int len);
89 static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen);
90 static void ldl_random_string(char *buf, uint16_t len, char *set);
91
92 static struct {
93 unsigned int flags;
94 FILE *log_stream;
95 int debug;
96 apr_pool_t *memory_pool;
97 unsigned int id;
98 ldl_logger_t logger;
99 apr_hash_t *avatar_hash;
100 apr_thread_mutex_t *flag_mutex;
101 } globals;
102
103 struct packet_node {
104 char id[80];
105 iks *xml;
106 unsigned int retries;
107 apr_time_t next;
108 };
109
110 struct ldl_buffer {
111 char *buf;
112 unsigned int len;
113 int hit;
114 };
115
116 typedef enum {
117 CS_NEW,
118 CS_START,
119 CS_CONNECTED
120 } ldl_handle_state_t;
121
122 struct ldl_handle {
123 iksparser *parser;
124 iksid *acc;
125 iksfilter *filter;
126 char *login;
127 char *password;
128 char *server;
129 char *status_msg;
130 char *priority;
131 uint16_t port;
132 int features;
133 int counter;
134 int job_done;
135 unsigned int flags;
136 apr_queue_t *queue;
137 apr_queue_t *retry_queue;
138 apr_hash_t *sessions;
139 apr_hash_t *retry_hash;
140 apr_hash_t *probe_hash;
141 apr_hash_t *sub_hash;
142 apr_thread_mutex_t *lock;
143 apr_thread_mutex_t *flag_mutex;
144 ldl_loop_callback_t loop_callback;
145 ldl_session_callback_t session_callback;
146 ldl_response_callback_t response_callback;
147 apr_pool_t *pool;
148 void *private_info;
149 FILE *log_stream;
150 ldl_handle_state_t state;
151 int fail_count;
152 };
153
154 struct ldl_session {
155 ldl_state_t state;
156 ldl_handle_t *handle;
157 char *id;
158 char *initiator;
159 char *them;
160 char *ip;
161 char *login;
162 ldl_payload_t payloads[LDL_MAX_PAYLOADS];
163 unsigned int payload_len;
164 /*! \brief Transport candidates, organized per type */
165 ldl_candidate_t candidates[LDL_TPORT_MAX][LDL_MAX_CANDIDATES];
166 /*! \brief Length of the candidate list, per transport type */
167 unsigned int candidate_len[LDL_TPORT_MAX];
168 apr_pool_t *pool;
169 apr_hash_t *variables;
170 apr_time_t created;
171 void *private_data;
172 ldl_user_flag_t flags;
173 };
174
175 static int on_disco_default(void *user_data, ikspak *pak);
176 static int on_vcard(void *user_data, ikspak *pak);
177 typedef int (*iks_filter_callback_t)(void *user_data, ikspak *pak);
178
179 struct ldl_feature {
180 const char *name;
181 iks_filter_callback_t callback;
182 };
183 typedef struct ldl_feature ldl_feature_t;
184
185 #define FEATURE_DISCO "http://jabber.org/protocol/disco"
186 #define FEATURE_DISCO_INFO "http://jabber.org/protocol/disco#info"
187 #define FEATURE_VERSION "jabber:iq:version"
188 #define FEATURE_VCARD "vcard-temp"
189 #define FEATURE_VOICE "http://www.google.com/xmpp/protocol/voice/v1"
190 #define FEATURE_VIDEO "http://www.google.com/xmpp/protocol/video/v1"
191 #define FEATURE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1"
192 #define FEATURE_LAST "jabber:iq:last"
193
194 static ldl_feature_t FEATURES[] = {
195 { FEATURE_DISCO, on_disco_default },
196 { FEATURE_DISCO_INFO, on_disco_default },
197 { FEATURE_VERSION, on_disco_default },
198 { FEATURE_VCARD, on_vcard},
199 { FEATURE_VOICE, on_disco_default },
200 { FEATURE_VIDEO, on_disco_default },
201 { FEATURE_CAMERA, on_disco_default },
202 { FEATURE_LAST, on_disco_default },
203 { NULL, NULL}
204 };
205
206
207 struct ldl_avatar {
208 char *path;
209 char *base64;
210 char hash[256];
211 };
212
213 typedef struct ldl_avatar ldl_avatar_t;
214
215
lowercase(char * str)216 static void lowercase(char *str)
217 {
218 size_t x = 0;
219
220 if (str) {
221 for (x = 0; x < strlen(str); x++) {
222 str[x] = (char)tolower((int)str[x]);
223 }
224 }
225 }
226
cut_path(char * in)227 static char *cut_path(char *in)
228 {
229 char *p, *ret = in;
230 char delims[] = "/\\";
231 char *i;
232
233 for (i = delims; *i; i++) {
234 p = in;
235 while ((p = strchr(p, *i)) != 0) {
236 ret = ++p;
237 }
238 }
239 return ret;
240 }
241
default_logger(char * file,const char * func,int line,int level,char * fmt,...)242 static void default_logger(char *file, const char *func, int line, int level, char *fmt, ...)
243 {
244 char *fp;
245 char data[1024];
246
247 va_list ap;
248
249 fp = cut_path(file);
250
251 va_start(ap, fmt);
252
253 vsnprintf(data, sizeof(data), fmt, ap);
254
255 fprintf(globals.log_stream, "%s:%d %s() %s", fp, line, func, data);
256
257 va_end(ap);
258
259 }
260
next_id(void)261 static unsigned int next_id(void)
262 {
263 return globals.id++;
264 }
265
iks_name_nons(iks * x)266 static char *iks_name_nons(iks *x)
267 {
268 char *r = iks_name(x);
269 char *p;
270
271 if (r && (p = strchr(r, ':'))) {
272 r = p + 1;
273 }
274
275 return r;
276 }
277
278
ldl_session_get_value(ldl_session_t * session,char * key)279 char *ldl_session_get_value(ldl_session_t *session, char *key)
280 {
281 return apr_hash_get(session->variables, key, APR_HASH_KEY_STRING);
282 }
283
ldl_session_set_value(ldl_session_t * session,const char * key,const char * val)284 void ldl_session_set_value(ldl_session_t *session, const char *key, const char *val)
285 {
286 apr_hash_set(session->variables, apr_pstrdup(session->pool, key), APR_HASH_KEY_STRING, apr_pstrdup(session->pool, val));
287 }
288
ldl_session_get_id(ldl_session_t * session)289 char *ldl_session_get_id(ldl_session_t *session)
290 {
291 return session->id;
292 }
293
ldl_session_send_msg(ldl_session_t * session,char * subject,char * body)294 void ldl_session_send_msg(ldl_session_t *session, char *subject, char *body)
295 {
296 ldl_handle_send_msg(session->handle, session->login, session->them, subject, body);
297 }
298
ldl_session_destroy(ldl_session_t ** session_p)299 ldl_status ldl_session_destroy(ldl_session_t **session_p)
300 {
301 ldl_session_t *session = *session_p;
302
303 if (session) {
304 apr_pool_t *pool = session->pool;
305 apr_hash_t *hash = session->handle->sessions;
306
307 if (globals.debug) {
308 globals.logger(DL_LOG_CRIT, "Destroyed Session %s\n", session->id);
309 }
310
311 if (session->id) {
312 apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
313 }
314
315 if (session->them) {
316 apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
317 }
318
319 apr_pool_destroy(pool);
320 pool = NULL;
321 *session_p = NULL;
322 return LDL_STATUS_SUCCESS;
323 }
324
325 return LDL_STATUS_FALSE;
326 }
327
328
ldl_session_create(ldl_session_t ** session_p,ldl_handle_t * handle,char * id,char * them,char * me,ldl_user_flag_t flags)329 ldl_status ldl_session_create(ldl_session_t **session_p, ldl_handle_t *handle, char *id, char *them, char *me, ldl_user_flag_t flags)
330 {
331 ldl_session_t *session = NULL;
332
333 if (!(session = apr_palloc(handle->pool, sizeof(ldl_session_t)))) {
334 globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
335 *session_p = NULL;
336 return LDL_STATUS_MEMERR;
337 }
338 memset(session, 0, sizeof(ldl_session_t));
339 apr_pool_create(&session->pool, globals.memory_pool);
340 session->id = apr_pstrdup(session->pool, id);
341 session->them = apr_pstrdup(session->pool, them);
342
343 if (flags & LDL_FLAG_OUTBOUND) {
344 session->initiator = apr_pstrdup(session->pool, me);
345 }
346
347 if (ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
348 session->login = apr_pstrdup(session->pool, me);
349 } else {
350 session->login = apr_pstrdup(session->pool, handle->login);
351 }
352
353 apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session);
354 apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session);
355 session->handle = handle;
356 session->created = apr_time_now();
357 session->state = LDL_STATE_NEW;
358 session->variables = apr_hash_make(session->pool);
359 session->flags = flags;
360 *session_p = session;
361
362
363 if (globals.debug) {
364 globals.logger(DL_LOG_CRIT, "Created Session %s\n", id);
365 }
366
367 return LDL_STATUS_SUCCESS;
368 }
369
parse_session_code(ldl_handle_t * handle,char * id,char * from,char * to,iks * xml,char * xtype)370 static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, char *to, iks *xml, char *xtype)
371 {
372 ldl_session_t *session = NULL;
373 ldl_signal_t dl_signal = LDL_SIGNAL_NONE;
374 char *initiator = iks_find_attrib(xml, "initiator");
375 char *msg = NULL;
376
377 if (!(session = apr_hash_get(handle->sessions, id, APR_HASH_KEY_STRING))) {
378 ldl_session_create(&session, handle, id, from, to, LDL_FLAG_NONE);
379 if (!session) {
380 return LDL_STATUS_MEMERR;
381 }
382 }
383
384 if (!session) {
385 if (globals.debug) {
386 globals.logger(DL_LOG_CRIT, "Non-Existent Session %s!\n", id);
387 }
388 return LDL_STATUS_MEMERR;
389 }
390
391 if (globals.debug) {
392 globals.logger(DL_LOG_CRIT, "Message for Session %s\n", id);
393 }
394
395 while(xml) {
396 char *type = NULL;
397 iks *tag;
398
399 if (iks_type(xml) != IKS_CDATA) {
400 type = xtype ? xtype : iks_find_attrib(xml, "type");
401 }
402
403 if (type) {
404
405 if (!strcasecmp(type, "redirect")) {
406 apr_hash_t *hash = session->handle->sessions;
407 char *p = to;
408 if ((p = strchr(to, ':'))) {
409 p++;
410 } else {
411 p = to;
412 }
413
414
415 apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
416 apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
417 session->them = apr_pstrdup(session->pool, p);
418 apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session);
419 apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session);
420
421 dl_signal = LDL_SIGNAL_REDIRECT;
422 } else if (!strcasecmp(type, "initiate") || !strcasecmp(type, "accept")) {
423
424 dl_signal = LDL_SIGNAL_INITIATE;
425
426 if (!strcasecmp(type, "accept")) {
427 msg = "accept";
428 }
429 if (!session->initiator && initiator) {
430 session->initiator = apr_pstrdup(session->pool, initiator);
431 }
432 tag = iks_child (xml);
433
434 while(tag) {
435 if (!strcasecmp(iks_name_nons(tag), "description")) {
436 iks * itag = iks_child (tag);
437 while(itag) {
438 if (!strcasecmp(iks_name_nons(itag), "payload-type") && session->payload_len < LDL_MAX_PAYLOADS) {
439 char *name = iks_find_attrib(itag, "name");
440 char *id = iks_find_attrib(itag, "id");
441 char *rate = iks_find_attrib(itag, "clockrate");
442 char *ptime = iks_find_attrib(itag, "ptime");
443 if (name && id) {
444 session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name);
445 session->payloads[session->payload_len].id = atoi(id);
446 if (ptime) {
447 session->payloads[session->payload_len].ptime = atoi(ptime);
448 } else {
449 session->payloads[session->payload_len].ptime = 20;
450 }
451 if (rate) {
452 session->payloads[session->payload_len].rate = atoi(rate);
453 } else {
454 if (!strncasecmp(iks_name(itag), "vid", 3)) {
455 session->payloads[session->payload_len].rate = 90000;
456 } else {
457 session->payloads[session->payload_len].rate = 8000;
458 }
459 }
460 session->payload_len++;
461
462 if (globals.debug) {
463 globals.logger(DL_LOG_CRIT, "Add Payload [%s] id='%s'\n", name, id);
464 }
465 }
466 }
467 itag = iks_next_tag(itag);
468 }
469 }
470 tag = iks_next_tag(tag);
471 }
472 } else if (!strcasecmp(type, "transport-accept")) {
473 dl_signal = LDL_SIGNAL_TRANSPORT_ACCEPT;
474 } else if (!strcasecmp(type, "reject")) {
475 dl_signal = LDL_SIGNAL_REJECT;
476 } else if (!strcasecmp(type, "transport-info") || !strcasecmp(type, "candidates")) {
477 char *tid = iks_find_attrib(xml, "id");
478 dl_signal = LDL_SIGNAL_CANDIDATES;
479 tag = iks_child (xml);
480 id = type;
481 if (tag && !strcasecmp(iks_name_nons(tag), "transport")) {
482 tag = iks_child(tag);
483 }
484
485 for (;tag;tag = iks_next_tag(tag)) {
486 if (!strcasecmp(iks_name_nons(tag), "info_element")) {
487 char *name = iks_find_attrib(tag, "name");
488 char *value = iks_find_attrib(tag, "value");
489 if (globals.debug) {
490 globals.logger(DL_LOG_CRIT, "Info Element [%s]=[%s]\n", name, value);
491 }
492 ldl_session_set_value(session, name, value);
493
494 } else if (!strcasecmp(iks_name_nons(tag), "candidate") /*&& session->candidate_len < LDL_MAX_CANDIDATES*/) {
495 char *key;
496 double pref = 0.0;
497 int index = -1;
498 ldl_transport_type_t tport;
499 unsigned int *candidate_len = NULL;
500 ldl_candidate_t (*candidates)[LDL_MAX_CANDIDATES] = NULL;
501
502 if (!(key = iks_find_attrib(tag, "preference"))) {
503 globals.logger(DL_LOG_WARNING, "Field preference was not set\n");
504 continue;
505 } else {
506 unsigned int x;
507
508 pref = strtod(key, NULL);
509
510 /* Check what kind of candidate this is */
511 if ((key = iks_find_attrib(tag, "name")) && ((tport = ldl_transport_type_parse(key)) != LDL_TPORT_MAX)) {
512 candidates = &(session->candidates[tport]);
513 candidate_len = &(session->candidate_len[tport]);
514 } else {
515 globals.logger(DL_LOG_WARNING, "No such transport type: %s\n", key);
516 continue;
517 }
518
519 if (*candidate_len >= LDL_MAX_CANDIDATES) {
520 globals.logger(DL_LOG_WARNING, "Too many %s candidates\n", key);
521 continue;
522 }
523
524 for (x = 0; x < *candidate_len; x++) {
525 if ((*candidates)[x].pref == pref) {
526 if (globals.debug) {
527 globals.logger(DL_LOG_CRIT, "Duplicate Pref! Updating...\n");
528 }
529 index = x;
530 break;
531 }
532 }
533 }
534
535 if (index < 0) {
536 index = (*candidate_len)++;
537 }
538
539 (*candidates)[index].pref = pref;
540
541 if (tid) {
542 (*candidates)[index].tid = apr_pstrdup(session->pool, tid);
543 }
544
545 if ((key = iks_find_attrib(tag, "name"))) {
546 (*candidates)[index].name = apr_pstrdup(session->pool, key);
547 }
548 if ((key = iks_find_attrib(tag, "type"))) {
549 (*candidates)[index].type = apr_pstrdup(session->pool, key);
550 }
551 if ((key = iks_find_attrib(tag, "protocol"))) {
552 (*candidates)[index].protocol = apr_pstrdup(session->pool, key);
553 }
554 if ((key = iks_find_attrib(tag, "username"))) {
555 (*candidates)[index].username = apr_pstrdup(session->pool, key);
556 }
557 if ((key = iks_find_attrib(tag, "password"))) {
558 (*candidates)[index].password = apr_pstrdup(session->pool, key);
559 }
560 if ((key = iks_find_attrib(tag, "address"))) {
561 (*candidates)[index].address = apr_pstrdup(session->pool, key);
562 }
563 if ((key = iks_find_attrib(tag, "port"))) {
564 (*candidates)[index].port = (uint16_t)atoi(key);
565 }
566
567 if (!(*candidates)[index].type) {
568 (*candidates)[index].type = apr_pstrdup(session->pool, "stun");
569 }
570
571
572 if (globals.debug) {
573 globals.logger(DL_LOG_CRIT,
574 "New Candidate %d\n"
575 "name=%s\n"
576 "type=%s\n"
577 "protocol=%s\n"
578 "username=%s\n"
579 "password=%s\n"
580 "address=%s\n"
581 "port=%d\n"
582 "pref=%0.2f\n",
583 *candidate_len,
584 (*candidates)[index].name,
585 (*candidates)[index].type,
586 (*candidates)[index].protocol,
587 (*candidates)[index].username,
588 (*candidates)[index].password,
589 (*candidates)[index].address,
590 (*candidates)[index].port,
591 (*candidates)[index].pref
592 );
593 }
594 }
595 }
596 } else if (!strcasecmp(type, "terminate")) {
597 dl_signal = LDL_SIGNAL_TERMINATE;
598 } else if (!strcasecmp(type, "error")) {
599 dl_signal = LDL_SIGNAL_ERROR;
600 }
601 }
602
603 xml = iks_child(xml);
604 }
605
606 if (handle->session_callback && dl_signal) {
607 handle->session_callback(handle, session, dl_signal, to, from, id, msg);
608 }
609
610 return LDL_STATUS_SUCCESS;
611 }
612
613
parse_jingle_code(ldl_handle_t * handle,iks * xml,char * to,char * from,char * type)614 static ldl_status parse_jingle_code(ldl_handle_t *handle, iks *xml, char *to, char *from, char *type)
615 {
616 ldl_session_t *session = NULL;
617 ldl_signal_t dl_signal = LDL_SIGNAL_NONE;
618 char *initiator = iks_find_attrib(xml, "initiator");
619 char *msg = NULL;
620 char *id = iks_find_attrib(xml, "sid");
621 char *action = iks_find_attrib(xml, "action");
622 iks *tag;
623
624
625 if (!strcasecmp(type, "error")) {
626 action = type;
627 }
628
629
630 if (!(id && action && from)) {
631 globals.logger(DL_LOG_CRIT, "missing required params\n");
632 return LDL_STATUS_FALSE;
633 }
634
635 if (!(session = apr_hash_get(handle->sessions, id, APR_HASH_KEY_STRING))) {
636 ldl_session_create(&session, handle, id, from, to, LDL_FLAG_NONE);
637 if (!session) {
638 return LDL_STATUS_MEMERR;
639 }
640 }
641
642 if (!session) {
643 if (globals.debug) {
644 globals.logger(DL_LOG_CRIT, "Non-Existent Session %s!\n", id);
645 }
646 return LDL_STATUS_MEMERR;
647 }
648
649 if (globals.debug) {
650 globals.logger(DL_LOG_CRIT, "Message for Session %s\n", id);
651 }
652
653
654 if (action) {
655
656 if (!strcasecmp(action, "redirect")) {
657 apr_hash_t *hash = session->handle->sessions;
658 char *p = to;
659 if ((p = strchr(to, ':'))) {
660 p++;
661 } else {
662 p = to;
663 }
664
665
666 apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
667 apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
668 session->them = apr_pstrdup(session->pool, p);
669 apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session);
670 apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session);
671
672 dl_signal = LDL_SIGNAL_REDIRECT;
673 } else if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "session-accept")) {
674
675 dl_signal = LDL_SIGNAL_INITIATE;
676
677 if (!strcasecmp(action, "session-accept")) {
678 msg = "accept";
679 }
680
681 if (!session->initiator && initiator) {
682 session->initiator = apr_pstrdup(session->pool, initiator);
683 }
684 tag = iks_child (xml);
685
686 while(tag) {
687
688 if (!strcasecmp(iks_name_nons(tag), "content")) {
689 iks *dtag = iks_child (tag);
690 char key[512];
691
692 if (!strcasecmp(iks_name_nons(dtag), "description")) {
693 iks *itag = iks_child (dtag);
694 char *name = iks_find_attrib(tag, "name");
695 char *media = iks_find_attrib(dtag, "media");
696
697 if (globals.debug) {
698 globals.logger(DL_LOG_CRIT, "Found description of type '%s' media type '%s'\n", name, media);
699
700 }
701
702 while(itag) {
703 if (!strcasecmp(iks_name_nons(itag), "rtcp-mux")) {
704 snprintf(key, sizeof(key), "%s:rtcp-mux", media);
705 ldl_session_set_value(session, key, "true");
706 }
707
708 if (!strcasecmp(iks_name_nons(itag), "encryption")) {
709 iks *etag = iks_child (itag);
710
711 while(etag) {
712 char *suite = iks_find_attrib(etag, "crypto-suite");
713 char *params = iks_find_attrib(etag, "key-params");
714 char *tag = iks_find_attrib(etag, "tag");
715 char val[512];
716
717 if (suite && params && tag) {
718 snprintf(key, sizeof(key), "%s:crypto:%s", media, tag);
719 snprintf(val, sizeof(val), "%s %s %s", tag, suite, params);
720
721 ldl_session_set_value(session, key, val);
722 }
723
724 etag = iks_next_tag(etag);
725 }
726 }
727
728
729 if (!strcasecmp(iks_name_nons(itag), "payload-type") && session->payload_len < LDL_MAX_PAYLOADS) {
730 char *name = iks_find_attrib(itag, "name");
731 char *id = iks_find_attrib(itag, "id");
732 char *rate = iks_find_attrib(itag, "clockrate");
733
734 if (name && id) {
735 session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name);
736 session->payloads[session->payload_len].id = atoi(id);
737 if (rate) {
738 session->payloads[session->payload_len].rate = atoi(rate);
739 } else {
740 if (!strcasecmp(media, "video")) {
741 session->payloads[session->payload_len].rate = 90000;
742 } else {
743 session->payloads[session->payload_len].rate = 8000;
744 }
745 }
746 session->payload_len++;
747
748 if (globals.debug) {
749 globals.logger(DL_LOG_CRIT, "Add Payload [%s] id='%s'\n", name, id);
750 }
751 }
752 }
753 itag = iks_next_tag(itag);
754 }
755
756 }
757 }
758
759 tag = iks_next_tag(tag);
760 }
761 } else if (!strcasecmp(action, "transport-accept")) {
762 dl_signal = LDL_SIGNAL_TRANSPORT_ACCEPT;
763 } else if (!strcasecmp(action, "reject")) {
764 dl_signal = LDL_SIGNAL_REJECT;
765 } else if (!strcasecmp(action, "transport-info")) {
766
767 tag = iks_child (xml);
768
769 while(tag) {
770
771 if (!strcasecmp(iks_name_nons(tag), "content")) {
772 iks *ttag = iks_child (tag);
773
774 dl_signal = LDL_SIGNAL_CANDIDATES;
775
776 id = action;
777
778 if (ttag && !strcasecmp(iks_name_nons(ttag), "transport")) {
779 ttag = iks_child(ttag);
780 }
781
782 for (;ttag;ttag = iks_next_tag(ttag)) {
783 if (!strcasecmp(iks_name_nons(ttag), "info_element")) {
784 char *name = iks_find_attrib(ttag, "name");
785 char *value = iks_find_attrib(ttag, "value");
786 if (globals.debug) {
787 globals.logger(DL_LOG_CRIT, "Info Element [%s]=[%s]\n", name, value);
788 }
789 ldl_session_set_value(session, name, value);
790
791 } else if (!strcasecmp(iks_name_nons(ttag), "candidate")) {
792 char *key;
793 double pref = 0.0;
794 int index = -1;
795 ldl_transport_type_t tport;
796 unsigned int *candidate_len = NULL;
797 ldl_candidate_t (*candidates)[LDL_MAX_CANDIDATES] = NULL;
798
799 if ((key = iks_find_attrib(ttag, "preference"))) {
800 unsigned int x;
801
802 pref = strtod(key, NULL);
803
804 /* Check what kind of candidate this is */
805 if ((key = iks_find_attrib(ttag, "name")) && ((tport = ldl_transport_type_parse(key)) != LDL_TPORT_MAX)) {
806 candidates = &(session->candidates[tport]);
807 candidate_len = &(session->candidate_len[tport]);
808 } else {
809 globals.logger(DL_LOG_WARNING, "No such transport type: %s\n", key);
810 continue;
811 }
812
813 if (*candidate_len >= LDL_MAX_CANDIDATES) {
814 globals.logger(DL_LOG_WARNING, "Too many %s candidates\n", key);
815 continue;
816 }
817
818 for (x = 0; x < *candidate_len; x++) {
819 if ((*candidates)[x].pref == pref) {
820 if (globals.debug) {
821 globals.logger(DL_LOG_CRIT, "Duplicate Pref!\n");
822 }
823 index = x;
824 break;
825 }
826 }
827 } else {
828 globals.logger(DL_LOG_WARNING, "No preference specified");
829 continue;
830 }
831
832 if (index < 0) {
833 index = (*candidate_len)++;
834 }
835
836 (*candidates)[index].pref = pref;
837
838 if ((key = iks_find_attrib(ttag, "name"))) {
839 (*candidates)[index].name = apr_pstrdup(session->pool, key);
840 }
841 if ((key = iks_find_attrib(ttag, "type"))) {
842 (*candidates)[index].type = apr_pstrdup(session->pool, key);
843 }
844 if ((key = iks_find_attrib(ttag, "protocol"))) {
845 (*candidates)[index].protocol = apr_pstrdup(session->pool, key);
846 }
847 if ((key = iks_find_attrib(ttag, "username"))) {
848 (*candidates)[index].username = apr_pstrdup(session->pool, key);
849 }
850 if ((key = iks_find_attrib(ttag, "password"))) {
851 (*candidates)[index].password = apr_pstrdup(session->pool, key);
852 }
853 if ((key = iks_find_attrib(ttag, "address"))) {
854 (*candidates)[index].address = apr_pstrdup(session->pool, key);
855 }
856 if ((key = iks_find_attrib(ttag, "port"))) {
857 (*candidates)[index].port = (uint16_t)atoi(key);
858 }
859
860 if (!(*candidates)[index].type) {
861 (*candidates)[index].type = apr_pstrdup(session->pool, "stun");
862 }
863
864
865 if (globals.debug) {
866 globals.logger(DL_LOG_CRIT,
867 "New Candidate %d\n"
868 "name=%s\n"
869 "type=%s\n"
870 "protocol=%s\n"
871 "username=%s\n"
872 "password=%s\n"
873 "address=%s\n"
874 "port=%d\n"
875 "pref=%0.2f\n",
876 *candidate_len,
877 (*candidates)[index].name,
878 (*candidates)[index].type,
879 (*candidates)[index].protocol,
880 (*candidates)[index].username,
881 (*candidates)[index].password,
882 (*candidates)[index].address,
883 (*candidates)[index].port,
884 (*candidates)[index].pref
885 );
886 }
887 }
888 }
889 }
890
891 tag = iks_next_tag(tag);
892 }
893 } else if (!strcasecmp(action, "session-terminate")) {
894 dl_signal = LDL_SIGNAL_TERMINATE;
895 } else if (!strcasecmp(action, "error")) {
896 dl_signal = LDL_SIGNAL_ERROR;
897 }
898 }
899
900
901
902 if (handle->session_callback && dl_signal) {
903 handle->session_callback(handle, session, dl_signal, to, from, id, msg);
904 }
905
906 return LDL_STATUS_SUCCESS;
907 }
908
909
910
911 const char *marker = "TRUE";
912
913
on_vcard(void * user_data,ikspak * pak)914 static int on_vcard(void *user_data, ikspak *pak)
915 {
916 ldl_handle_t *handle = user_data;
917 char *from = iks_find_attrib(pak->x, "from");
918 char *to = iks_find_attrib(pak->x, "to");
919
920 if (handle->session_callback) {
921 handle->session_callback(handle, NULL, LDL_SIGNAL_VCARD, to, from, pak->id, NULL);
922 }
923
924 return IKS_FILTER_EAT;
925 }
926
927
on_disco_default(void * user_data,ikspak * pak)928 static int on_disco_default(void *user_data, ikspak *pak)
929 {
930 char *node = NULL;
931 char *ns = NULL;
932 ldl_handle_t *handle = user_data;
933 iks *iq = NULL, *query, *tag;
934 uint8_t send = 0;
935 int x;
936
937 if (pak && pak->query) {
938 ns = iks_find_attrib(pak->query, "xmlns");
939 node = iks_find_attrib(pak->query, "node");
940 }
941
942 if (pak && pak->subtype == IKS_TYPE_RESULT) {
943 globals.logger(DL_LOG_CRIT, "FixME!!! node=[%s]\n", node?node:"");
944 } else if (pak && pak->subtype == IKS_TYPE_GET) {
945 if (ns && (iq = iks_new("iq"))) {
946 int all = 0;
947
948 iks_insert_attrib(iq, "from", handle->login);
949 if (pak->from) {
950 iks_insert_attrib(iq, "to", pak->from->full);
951 }
952 iks_insert_attrib(iq, "id", pak->id);
953 iks_insert_attrib(iq, "type", "result");
954
955 if (!(query = iks_insert (iq, "query"))) {
956 goto fail;
957 }
958 iks_insert_attrib(query, "xmlns", ns);
959
960 if (!strcasecmp(ns, FEATURE_LAST)) {
961 iks_insert_attrib(query, "seconds", "1");
962 }
963
964 if (!(tag = iks_insert (query, "identity"))) {
965 goto fail;
966 }
967
968 iks_insert_attrib(tag, "category", "gateway");
969 //iks_insert_attrib(tag, "type", "voice");
970 iks_insert_attrib(tag, "name", "LibDingaLing");
971
972 if (!strcasecmp(ns, FEATURE_DISCO_INFO)) {
973 if (!node) {
974 all++;
975 } else {
976 char *p;
977
978 if ((p = strstr(node, "caps#"))) {
979 char *what = p + 5;
980
981 if (!strcasecmp(what, "voice-v1")) {
982 if (!(tag = iks_insert (query, "feature"))) {
983 goto fail;
984 }
985 iks_insert_attrib(tag, "var", FEATURE_VOICE);
986 goto done;
987 }
988
989 }
990 }
991 }
992
993 for (x = 0; FEATURES[x].name; x++) {
994 if (all || !ns || !strcasecmp(ns, FEATURES[x].name)) {
995 if (!(tag = iks_insert (query, "feature"))) {
996 goto fail;
997 }
998 iks_insert_attrib(tag, "var", FEATURES[x].name);
999 }
1000 }
1001
1002 done:
1003
1004 apr_queue_push(handle->queue, iq);
1005 iq = NULL;
1006 send = 1;
1007 }
1008 fail:
1009
1010 if (iq) {
1011 iks_delete(iq);
1012 }
1013
1014 if (!send) {
1015 globals.logger(DL_LOG_CRIT, "Memory Error!\n");
1016 }
1017 }
1018
1019 return IKS_FILTER_EAT;
1020 }
1021
on_presence(void * user_data,ikspak * pak)1022 static int on_presence(void *user_data, ikspak *pak)
1023 {
1024 ldl_handle_t *handle = user_data;
1025 char *from = iks_find_attrib(pak->x, "from");
1026 char *to = iks_find_attrib(pak->x, "to");
1027 char *type = iks_find_attrib(pak->x, "type");
1028 char *show = iks_find_cdata(pak->x, "show");
1029 char *status = iks_find_cdata(pak->x, "status");
1030 char id[1024];
1031 char *resource;
1032 struct ldl_buffer *buffer;
1033 ldl_signal_t dl_signal = LDL_SIGNAL_PRESENCE_IN;
1034 int done = 0;
1035
1036
1037 if (type && *type) {
1038 if (!strcasecmp(type, "unavailable")) {
1039 dl_signal = LDL_SIGNAL_PRESENCE_OUT;
1040 } else if (!strcasecmp(type, "probe")) {
1041 dl_signal = LDL_SIGNAL_PRESENCE_PROBE;
1042 }
1043 if (!status) {
1044 status = type;
1045 }
1046 } else {
1047 if (!status) {
1048 status = "Available";
1049 }
1050 }
1051
1052
1053 apr_cpystrn(id, from, sizeof(id));
1054 lowercase(id);
1055
1056 if ((resource = strchr(id, '/'))) {
1057 *resource++ = '\0';
1058 }
1059
1060
1061 if (!apr_hash_get(handle->sub_hash, from, APR_HASH_KEY_STRING)) {
1062 iks *msg;
1063 apr_hash_set(handle->sub_hash, apr_pstrdup(handle->pool, from), APR_HASH_KEY_STRING, &marker);
1064 if ((msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, id, "Ding A Ling...."))) {
1065 apr_queue_push(handle->queue, msg);
1066 msg = NULL;
1067 }
1068 }
1069
1070 if (resource && (strstr(resource, "talk") || strstr(resource, "telepathy")) && (buffer = apr_hash_get(handle->probe_hash, id, APR_HASH_KEY_STRING))) {
1071 apr_cpystrn(buffer->buf, from, buffer->len);
1072 buffer->hit = 1;
1073 done = 1;
1074 }
1075
1076 if (!done) {
1077 iks *xml = iks_find(pak->x, "c");
1078 if (!xml) {
1079 xml = iks_find(pak->x, "caps:c");
1080 }
1081
1082 if (xml) {
1083 char *ext = iks_find_attrib(xml, "ext");;
1084 if (ext && strstr(ext, "voice-v1") && (buffer = apr_hash_get(handle->probe_hash, id, APR_HASH_KEY_STRING))) {
1085 apr_cpystrn(buffer->buf, from, buffer->len);
1086 buffer->hit = 1;
1087 }
1088 }
1089 }
1090
1091
1092 if (handle->session_callback) {
1093 handle->session_callback(handle, NULL, dl_signal, to, id, status ? status : "n/a", show ? show : "n/a");
1094 }
1095
1096 return IKS_FILTER_EAT;
1097 }
1098
ldl_handle_strdup(ldl_handle_t * handle,char * str)1099 static char *ldl_handle_strdup(ldl_handle_t *handle, char *str)
1100 {
1101 char *dup;
1102 apr_size_t len;
1103
1104 len = strlen(str) + 1;
1105 dup = apr_palloc(handle->pool, len);
1106 assert(dup != NULL);
1107 strncpy(dup, str, len);
1108 return dup;
1109 }
1110
ldl_strip_resource(char * in)1111 static void ldl_strip_resource(char *in)
1112 {
1113 char *p;
1114
1115 if ((p = strchr(in, '/'))) {
1116 *p = '\0';
1117 }
1118 }
1119
ldl_get_avatar(ldl_handle_t * handle,char * path,char * from)1120 static ldl_avatar_t *ldl_get_avatar(ldl_handle_t *handle, char *path, char *from)
1121 {
1122 ldl_avatar_t *ap;
1123 uint8_t image[8192];
1124 unsigned char base64[9216] = "";
1125 int fd = -1;
1126 size_t bytes;
1127 char *key;
1128 //char hash[128] = "";
1129
1130 if (from && (ap = (ldl_avatar_t *) apr_hash_get(globals.avatar_hash, from, APR_HASH_KEY_STRING))) {
1131 return ap;
1132 }
1133
1134 if (path && from) {
1135 if ((ap = (ldl_avatar_t *) apr_hash_get(globals.avatar_hash, path, APR_HASH_KEY_STRING))) {
1136 key = ldl_handle_strdup(handle, from);
1137 ldl_strip_resource(key);
1138 apr_hash_set(globals.avatar_hash, key, APR_HASH_KEY_STRING, ap);
1139 return ap;
1140 }
1141 }
1142
1143 if (!(path && from)) {
1144 return NULL;
1145 }
1146
1147 if ((fd = open(path, O_RDONLY, 0)) < 0) {
1148 globals.logger(DL_LOG_ERR, "File %s does not exist!\n", path);
1149 return NULL;
1150 }
1151
1152 bytes = read(fd, image, sizeof(image));
1153 close(fd);
1154
1155 ap = malloc(sizeof(*ap));
1156 assert(ap != NULL);
1157 memset(ap, 0, sizeof(*ap));
1158 sha1_hash(ap->hash, (unsigned char *) image, (unsigned int)bytes);
1159 ap->path = strdup(path);
1160
1161 key = ldl_handle_strdup(handle, from);
1162 ldl_strip_resource(key);
1163
1164 b64encode((unsigned char *)image, bytes, base64, sizeof(base64));
1165 ap->base64 = strdup((const char *)base64);
1166 apr_hash_set(globals.avatar_hash, ap->path, APR_HASH_KEY_STRING, ap);
1167 apr_hash_set(globals.avatar_hash, key, APR_HASH_KEY_STRING, ap);
1168 return ap;
1169 }
1170
1171
do_presence(ldl_handle_t * handle,char * from,char * to,char * type,char * rpid,char * message,char * avatar)1172 static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message, char *avatar)
1173 {
1174 iks *pres;
1175 char buf[512];
1176 iks *tag;
1177
1178 if (from && !strchr(from, '/')) {
1179 snprintf(buf, sizeof(buf), "%s/talk", from);
1180 from = buf;
1181 }
1182
1183 if (ldl_test_flag(handle, LDL_FLAG_COMPONENT) && from && to && ldl_jid_domcmp(from, to)) {
1184 globals.logger(DL_LOG_ERR, "Refusal to send presence from and to the same domain in component mode [%s][%s]\n", from, to);
1185 return;
1186 }
1187
1188 if ((pres = iks_new("presence"))) {
1189 iks_insert_attrib(pres, "xmlns", "jabber:client");
1190 if (from) {
1191 iks_insert_attrib(pres, "from", from);
1192 }
1193 if (to) {
1194 iks_insert_attrib(pres, "to", to);
1195 }
1196 if (type) {
1197 iks_insert_attrib(pres, "type", type);
1198 }
1199
1200 if (rpid) {
1201 if ((tag = iks_insert (pres, "show"))) {
1202 iks_insert_cdata(tag, rpid, 0);
1203 }
1204 }
1205
1206 if (message) {
1207 if ((tag = iks_insert (pres, "status"))) {
1208 iks_insert_cdata(tag, message, 0);
1209 }
1210 }
1211
1212 if (message || rpid) {
1213 ldl_avatar_t *ap;
1214
1215 if (avatar) {
1216 if ((ap = ldl_get_avatar(handle, avatar, from))) {
1217 if ((tag = iks_insert(pres, "x"))) {
1218 iks *hash;
1219 iks_insert_attrib(tag, "xmlns", "vcard-temp:x:update");
1220 if ((hash = iks_insert(tag, "photo"))) {
1221 iks_insert_cdata(hash, ap->hash, 0);
1222 }
1223 }
1224 }
1225 }
1226
1227 if ((tag = iks_insert(pres, "c"))) {
1228 iks_insert_attrib(tag, "node", "http://www.freeswitch.org/xmpp/client/caps");
1229 iks_insert_attrib(tag, "ver", LDL_CAPS_VER);
1230 iks_insert_attrib(tag, "ext", "sidebar voice-v1 video-v1 camera-v1");
1231 iks_insert_attrib(tag, "client", "libdingaling");
1232 iks_insert_attrib(tag, "xmlns", "http://jabber.org/protocol/caps");
1233 }
1234 }
1235
1236 apr_queue_push(handle->queue, pres);
1237 pres = NULL;
1238 }
1239 }
1240
do_roster(ldl_handle_t * handle)1241 static void do_roster(ldl_handle_t *handle)
1242 {
1243 if (handle->session_callback) {
1244 handle->session_callback(handle, NULL, LDL_SIGNAL_ROSTER, NULL, handle->login, NULL, NULL);
1245 }
1246 }
1247
on_unsubscribe(void * user_data,ikspak * pak)1248 static int on_unsubscribe(void *user_data, ikspak *pak)
1249 {
1250 ldl_handle_t *handle = user_data;
1251 char *from = iks_find_attrib(pak->x, "from");
1252 char *to = iks_find_attrib(pak->x, "to");
1253
1254 if (handle->session_callback) {
1255 handle->session_callback(handle, NULL, LDL_SIGNAL_UNSUBSCRIBE, to, from, NULL, NULL);
1256 }
1257
1258 return IKS_FILTER_EAT;
1259 }
1260
on_subscribe(void * user_data,ikspak * pak)1261 static int on_subscribe(void *user_data, ikspak *pak)
1262 {
1263 ldl_handle_t *handle = user_data;
1264 char *from = iks_find_attrib(pak->x, "from");
1265 char *to = iks_find_attrib(pak->x, "to");
1266 iks *msg = NULL;
1267 char *id = strdup(from);
1268 char *r;
1269
1270 if (!id) {
1271 return -1;
1272 }
1273 if ((r = strchr(from, '/'))) {
1274 *r++ = '\0';
1275 }
1276
1277 if ((msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, id, "Ding A Ling...."))) {
1278 if (to && ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1279 iks_insert_attrib(msg, "from", to);
1280 }
1281
1282 apr_queue_push(handle->queue, msg);
1283 msg = NULL;
1284 }
1285
1286 if ((msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, "Ding A Ling...."))) {
1287
1288 if (to && ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1289 iks_insert_attrib(msg, "from", to);
1290 }
1291
1292 apr_queue_push(handle->queue, msg);
1293 msg = NULL;
1294 }
1295
1296 if (handle->session_callback) {
1297 handle->session_callback(handle, NULL, LDL_SIGNAL_SUBSCRIBE, to, from, NULL, NULL);
1298 }
1299
1300 return IKS_FILTER_EAT;
1301 }
1302
cancel_retry(ldl_handle_t * handle,char * id)1303 static void cancel_retry(ldl_handle_t *handle, char *id)
1304 {
1305 struct packet_node *packet_node;
1306
1307 apr_thread_mutex_lock(handle->lock);
1308 if ((packet_node = apr_hash_get(handle->retry_hash, id, APR_HASH_KEY_STRING))) {
1309 if (globals.debug) {
1310 globals.logger(DL_LOG_CRIT, "Cancel packet %s\n", packet_node->id);
1311 }
1312 packet_node->retries = 0;
1313 }
1314 apr_thread_mutex_unlock(handle->lock);
1315 }
1316
working_find(iks * tag,const char * name)1317 static iks* working_find(iks *tag, const char *name)
1318 {
1319 while(tag) {
1320 if (!strcasecmp(iks_name(tag), name)) {
1321 return tag;
1322 }
1323 tag = iks_next_tag(tag);
1324 }
1325
1326 return NULL;
1327 }
1328
working_find_nons(iks * tag,const char * name)1329 static iks* working_find_nons(iks *tag, const char *name)
1330 {
1331 while(tag) {
1332 char *a = iks_name(tag);
1333 char *b = (char *)name;
1334 char *p;
1335
1336 if ((p = strchr(a, ':'))) {
1337 a = p+1;
1338 }
1339
1340 if ((p = strchr(b, ':'))) {
1341 b = p+1;
1342 }
1343
1344 if (!strcasecmp(a,b)) {
1345 return tag;
1346 }
1347 tag = iks_next_tag(tag);
1348 }
1349
1350 return NULL;
1351 }
1352
on_commands(void * user_data,ikspak * pak)1353 static int on_commands(void *user_data, ikspak *pak)
1354 {
1355 ldl_handle_t *handle = user_data;
1356 char *from = iks_find_attrib(pak->x, "from");
1357 char *to = iks_find_attrib(pak->x, "to");
1358 char *iqid = iks_find_attrib(pak->x, "id");
1359 char *type = iks_find_attrib(pak->x, "type");
1360 uint8_t is_result = strcasecmp(type, "result") ? 0 : 1;
1361 uint8_t is_error = strcasecmp(type, "error") ? 0 : 1;
1362 iks *xml, *xsession, *xerror = NULL, *xredir = NULL;
1363 iks *xjingle;
1364
1365
1366 xml = iks_child (pak->x);
1367
1368 if (is_error) {
1369 if ((xerror = working_find(xml, "error"))) {
1370 char *code = iks_find_attrib(xerror, "code");
1371 if (code && !strcmp(code, "302") &&
1372 ((xredir = iks_find(xerror, "ses:redirect")) || (xredir = iks_find(xerror, "redirect")))) {
1373 is_result = 0;
1374 is_error = 0;
1375 cancel_retry(handle, iqid);
1376 }
1377 }
1378 }
1379
1380
1381 if (is_result) {
1382 iks *tag = iks_child (pak->x);
1383 while(tag) {
1384 if (!strcasecmp(iks_name_nons(tag), "bind")) {
1385 char *jid = iks_find_cdata(tag, "jid");
1386 char *resource = strchr(jid, '/');
1387 if (resource) {
1388 resource++;
1389 handle->acc->resource = apr_pstrdup(handle->pool, resource);
1390 }
1391 handle->login = apr_pstrdup(handle->pool, jid);
1392 #if 0
1393 if ((iq = iks_new("iq"))) {
1394 iks_insert_attrib(iq, "type", "get");
1395 iks_insert_attrib(iq, "id", "roster");
1396 x = iks_insert(iq, "query");
1397 iks_insert_attrib(x, "xmlns", "jabber:iq:roster");
1398 iks_insert_attrib(x, "xmlns:gr", "google:roster");
1399 iks_insert_attrib(x, "gr:ext", "2");
1400 iks_insert_attrib(x, "gr:include", "all");
1401 apr_queue_push(handle->queue, iq);
1402 iq = NULL;
1403 break;
1404 }
1405 #endif
1406 }
1407 tag = iks_next_tag(tag);
1408 }
1409 }
1410
1411
1412
1413 if ((is_result || is_error) && iqid && from) {
1414
1415 cancel_retry(handle, iqid);
1416
1417 if (is_result) {
1418 if (handle->response_callback) {
1419 handle->response_callback(handle, iqid);
1420 }
1421 return IKS_FILTER_EAT;
1422 } else if (is_error) {
1423 return IKS_FILTER_EAT;
1424
1425 }
1426 }
1427
1428
1429
1430 if ((handle->flags & LDL_FLAG_JINGLE) && (xjingle = working_find_nons(xml, "jin:jingle"))) {
1431 if (parse_jingle_code(handle, xjingle, to, from, type) == LDL_STATUS_SUCCESS) {
1432 iks *reply;
1433 if ((reply = iks_make_iq(IKS_TYPE_RESULT, NULL))) {
1434 iks_insert_attrib(reply, "to", from);
1435 iks_insert_attrib(reply, "from", to);
1436 iks_insert_attrib(reply, "id", iqid);
1437 apr_queue_push(handle->queue, reply);
1438 reply = NULL;
1439 }
1440 }
1441
1442 } else if ((xsession = working_find_nons(xml, "ses:session"))) {
1443 char *id;
1444
1445 id = iks_find_attrib(xsession, "id");
1446
1447 if (xredir) {
1448 to = iks_cdata(iks_child(xredir));
1449 type = "redirect";
1450 }
1451
1452 if (strcasecmp(type, "error") && strcasecmp(type, "redirect")) {
1453 type = NULL;
1454 }
1455
1456 if (parse_session_code(handle, id, from, to, xsession, type) == LDL_STATUS_SUCCESS) {
1457 iks *reply;
1458 if ((reply = iks_make_iq(IKS_TYPE_RESULT, NULL))) {
1459 iks_insert_attrib(reply, "to", from);
1460 iks_insert_attrib(reply, "from", to);
1461 iks_insert_attrib(reply, "id", iqid);
1462 apr_queue_push(handle->queue, reply);
1463 reply = NULL;
1464 }
1465 }
1466 }
1467
1468 return IKS_FILTER_EAT;
1469 }
1470
1471
on_result(void * user_data,ikspak * pak)1472 static int on_result(void *user_data, ikspak *pak)
1473 {
1474 ldl_handle_t *handle = user_data;
1475 iks *msg, *ctag, *tag;
1476
1477 if ((msg = iks_make_pres (IKS_SHOW_AVAILABLE, handle->status_msg))) {
1478 ctag = iks_insert(msg, "c");
1479 iks_insert_attrib(ctag, "node", "http://www.freeswitch.org/xmpp/client/caps");
1480 iks_insert_attrib(ctag, "ver", "1.0.0.1");
1481 iks_insert_attrib(ctag, "ext", "sidebar voice-v1 video-v1");
1482 iks_insert_attrib(ctag, "client", "libdingaling");
1483 iks_insert_attrib(ctag, "xmlns", "http://jabber.org/protocol/caps");
1484
1485 if (handle->priority && strlen(handle->priority)) {
1486 tag = iks_insert (msg, "priority");
1487 iks_insert_cdata(tag, handle->priority, 0);
1488 }
1489
1490 apr_queue_push(handle->queue, msg);
1491 msg = NULL;
1492 }
1493 return IKS_FILTER_EAT;
1494 }
1495
1496 static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1497 #define B64BUFFLEN 1024
1498
b64encode(unsigned char * in,size_t ilen,unsigned char * out,size_t olen)1499 static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen)
1500 {
1501 int y=0,bytes=0;
1502 size_t x=0;
1503 unsigned int b=0,l=0;
1504
1505 for(x=0;x<ilen;x++) {
1506 b = (b<<8) + in[x];
1507 l += 8;
1508 while (l >= 6) {
1509 out[bytes++] = c64[(b>>(l-=6))%64];
1510 if(++y!=72) {
1511 continue;
1512 }
1513 //out[bytes++] = '\n';
1514 y=0;
1515 }
1516 }
1517
1518 if (l > 0) {
1519 out[bytes++] = c64[((b%16)<<(6-l))%64];
1520 }
1521 if (l != 0) while (l < 6) {
1522 out[bytes++] = '=', l += 2;
1523 }
1524
1525 return 0;
1526 }
1527
sha1_hash(char * out,unsigned char * in,unsigned int len)1528 static void sha1_hash(char *out, unsigned char *in, unsigned int len)
1529 {
1530 SHA1Context sha;
1531 char *p;
1532 int x;
1533 unsigned char digest[SHA1_HASH_SIZE] = "";
1534
1535 SHA1Init(&sha);
1536
1537 SHA1Update(&sha, in, len);
1538
1539 SHA1Final(&sha, digest);
1540
1541 p = out;
1542 for (x = 0; x < SHA1_HASH_SIZE; x++) {
1543 p += sprintf(p, "%2.2x", digest[x]);
1544 }
1545 }
1546
1547
on_stream_component(ldl_handle_t * handle,int type,iks * node)1548 static int on_stream_component(ldl_handle_t *handle, int type, iks *node)
1549 {
1550 ikspak *pak = NULL;
1551
1552 if (node) {
1553 pak = iks_packet(node);
1554 }
1555
1556 switch (type) {
1557 case IKS_NODE_START:
1558 if (pak && handle->state == CS_NEW) {
1559 char secret[256] = "";
1560 char hash[256] = "";
1561 char handshake[512] = "";
1562
1563 snprintf(secret, sizeof(secret), "%s%s", pak->id, handle->password);
1564 sha1_hash(hash, (unsigned char *) secret, (unsigned int)strlen(secret));
1565 snprintf(handshake, sizeof(handshake), "<handshake>%s</handshake>", hash);
1566 iks_send_raw(handle->parser, handshake);
1567 handle->state = CS_START;
1568 if (iks_recv(handle->parser, 1) == 2) {
1569 handle->state = CS_CONNECTED;
1570 if (!ldl_test_flag(handle, LDL_FLAG_AUTHORIZED)) {
1571 do_roster(handle);
1572 if (handle->session_callback) {
1573 handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_SUCCESS, "user", "core", "Login Success", handle->login);
1574 }
1575 globals.logger(DL_LOG_DEBUG, "XMPP authenticated\n");
1576 ldl_set_flag_locked(handle, LDL_FLAG_AUTHORIZED);
1577 ldl_set_flag_locked(handle, LDL_FLAG_CONNECTED);
1578 handle->fail_count = 0;
1579 }
1580 } else {
1581 globals.logger(DL_LOG_ERR, "LOGIN ERROR!\n");
1582 handle->state = CS_NEW;
1583 }
1584 break;
1585 }
1586 break;
1587
1588 case IKS_NODE_NORMAL:
1589 break;
1590
1591 case IKS_NODE_ERROR:
1592 globals.logger(DL_LOG_ERR, "NODE ERROR!\n");
1593 return IKS_HOOK;
1594
1595 case IKS_NODE_STOP:
1596 globals.logger(DL_LOG_ERR, "DISCONNECTED!\n");
1597 return IKS_HOOK;
1598 }
1599
1600 iks_filter_packet(handle->filter, pak);
1601
1602 if (handle->job_done == 1) {
1603 return IKS_HOOK;
1604 }
1605
1606 if (node) {
1607 iks_delete(node);
1608 }
1609
1610 return IKS_OK;
1611 }
1612
on_stream(ldl_handle_t * handle,int type,iks * node)1613 static int on_stream(ldl_handle_t *handle, int type, iks *node)
1614 {
1615 handle->counter = opt_timeout;
1616
1617
1618 switch (type) {
1619 case IKS_NODE_START:
1620 if (ldl_test_flag(handle, LDL_FLAG_TLS) && !iks_is_secure(handle->parser)) {
1621 if (iks_has_tls()) {
1622 iks_start_tls(handle->parser);
1623 } else {
1624 globals.logger(DL_LOG_WARNING, "TLS NOT SUPPORTED IN THIS BUILD!\n");
1625 }
1626 }
1627 break;
1628 case IKS_NODE_NORMAL:
1629 if (node && strcmp("stream:features", iks_name(node)) == 0) {
1630 handle->features = iks_stream_features(node);
1631 if (ldl_test_flag(handle, LDL_FLAG_TLS) && !iks_is_secure(handle->parser))
1632 break;
1633 if (ldl_test_flag(handle, LDL_FLAG_CONNECTED)) {
1634 iks *t;
1635 if (handle->features & IKS_STREAM_BIND) {
1636 if ((t = iks_make_resource_bind(handle->acc))) {
1637 apr_queue_push(handle->queue, t);
1638 t = NULL;
1639 }
1640 }
1641 if (handle->features & IKS_STREAM_SESSION) {
1642 if ((t = iks_make_session())) {
1643 iks_insert_attrib(t, "id", "auth");
1644 apr_queue_push(handle->queue, t);
1645 t = NULL;
1646 }
1647 }
1648 } else {
1649 if (handle->features & IKS_STREAM_SASL_MD5) {
1650 iks_start_sasl(handle->parser, IKS_SASL_DIGEST_MD5, handle->acc->user, handle->password);
1651 } else if (handle->features & IKS_STREAM_SASL_PLAIN) {
1652 iks *x = NULL;
1653
1654 if ((x = iks_new("auth"))) {
1655 char s[512] = "";
1656 char base64[1024] = "";
1657 uint32_t slen;
1658
1659 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
1660 iks_insert_attrib(x, "mechanism", "PLAIN");
1661 iks_insert_attrib(x, "encoding", "UTF-8");
1662 snprintf(s, sizeof(s), "%c%s%c%s", 0, handle->acc->user, 0, handle->password);
1663 slen = (uint32_t)(strlen(handle->acc->user) + strlen(handle->password) + 2);
1664 b64encode((unsigned char *)s, slen, (unsigned char *) base64, sizeof(base64));
1665 iks_insert_cdata(x, base64, 0);
1666 apr_queue_push(handle->queue, x);
1667 x = NULL;
1668 } else {
1669 globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
1670 break;
1671 }
1672
1673 }
1674 }
1675 } else if (node && strcmp("failure", iks_name_nons(node)) == 0) {
1676 globals.logger(DL_LOG_CRIT, "sasl authentication failed\n");
1677 if (handle->session_callback) {
1678 handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_FAILURE, "user", "core", "Login Failure", handle->login);
1679 }
1680 } else if (node && strcmp("success", iks_name_nons(node)) == 0) {
1681 globals.logger(DL_LOG_NOTICE, "XMPP server connected\n");
1682 iks_send_header(handle->parser, handle->acc->server);
1683 ldl_set_flag_locked(handle, LDL_FLAG_CONNECTED);
1684 if (handle->session_callback) {
1685 handle->session_callback(handle, NULL, LDL_SIGNAL_CONNECTED, "user", "core", "Server Connected", handle->login);
1686 }
1687 } else {
1688 ikspak *pak;
1689 if (!ldl_test_flag(handle, LDL_FLAG_AUTHORIZED)) {
1690 if (handle->session_callback) {
1691 handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_SUCCESS, "user", "core", "Login Success", handle->login);
1692 }
1693 globals.logger(DL_LOG_NOTICE, "XMPP authenticated\n");
1694 ldl_set_flag_locked(handle, LDL_FLAG_AUTHORIZED);
1695 }
1696 if (node) {
1697 pak = iks_packet(node);
1698 iks_filter_packet(handle->filter, pak);
1699 }
1700 if (handle->job_done == 1) {
1701 return IKS_HOOK;
1702 }
1703 }
1704 break;
1705 #if 0
1706 case IKS_NODE_STOP:
1707 globals.logger(DL_LOG_DEBUG, "server disconnected\n");
1708 break;
1709
1710 case IKS_NODE_ERROR:
1711 globals.logger(DL_LOG_DEBUG, "stream error\n");
1712 break;
1713 #endif
1714
1715 }
1716
1717 if (node) {
1718 iks_delete(node);
1719 }
1720 return IKS_OK;
1721 }
1722
on_msg(void * user_data,ikspak * pak)1723 static int on_msg(void *user_data, ikspak *pak)
1724 {
1725 char *cmd = iks_find_cdata(pak->x, "body");
1726 char *to = iks_find_attrib(pak->x, "to");
1727 char *from = iks_find_attrib(pak->x, "from");
1728 char *subject = iks_find_attrib(pak->x, "subject");
1729 ldl_handle_t *handle = user_data;
1730 ldl_session_t *session = NULL;
1731
1732 if (from) {
1733 session = apr_hash_get(handle->sessions, from, APR_HASH_KEY_STRING);
1734 }
1735
1736 if (handle->session_callback) {
1737 handle->session_callback(handle, session, LDL_SIGNAL_MSG, to, from, subject ? subject : "N/A", cmd);
1738 }
1739
1740 return 0;
1741 }
1742
on_error(void * user_data,ikspak * pak)1743 static int on_error(void *user_data, ikspak * pak)
1744 {
1745 globals.logger(DL_LOG_ERR, "authorization failed\n");
1746 return IKS_FILTER_EAT;
1747 }
1748
on_log(ldl_handle_t * handle,const char * data,size_t size,int is_incoming)1749 static void on_log(ldl_handle_t *handle, const char *data, size_t size, int is_incoming)
1750 {
1751
1752 if (globals.debug) {
1753 if (is_incoming) {
1754 globals.logger(DL_LOG_INFO, "+xml:%s%s:%s", iks_is_secure(handle->parser) ? "Sec" : "", is_incoming ? "RECV" : "SEND", data);
1755 } else {
1756 globals.logger(DL_LOG_NOTICE, "+xml:%s%s:%s", iks_is_secure(handle->parser) ? "Sec" : "", is_incoming ? "RECV" : "SEND", data);
1757 }
1758 }
1759 }
1760
j_setup_filter(ldl_handle_t * handle)1761 static void j_setup_filter(ldl_handle_t *handle)
1762 {
1763 int x = 0;
1764
1765 if (handle->filter) {
1766 iks_filter_delete(handle->filter);
1767 }
1768 handle->filter = iks_filter_new();
1769
1770 iks_filter_add_rule(handle->filter, on_msg, handle, IKS_RULE_TYPE, IKS_PAK_MESSAGE, IKS_RULE_SUBTYPE, IKS_TYPE_CHAT, IKS_RULE_DONE);
1771
1772 iks_filter_add_rule(handle->filter, on_result, handle,
1773 IKS_RULE_TYPE, IKS_PAK_IQ,
1774 IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1775
1776 iks_filter_add_rule(handle->filter, on_presence, handle,
1777 IKS_RULE_TYPE, IKS_PAK_PRESENCE,
1778 //IKS_RULE_SUBTYPE, IKS_TYPE_SET,
1779 IKS_RULE_DONE);
1780
1781 iks_filter_add_rule(handle->filter, on_commands, handle,
1782 IKS_RULE_TYPE, IKS_PAK_IQ,
1783 IKS_RULE_SUBTYPE, IKS_TYPE_SET,
1784 IKS_RULE_DONE);
1785
1786 iks_filter_add_rule(handle->filter, on_commands, handle,
1787 IKS_RULE_TYPE, IKS_PAK_IQ,
1788 IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
1789 IKS_RULE_DONE);
1790
1791 iks_filter_add_rule(handle->filter, on_commands, handle,
1792 IKS_RULE_TYPE, IKS_PAK_IQ,
1793 IKS_RULE_SUBTYPE, IKS_TYPE_ERROR,
1794 IKS_RULE_DONE);
1795
1796 iks_filter_add_rule(handle->filter, on_subscribe, handle,
1797 IKS_RULE_TYPE, IKS_PAK_S10N,
1798 IKS_RULE_SUBTYPE, IKS_TYPE_SUBSCRIBE,
1799 IKS_RULE_DONE);
1800
1801 iks_filter_add_rule(handle->filter, on_unsubscribe, handle,
1802 IKS_RULE_TYPE, IKS_PAK_S10N,
1803 IKS_RULE_SUBTYPE, IKS_TYPE_UNSUBSCRIBE,
1804 IKS_RULE_DONE);
1805
1806 iks_filter_add_rule(handle->filter, on_error, handle,
1807 IKS_RULE_TYPE, IKS_PAK_IQ,
1808 IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1809
1810 for (x = 0; FEATURES[x].name; x++) {
1811 iks_filter_add_rule(handle->filter, FEATURES[x].callback, handle,
1812 IKS_RULE_NS, FEATURES[x].name, IKS_RULE_DONE);
1813 }
1814 }
1815
ldl_flush_queue(ldl_handle_t * handle,int done)1816 static ldl_queue_t ldl_flush_queue(ldl_handle_t *handle, int done)
1817 {
1818 iks *msg;
1819 void *pop = NULL;
1820 unsigned int len = 0, x = 0;
1821
1822 ldl_queue_t sent_data = LDL_QUEUE_NONE;
1823
1824 apr_thread_mutex_lock(handle->lock);
1825
1826 while(apr_queue_trypop(handle->queue, &pop) == APR_SUCCESS) {
1827 if (pop) {
1828 msg = (iks *) pop;
1829 if (!done) {
1830 if (iks_send(handle->parser, msg) != IKS_OK) {
1831 globals.logger(DL_LOG_DEBUG, "Failed sending data!\n");
1832 };
1833 };
1834 iks_delete(msg);
1835 pop = NULL;
1836 sent_data = LDL_QUEUE_SENT;
1837 } else {
1838 break;
1839 }
1840 }
1841
1842 len = apr_queue_size(handle->retry_queue);
1843 if (globals.debug && len) {
1844 globals.logger(DL_LOG_CRIT, "Processing %u packets in retry queue\n", len);
1845 }
1846
1847 pop = NULL;
1848
1849 while(x < len && apr_queue_trypop(handle->retry_queue, &pop) == APR_SUCCESS) {
1850 if (!pop) {
1851 break;
1852 } else {
1853 struct packet_node *packet_node = (struct packet_node *) pop;
1854 apr_time_t now = apr_time_now();
1855 x++;
1856
1857 if (packet_node->next <= now) {
1858 if (packet_node->retries > 0) {
1859 packet_node->retries--;
1860 if (globals.debug) {
1861 globals.logger(DL_LOG_CRIT, "Sending packet %s (%d left)\n", packet_node->id, packet_node->retries);
1862 }
1863 if (iks_send(handle->parser, packet_node->xml) != IKS_OK) {
1864 globals.logger(DL_LOG_DEBUG, "Failed trying re-sending data!\n");
1865 };
1866 packet_node->next = now + 5000000;
1867 sent_data = LDL_QUEUE_SENT;
1868 }
1869 }
1870 if (packet_node->retries == 0 || done) {
1871 if (globals.debug) {
1872 globals.logger(DL_LOG_CRIT, "Discarding packet %s\n", packet_node->id);
1873 }
1874 apr_hash_set(handle->retry_hash, packet_node->id, APR_HASH_KEY_STRING, NULL);
1875 iks_delete(packet_node->xml);
1876 free(packet_node);
1877 } else {
1878 apr_queue_push(handle->retry_queue, packet_node);
1879 packet_node = NULL;
1880 }
1881 pop = NULL;
1882 }
1883 }
1884 apr_thread_mutex_unlock(handle->lock);
1885 return sent_data;
1886 }
1887
1888
xmpp_connect(ldl_handle_t * handle,char * jabber_id,char * pass)1889 static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass)
1890 {
1891 int count_ka = LDL_KEEPALIVE_TIMEOUT;
1892 time_t tstart, tnow;
1893
1894 while (ldl_test_flag((&globals), LDL_FLAG_READY) && ldl_test_flag(handle, LDL_FLAG_RUNNING)) {
1895 int e;
1896 char tmp[512], *sl;
1897 int fd;
1898
1899 handle->parser = iks_stream_new(ldl_test_flag(handle, LDL_FLAG_COMPONENT) ? IKS_NS_COMPONENT : IKS_NS_CLIENT,
1900 handle,
1901 (iksStreamHook *) (ldl_test_flag(handle, LDL_FLAG_COMPONENT) ? on_stream_component : on_stream));
1902
1903
1904 iks_set_log_hook(handle->parser, (iksLogHook *) on_log);
1905
1906
1907 strncpy(tmp, jabber_id, sizeof(tmp)-1);
1908 sl = strchr(tmp, '/');
1909
1910 if (!sl && !ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1911 /* user gave no resource name, use the default */
1912 snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), "/%s", "talk");
1913 } else if (sl && ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1914 *sl = '\0';
1915 }
1916
1917 handle->acc = iks_id_new(iks_parser_stack(handle->parser), tmp);
1918
1919 handle->password = pass;
1920
1921 j_setup_filter(handle);
1922
1923 globals.logger(DL_LOG_DEBUG, "xmpp connecting\n");
1924
1925 e = iks_connect_via(handle->parser,
1926 handle->server ? handle->server : handle->acc->server,
1927 handle->port ? handle->port : IKS_JABBER_PORT,
1928 handle->acc->server);
1929
1930 switch (e) {
1931 case IKS_OK:
1932 break;
1933 case IKS_NET_NODNS:
1934 globals.logger(DL_LOG_CRIT, "hostname lookup failed\n");
1935 microsleep(1000);
1936 goto fail;
1937 case IKS_NET_NOCONN:
1938 globals.logger(DL_LOG_CRIT, "connection failed\n");
1939 microsleep(1000);
1940 goto fail;
1941 default:
1942 globals.logger(DL_LOG_CRIT, "io error 1 %d\n", e);
1943 microsleep(1000);
1944 goto fail;
1945 }
1946
1947 handle->counter = opt_timeout;
1948 if ((tstart = time(NULL)) == -1) {
1949 globals.logger(DL_LOG_DEBUG, "error determining connection time");
1950 }
1951
1952 while (ldl_test_flag((&globals), LDL_FLAG_READY) && ldl_test_flag(handle, LDL_FLAG_RUNNING)) {
1953 e = iks_recv(handle->parser, 1);
1954
1955 if (handle->loop_callback) {
1956 if (handle->loop_callback(handle) != LDL_STATUS_SUCCESS) {
1957 ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
1958 break;
1959 }
1960 }
1961
1962 if (handle->job_done) {
1963 break;
1964 }
1965
1966 if (IKS_HOOK == e) {
1967 break;
1968 }
1969
1970 if (IKS_OK != e || ldl_test_flag(handle, LDL_FLAG_BREAK)) {
1971 globals.logger(DL_LOG_DEBUG, "io error 2 %d retry in %d second(s)", e, ++handle->fail_count);
1972 if ((tnow = time(NULL)) == -1) {
1973 globals.logger(DL_LOG_DEBUG, "error deterniming io error time");
1974 }
1975 if (difftime(tnow, tstart) > 30) {
1976 /* this is a new error situation: reset counter */
1977 globals.logger(DL_LOG_DEBUG, "resetting fail count");
1978 handle->fail_count = 1;
1979 }
1980 microsleep(1000 * handle->fail_count);
1981 goto fail;
1982 }
1983
1984 if (ldl_test_flag(handle, LDL_FLAG_RUNNING)) {
1985 if (ldl_flush_queue(handle, 0) == LDL_QUEUE_SENT) {
1986 count_ka = LDL_KEEPALIVE_TIMEOUT;
1987 }
1988 }
1989
1990 if (!ldl_test_flag(handle, LDL_FLAG_CONNECTED)) {
1991 handle->counter--;
1992
1993 if (IKS_NET_TLSFAIL == e) {
1994 globals.logger(DL_LOG_CRIT, "tls handshake failed\n");
1995 microsleep(500);
1996 break;
1997 }
1998
1999 if (handle->counter == 0) {
2000 globals.logger(DL_LOG_CRIT, "network timeout\n");
2001 microsleep(500);
2002 break;
2003 }
2004 }
2005
2006 if (count_ka-- <= 0) {
2007 if( iks_send_raw(handle->parser, " ") == IKS_OK) {
2008 globals.logger(DL_LOG_DEBUG, "Sent keep alive signal");
2009 count_ka = LDL_KEEPALIVE_TIMEOUT;
2010 } else {
2011 globals.logger(DL_LOG_DEBUG, "Failed sending keep alive signal");
2012 microsleep(500);
2013 break;
2014 }
2015 }
2016
2017 }
2018
2019 fail:
2020
2021 ldl_clear_flag_locked(handle, LDL_FLAG_CONNECTED);
2022 ldl_clear_flag_locked(handle, LDL_FLAG_AUTHORIZED);
2023 ldl_clear_flag_locked(handle, LDL_FLAG_BREAK);
2024 handle->state = CS_NEW;
2025
2026 if ((fd = iks_fd(handle->parser)) > -1) {
2027 shutdown(fd, 0x02);
2028 }
2029
2030 iks_disconnect(handle->parser);
2031 iks_parser_delete(handle->parser);
2032 }
2033 ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
2034
2035 ldl_flush_queue(handle, 1);
2036
2037 ldl_set_flag_locked(handle, LDL_FLAG_STOPPED);
2038
2039 }
2040
add_elements(ldl_session_t * session,iks * tag)2041 static void add_elements(ldl_session_t *session, iks *tag)
2042 {
2043 apr_hash_index_t *hi;
2044 return;
2045 for (hi = apr_hash_first(session->pool, session->variables); hi; hi = apr_hash_next(hi)) {
2046 void *val = NULL;
2047 const void *key = NULL;
2048
2049 apr_hash_this(hi, &key, NULL, &val);
2050 if (val) {
2051 iks *var = iks_insert(tag, "info_element");
2052 iks_insert_attrib(var, "xmlns", "http://www.freeswitch.org/jie");
2053 iks_insert_attrib(var, "name", (char *) key);
2054 iks_insert_attrib(var, "value", (char *) val);
2055 }
2056 }
2057 }
2058
2059
ldl_set_jingle_tag(ldl_session_t * session,iks * iq,char * action)2060 static iks *ldl_set_jingle_tag(ldl_session_t *session, iks *iq, char *action)
2061 {
2062 iks *jin = iks_insert (iq, "jin:jingle");
2063 iks_insert_attrib(jin, "xmlns:jin", "urn:xmpp:jingle:1");
2064 iks_insert_attrib(jin, "action", action);
2065 iks_insert_attrib(jin, "sid", session->id);
2066 //iks_insert_attrib(jin, "initiator", session->initiator ? session->initiator : session->them);
2067
2068 return jin;
2069 }
2070
new_jingle_iq(ldl_session_t * session,iks ** iqp,iks ** jinp,unsigned int * id,char * action)2071 static ldl_status new_jingle_iq(ldl_session_t *session, iks **iqp, iks **jinp, unsigned int *id, char *action)
2072 {
2073 iks *iq , *jin;
2074 unsigned int myid;
2075 char idbuf[80];
2076
2077 myid = next_id();
2078 snprintf(idbuf, sizeof(idbuf), "%u", myid);
2079 iq = iks_new("iq");
2080 iks_insert_attrib(iq, "xmlns", "jabber:client");
2081 iks_insert_attrib(iq, "from", session->login);
2082 iks_insert_attrib(iq, "to", session->them);
2083 iks_insert_attrib(iq, "type", "set");
2084 iks_insert_attrib(iq, "id", idbuf);
2085
2086 jin = ldl_set_jingle_tag(session, iq, action);
2087
2088 *jinp = jin;
2089 *iqp = iq;
2090 *id = myid;
2091 return LDL_STATUS_SUCCESS;
2092 }
2093
2094
new_session_iq(ldl_session_t * session,iks ** iqp,iks ** sessp,unsigned int * id,char * type)2095 static ldl_status new_session_iq(ldl_session_t *session, iks **iqp, iks **sessp, unsigned int *id, char *type)
2096 {
2097 iks *iq, *sess;
2098 unsigned int myid;
2099 char idbuf[80];
2100
2101 myid = next_id();
2102 snprintf(idbuf, sizeof(idbuf), "%u", myid);
2103 iq = iks_new("iq");
2104 iks_insert_attrib(iq, "xmlns", "jabber:client");
2105 iks_insert_attrib(iq, "from", session->login);
2106 iks_insert_attrib(iq, "to", session->them);
2107 iks_insert_attrib(iq, "type", "set");
2108 iks_insert_attrib(iq, "id", idbuf);
2109 sess = iks_insert (iq, "ses:session");
2110 iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session");
2111
2112 iks_insert_attrib(sess, "type", type);
2113 iks_insert_attrib(sess, "id", session->id);
2114 iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them);
2115
2116 *sessp = sess;
2117 *iqp = iq;
2118 *id = myid;
2119 return LDL_STATUS_SUCCESS;
2120 }
2121
schedule_packet(ldl_handle_t * handle,unsigned int id,iks * xml,unsigned int retries)2122 static void schedule_packet(ldl_handle_t *handle, unsigned int id, iks *xml, unsigned int retries)
2123 {
2124 struct packet_node *packet_node;
2125
2126 apr_thread_mutex_lock(handle->lock);
2127 if ((packet_node = malloc(sizeof(*packet_node)))) {
2128 memset(packet_node, 0, sizeof(*packet_node));
2129 snprintf(packet_node->id, sizeof(packet_node->id), "%u", id);
2130 packet_node->xml = xml;
2131 packet_node->retries = retries;
2132 packet_node->next = apr_time_now();
2133 apr_hash_set(handle->retry_hash, packet_node->id, APR_HASH_KEY_STRING, packet_node);
2134 apr_queue_push(handle->retry_queue, packet_node);
2135 packet_node = NULL;
2136 }
2137 apr_thread_mutex_unlock(handle->lock);
2138
2139 }
2140
ldl_session_get_caller(ldl_session_t * session)2141 char *ldl_session_get_caller(ldl_session_t *session)
2142 {
2143 return session->them;
2144 }
2145
ldl_session_get_callee(ldl_session_t * session)2146 char *ldl_session_get_callee(ldl_session_t *session)
2147 {
2148 return session->login;
2149 }
2150
ldl_session_set_ip(ldl_session_t * session,char * ip)2151 void ldl_session_set_ip(ldl_session_t *session, char *ip)
2152 {
2153 session->ip = apr_pstrdup(session->pool, ip);
2154 }
2155
ldl_session_get_ip(ldl_session_t * session)2156 char *ldl_session_get_ip(ldl_session_t *session)
2157 {
2158 return session->ip;
2159 }
2160
ldl_session_set_private(ldl_session_t * session,void * private_data)2161 void ldl_session_set_private(ldl_session_t *session, void *private_data)
2162 {
2163 session->private_data = private_data;
2164 }
2165
ldl_session_get_private(ldl_session_t * session)2166 void *ldl_session_get_private(ldl_session_t *session)
2167 {
2168 return session->private_data;
2169 }
2170
ldl_session_accept_candidate(ldl_session_t * session,ldl_candidate_t * candidate)2171 void ldl_session_accept_candidate(ldl_session_t *session, ldl_candidate_t *candidate)
2172 {
2173 iks *iq, *sess, *tp;
2174 unsigned int myid;
2175 char idbuf[80];
2176 myid = next_id();
2177 snprintf(idbuf, sizeof(idbuf), "%u", myid);
2178
2179 if ((iq = iks_new("iq"))) {
2180 if (!iks_insert_attrib(iq, "type", "set")) goto fail;
2181 if (!iks_insert_attrib(iq, "id", idbuf)) goto fail;
2182 if (!iks_insert_attrib(iq, "from", session->login)) goto fail;
2183 if (!iks_insert_attrib(iq, "to", session->them)) goto fail;
2184 if (!(sess = iks_insert (iq, "ses:session"))) goto fail;
2185 if (!iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session")) goto fail;
2186 if (!iks_insert_attrib(sess, "type", "transport-accept")) goto fail;
2187 if (!iks_insert_attrib(sess, "id", candidate->tid)) goto fail;
2188 if (!iks_insert_attrib(sess, "xmlns", "http://www.google.com/session")) goto fail;
2189 if (!iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them)) goto fail;
2190 if (!(tp = iks_insert (sess, "transport"))) goto fail;
2191 if (!iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p")) goto fail;
2192 apr_queue_push(session->handle->queue, iq);
2193 iq = NULL;
2194 }
2195
2196 fail:
2197 if (iq) {
2198 iks_delete(iq);
2199 }
2200
2201 }
2202
ldl_handle_get_private(ldl_handle_t * handle)2203 void *ldl_handle_get_private(ldl_handle_t *handle)
2204 {
2205 return handle->private_info;
2206 }
2207
ldl_handle_get_login(ldl_handle_t * handle)2208 char *ldl_handle_get_login(ldl_handle_t *handle)
2209 {
2210 return handle->login;
2211 }
2212
ldl_handle_send_presence(ldl_handle_t * handle,char * from,char * to,char * type,char * rpid,char * message,char * avatar)2213 void ldl_handle_send_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message, char *avatar)
2214 {
2215 do_presence(handle, from, to, type, rpid, message, avatar);
2216 }
2217
ldl_random_string(char * buf,uint16_t len,char * set)2218 static void ldl_random_string(char *buf, uint16_t len, char *set)
2219 {
2220 char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
2221 int max;
2222 uint16_t x;
2223
2224 if (!set) {
2225 set = chars;
2226 }
2227
2228 max = (int) strlen(set);
2229
2230 srand((unsigned int) time(NULL));
2231
2232 for (x = 0; x < len; x++) {
2233 int j = (int) (max * 1.0 * rand() / (RAND_MAX + 1.0));
2234 buf[x] = set[j];
2235 }
2236 }
2237
2238 #define TLEN 8192
ldl_handle_send_vcard(ldl_handle_t * handle,char * from,char * to,char * id,char * vcard)2239 void ldl_handle_send_vcard(ldl_handle_t *handle, char *from, char *to, char *id, char *vcard)
2240 {
2241 iks *vxml = NULL, *iq = NULL;
2242 int e = 0;
2243 ldl_avatar_t *ap = NULL;
2244 char *text = NULL;
2245
2246 ap = ldl_get_avatar(handle, NULL, from);
2247
2248 if (!vcard) {
2249 char *ext;
2250
2251 if (!ap) {
2252 return;
2253 }
2254
2255 if ((ext = strrchr(ap->path, '.'))) {
2256 ext++;
2257 } else {
2258 ext = "png";
2259 }
2260 text = malloc(TLEN);
2261 snprintf(text, TLEN,
2262 "<vCard xmlns='vcard-temp'><PHOTO><TYPE>image/%s</TYPE><BINVAL>%s</BINVAL></PHOTO></vCard>",
2263 ext,
2264 ap->base64
2265 );
2266 vcard = text;
2267 } else {
2268 if (ap && (strstr(vcard, "photo") || strstr(vcard, "PHOTO"))) {
2269 ldl_random_string(ap->hash, sizeof(ap->hash) -1, NULL);
2270 }
2271 }
2272
2273
2274 if (!(vxml = iks_tree(vcard, 0, &e))) {
2275 globals.logger(DL_LOG_ERR, "Parse returned error [%d]\n", e);
2276 goto fail;
2277 }
2278
2279 if (!(iq = iks_new("iq"))) {
2280 globals.logger(DL_LOG_ERR, "Memory Error\n");
2281 goto fail;
2282 }
2283
2284 if (!iks_insert_attrib(iq, "to", to)) goto fail;
2285 if (!iks_insert_attrib(iq, "xmlns", "jabber:client")) goto fail;
2286 if (!iks_insert_attrib(iq,"from", from)) goto fail;
2287 if (!iks_insert_attrib(iq, "type", "result")) goto fail;
2288 if (!iks_insert_attrib(iq, "id", id)) goto fail;
2289 if (!iks_insert_node(iq, vxml)) goto fail;
2290
2291 apr_queue_push(handle->queue, iq);
2292
2293 iq = NULL;
2294 vxml = NULL;
2295
2296 fail:
2297
2298 if (iq) {
2299 iks_delete(iq);
2300 }
2301
2302 if (vxml) {
2303 iks_delete(vxml);
2304 }
2305
2306 if (text) {
2307 free(text);
2308 }
2309
2310 }
2311
ldl_handle_send_msg(ldl_handle_t * handle,char * from,char * to,const char * subject,const char * body)2312 void ldl_handle_send_msg(ldl_handle_t *handle, char *from, char *to, const char *subject, const char *body)
2313 {
2314 iks *msg;
2315 char *t, *e;
2316 char *bdup = NULL;
2317 int on = 0;
2318 int len = 0;
2319 char *my_body = strdup(body);
2320 char *my_body_base = my_body;
2321
2322 assert(handle != NULL);
2323 assert(body != NULL);
2324
2325 if (strchr(my_body, '<')) {
2326 len = (int) strlen(my_body);
2327 if (!(bdup = malloc(len))) {
2328 return;
2329 }
2330
2331 memset(bdup, 0, len);
2332
2333 e = bdup;
2334 for(t = my_body; *t; t++) {
2335 if (*t == '<') {
2336 on = 1;
2337 } else if (*t == '>') {
2338 t++;
2339 on = 0;
2340 }
2341
2342 if (!on) {
2343 *e++ = *t;
2344 }
2345 }
2346 my_body = bdup;
2347 }
2348
2349 msg = iks_make_msg(IKS_TYPE_NONE, to, my_body);
2350 iks_insert_attrib(msg, "type", "chat");
2351
2352 if (!from) {
2353 from = handle->login;
2354 }
2355
2356 iks_insert_attrib(msg, "from", from);
2357
2358 if (subject) {
2359 iks_insert_attrib(msg, "subject", subject);
2360 }
2361
2362 if (bdup) {
2363 free(bdup);
2364 }
2365
2366 if (my_body_base) {
2367 free(my_body_base);
2368 }
2369
2370 apr_queue_push(handle->queue, msg);
2371 msg = NULL;
2372
2373 }
2374
ldl_global_debug(int on)2375 int ldl_global_debug(int on)
2376 {
2377 if (on > -1) {
2378 globals.debug = on ? 1 : 0;
2379 }
2380
2381 return globals.debug ? 1 : 0;
2382 }
2383
ldl_global_set_logger(ldl_logger_t logger)2384 void ldl_global_set_logger(ldl_logger_t logger)
2385 {
2386 globals.logger = logger;
2387 }
2388
ldl_session_terminate(ldl_session_t * session)2389 unsigned int ldl_session_terminate(ldl_session_t *session)
2390 {
2391 iks *iq, *sess;
2392 unsigned int id;
2393 apr_hash_t *hash = session->handle->sessions;
2394
2395 new_session_iq(session, &iq, &sess, &id, "terminate");
2396
2397 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2398 ldl_set_jingle_tag(session, iq, "session-terminate");
2399 }
2400
2401 schedule_packet(session->handle, id, iq, LDL_RETRY);
2402
2403 if (session->id) {
2404 apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
2405 }
2406
2407 if (session->them) {
2408 apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
2409 }
2410
2411 return id;
2412
2413 }
2414
2415
2416
ldl_session_transport(ldl_session_t * session,ldl_candidate_t * candidates,unsigned int clen)2417 unsigned int ldl_session_transport(ldl_session_t *session,
2418 ldl_candidate_t *candidates,
2419 unsigned int clen)
2420
2421 {
2422 iks *iq, *sess, *tag;
2423 unsigned int x, id = 0;
2424
2425
2426 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2427 return ldl_session_candidates(session, candidates, clen);
2428 }
2429
2430
2431
2432 for (x = 0; x < clen; x++) {
2433 char buf[512];
2434 iq = NULL;
2435 sess = NULL;
2436 id = 0;
2437
2438 new_session_iq(session, &iq, &sess, &id, "transport-info");
2439
2440 tag = sess;
2441
2442 //if (0) add_elements(session, tag);
2443 tag = iks_insert(tag, "transport");
2444 iks_insert_attrib(tag, "xmlns", "http://www.google.com/transport/p2p");
2445 //iks_insert_attrib(tag, "xmlns", "urn:xmpp:jingle:transports:raw-udp:1");
2446
2447 tag = iks_insert(tag, "candidate");
2448
2449 if (candidates[x].name) {
2450 iks_insert_attrib(tag, "name", candidates[x].name);
2451 }
2452 if (candidates[x].address) {
2453 iks_insert_attrib(tag, "address", candidates[x].address);
2454 }
2455 if (candidates[x].port) {
2456 snprintf(buf, sizeof(buf), "%u", candidates[x].port);
2457 iks_insert_attrib(tag, "port", buf);
2458 }
2459 if (candidates[x].username) {
2460 iks_insert_attrib(tag, "username", candidates[x].username);
2461 }
2462 if (candidates[x].password) {
2463 iks_insert_attrib(tag, "password", candidates[x].password);
2464 }
2465 if (candidates[x].pref) {
2466 snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref);
2467 iks_insert_attrib(tag, "preference", buf);
2468 }
2469 if (candidates[x].protocol) {
2470 iks_insert_attrib(tag, "protocol", candidates[x].protocol);
2471 }
2472 if (candidates[x].type) {
2473 iks_insert_attrib(tag, "type", candidates[x].type);
2474 }
2475
2476 iks_insert_attrib(tag, "network", "0");
2477 iks_insert_attrib(tag, "generation", "0");
2478 schedule_packet(session->handle, id, iq, LDL_RETRY);
2479 }
2480
2481 return id;
2482 }
2483
ldl_session_candidates(ldl_session_t * session,ldl_candidate_t * candidates,unsigned int clen)2484 unsigned int ldl_session_candidates(ldl_session_t *session,
2485 ldl_candidate_t *candidates,
2486 unsigned int clen)
2487
2488 {
2489 iks *iq = NULL, *sess = NULL, *tag = NULL;
2490 unsigned int x = 0, id = 0;
2491
2492
2493 unsigned int pass = 0;
2494 iks *jingle = NULL, *jin_content = NULL, *p_trans = NULL;
2495 const char *tname = "";
2496 const char *type = "";
2497
2498 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2499
2500
2501 new_jingle_iq(session, &iq, &jingle, &id, "transport-info");
2502
2503 for (pass = 0; pass < 2; pass++) {
2504
2505 if (pass == 0) {
2506 type = "rtp";
2507 tname = "audio";
2508 } else {
2509 type = "video_rtp";
2510 tname = "video";
2511 }
2512
2513 jin_content = iks_insert(jingle, "jin:content");
2514 iks_insert_attrib(jin_content, "name", tname);
2515 iks_insert_attrib(jin_content, "creator", "initiator");
2516
2517 for (x = 0; x < clen; x++) {
2518 char buf[512];
2519
2520 if (strcasecmp(candidates[x].name, type)) {
2521 continue;
2522 }
2523
2524 p_trans = iks_insert(jin_content, "p:transport");
2525 iks_insert_attrib(p_trans, "xmlns:p", "http://www.google.com/transport/p2p");
2526
2527
2528
2529 tag = iks_insert(p_trans, "candidate");
2530
2531 if (candidates[x].name) {
2532 iks_insert_attrib(tag, "name", candidates[x].name);
2533 }
2534 if (candidates[x].address) {
2535 iks_insert_attrib(tag, "address", candidates[x].address);
2536 }
2537 if (candidates[x].port) {
2538 snprintf(buf, sizeof(buf), "%u", candidates[x].port);
2539 iks_insert_attrib(tag, "port", buf);
2540 }
2541 if (candidates[x].username) {
2542 iks_insert_attrib(tag, "username", candidates[x].username);
2543 }
2544 if (candidates[x].password) {
2545 iks_insert_attrib(tag, "password", candidates[x].password);
2546 }
2547 if (candidates[x].pref) {
2548 snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref);
2549 iks_insert_attrib(tag, "preference", buf);
2550 }
2551 if (candidates[x].protocol) {
2552 iks_insert_attrib(tag, "protocol", candidates[x].protocol);
2553 }
2554 if (candidates[x].type) {
2555 iks_insert_attrib(tag, "type", candidates[x].type);
2556 }
2557
2558 iks_insert_attrib(tag, "network", "0");
2559 iks_insert_attrib(tag, "generation", "0");
2560 }
2561 }
2562
2563
2564 schedule_packet(session->handle, id, iq, LDL_RETRY);
2565
2566 iq = NULL;
2567 sess = NULL;
2568 tag = NULL;
2569 id = 0;
2570 }
2571
2572
2573 new_session_iq(session, &iq, &sess, &id, "candidates");
2574 add_elements(session, sess);
2575
2576 for (x = 0; x < clen; x++) {
2577 char buf[512];
2578 //iq = NULL;
2579 //sess = NULL;
2580 //id = 0;
2581
2582 tag = iks_insert(sess, "ses:candidate");
2583
2584
2585
2586 if (candidates[x].name) {
2587 iks_insert_attrib(tag, "name", candidates[x].name);
2588 }
2589 if (candidates[x].address) {
2590 iks_insert_attrib(tag, "address", candidates[x].address);
2591 }
2592 if (candidates[x].port) {
2593 snprintf(buf, sizeof(buf), "%u", candidates[x].port);
2594 iks_insert_attrib(tag, "port", buf);
2595 }
2596 if (candidates[x].username) {
2597 iks_insert_attrib(tag, "username", candidates[x].username);
2598 }
2599 if (candidates[x].password) {
2600 iks_insert_attrib(tag, "password", candidates[x].password);
2601 }
2602 if (candidates[x].pref) {
2603 snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref);
2604 iks_insert_attrib(tag, "preference", buf);
2605 }
2606 if (candidates[x].protocol) {
2607 iks_insert_attrib(tag, "protocol", candidates[x].protocol);
2608 }
2609 if (candidates[x].type) {
2610 iks_insert_attrib(tag, "type", candidates[x].type);
2611 }
2612
2613 iks_insert_attrib(tag, "network", "0");
2614 iks_insert_attrib(tag, "generation", "0");
2615
2616 }
2617
2618 schedule_packet(session->handle, id, iq, LDL_RETRY);
2619
2620 return id;
2621 }
2622
2623
2624
ldl_handle_probe(ldl_handle_t * handle,char * id,char * from,char * buf,unsigned int len)2625 char *ldl_handle_probe(ldl_handle_t *handle, char *id, char *from, char *buf, unsigned int len)
2626 {
2627 iks *pres, *msg;
2628 char *lid = NULL, *low_id = NULL;
2629 struct ldl_buffer buffer;
2630 time_t started, elapsed, next = 0;
2631 char *notice = "Call Me!";
2632
2633 buffer.buf = buf;
2634 buffer.len = len;
2635 buffer.hit = 0;
2636
2637 apr_hash_set(handle->probe_hash, id, APR_HASH_KEY_STRING, &buffer);
2638
2639 started = time(NULL);
2640 for(;;) {
2641 elapsed = time(NULL) - started;
2642 if (elapsed == next) {
2643 msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, notice);
2644 iks_insert_attrib(msg, "from", from);
2645 apr_queue_push(handle->queue, msg);
2646 msg = NULL;
2647
2648 pres = iks_new("presence");
2649 iks_insert_attrib(pres, "xmlns", "jabber:client");
2650 iks_insert_attrib(pres, "type", "probe");
2651 iks_insert_attrib(pres, "to", id);
2652 iks_insert_attrib(pres, "from", from);
2653 apr_queue_push(handle->queue, pres);
2654 pres = NULL;
2655 next += 5;
2656 }
2657 if (elapsed >= 17) {
2658 break;
2659 }
2660 if (buffer.hit) {
2661 lid = buffer.buf;
2662 break;
2663 }
2664 ldl_yield(1000);
2665 }
2666
2667 if ((low_id = strdup(id))) {
2668 lowercase(id);
2669 apr_hash_set(handle->probe_hash, low_id, APR_HASH_KEY_STRING, NULL);
2670 free(low_id);
2671 }
2672
2673 return lid;
2674 }
2675
2676
ldl_handle_disco(ldl_handle_t * handle,char * id,char * from,char * buf,unsigned int len)2677 char *ldl_handle_disco(ldl_handle_t *handle, char *id, char *from, char *buf, unsigned int len)
2678 {
2679 iks *iq, *query, *msg;
2680 char *lid = NULL;
2681 struct ldl_buffer buffer;
2682 apr_time_t started;
2683 unsigned int elapsed;
2684 char *notice = "Call Me!";
2685 int again = 0;
2686 unsigned int myid;
2687 char idbuf[80];
2688
2689 myid = next_id();
2690 snprintf(idbuf, sizeof(idbuf), "%u", myid);
2691
2692 buffer.buf = buf;
2693 buffer.len = len;
2694 buffer.hit = 0;
2695
2696 if ((iq = iks_new("iq"))) {
2697 if ((query = iks_insert(iq, "query"))) {
2698 iks_insert_attrib(iq, "type", "get");
2699 iks_insert_attrib(iq, "to", id);
2700 iks_insert_attrib(iq,"from", from);
2701 iks_insert_attrib(iq, "id", idbuf);
2702 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2703 } else {
2704 iks_delete(iq);
2705 globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
2706 return NULL;
2707 }
2708 } else {
2709 globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
2710 return NULL;
2711 }
2712
2713 apr_hash_set(handle->probe_hash, id, APR_HASH_KEY_STRING, &buffer);
2714 msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, notice);
2715 apr_queue_push(handle->queue, msg);
2716 msg = NULL;
2717 msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, id, notice);
2718 apr_queue_push(handle->queue, msg);
2719 msg = NULL;
2720 apr_queue_push(handle->queue, iq);
2721 iq = NULL;
2722
2723 //schedule_packet(handle, next_id(), pres, LDL_RETRY);
2724
2725 started = apr_time_now();
2726 for(;;) {
2727 elapsed = (unsigned int)((apr_time_now() - started) / 1000);
2728 if (elapsed > 5000 && ! again) {
2729 msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, notice);
2730 apr_queue_push(handle->queue, msg);
2731 msg = NULL;
2732 again++;
2733 }
2734 if (elapsed > 10000) {
2735 break;
2736 }
2737 if (buffer.hit) {
2738 lid = buffer.buf;
2739 break;
2740 }
2741 ldl_yield(1000);
2742 }
2743
2744 apr_hash_set(handle->probe_hash, id, APR_HASH_KEY_STRING, NULL);
2745 return lid;
2746 }
2747
2748
2749
ldl_session_describe(ldl_session_t * session,ldl_payload_t * payloads,unsigned int plen,ldl_description_t description,unsigned int * audio_ssrc,unsigned int * video_ssrc,ldl_crypto_data_t * audio_crypto_data,ldl_crypto_data_t * video_crypto_data)2750 unsigned int ldl_session_describe(ldl_session_t *session,
2751 ldl_payload_t *payloads,
2752 unsigned int plen,
2753 ldl_description_t description, unsigned int *audio_ssrc, unsigned int *video_ssrc,
2754 ldl_crypto_data_t *audio_crypto_data, ldl_crypto_data_t *video_crypto_data)
2755 {
2756 iks *iq;
2757 iks *sess, *payload = NULL, *tag = NULL;//, *u = NULL;
2758
2759 unsigned int x, id;
2760 int video_call = 0;
2761 int compat = 1;
2762 //char *vid_mux = ldl_session_get_value(session, "video:rtcp-mux");
2763 //char *aud_mux = ldl_session_get_value(session, "audio:rtcp-mux");
2764 char tmp[80];
2765 iks *jpayload = NULL, *tp = NULL;
2766 iks *jingle, *jin_audio, *jin_audio_desc = NULL, *jin_video = NULL, *jin_video_desc = NULL, *crypto;
2767
2768
2769 if (!*audio_ssrc) {
2770 *audio_ssrc = (uint32_t) ((intptr_t) session + (uint32_t) time(NULL));
2771 }
2772
2773 if (!*video_ssrc) {
2774 *video_ssrc = (uint32_t) ((intptr_t) payloads + (uint32_t) time(NULL));
2775 }
2776
2777 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2778 new_jingle_iq(session, &iq, &jingle, &id, description == LDL_DESCRIPTION_ACCEPT ? "session-accept" : "session-initiate");
2779 iks_insert_attrib(jingle, "initiator", session->initiator ? session->initiator : session->them);
2780
2781 if (compat) {
2782 sess = iks_insert (iq, "ses:session");
2783 iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session");
2784
2785 iks_insert_attrib(sess, "type", description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate");
2786 iks_insert_attrib(sess, "id", session->id);
2787 iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them);
2788 }
2789
2790 } else {
2791 new_session_iq(session, &iq, &sess, &id, description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate");
2792 }
2793
2794
2795 /* Check if this is a video call */
2796 for (x = 0; x < plen; x++) {
2797 if (payloads[x].type == LDL_PAYLOAD_VIDEO) {
2798 video_call = 1;
2799 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2800 jin_video = iks_insert(jingle, "jin:content");
2801 iks_insert_attrib(jin_video, "name", "video");
2802 iks_insert_attrib(jin_video, "creator", "initiator");
2803 //iks_insert_attrib(jin_video, "senders", "both");
2804 jin_video_desc = iks_insert(jin_video, "rtp:description");
2805 iks_insert_attrib(jin_video_desc, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
2806 iks_insert_attrib(jin_video_desc, "media", "video");
2807 snprintf(tmp, sizeof(tmp), "%u", *video_ssrc);
2808 iks_insert_attrib(jin_video_desc, "ssrc", tmp);
2809 tp = iks_insert(jin_video, "p:transport");
2810 iks_insert_attrib(tp, "xmlns:p", "http://www.google.com/transport/p2p");
2811
2812 }
2813
2814 break;
2815 }
2816 }
2817
2818
2819 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2820 jin_audio = iks_insert(jingle, "jin:content");
2821 iks_insert_attrib(jin_audio, "name", "audio");
2822 iks_insert_attrib(jin_audio, "creator", "initiator");
2823 //iks_insert_attrib(jin_audio, "senders", "both");
2824 jin_audio_desc = iks_insert(jin_audio, "rtp:description");
2825 iks_insert_attrib(jin_audio_desc, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
2826 iks_insert_attrib(jin_audio_desc, "media", "audio");
2827 snprintf(tmp, sizeof(tmp), "%u", *audio_ssrc);
2828 iks_insert_attrib(jin_audio_desc, "ssrc", tmp);
2829 tp = iks_insert(jin_audio, "p:transport");
2830 iks_insert_attrib(tp, "xmlns:p", "http://www.google.com/transport/p2p");
2831 }
2832
2833 if (compat) {
2834
2835 if (video_call) {
2836 tag = iks_insert(sess, "vid:description");
2837 iks_insert_attrib(tag, "xmlns:vid", "http://www.google.com/session/video");
2838 } else {
2839 tag = iks_insert(sess, "pho:description");
2840 iks_insert_attrib(tag, "xmlns:pho", "http://www.google.com/session/phone");
2841 }
2842
2843 if (video_call) {
2844
2845 for (x = 0; x < plen; x++) {
2846 char idbuf[80];
2847
2848 if (payloads[x].type != LDL_PAYLOAD_VIDEO) {
2849 continue;
2850 }
2851
2852 sprintf(idbuf, "%d", payloads[x].id);
2853
2854
2855 payload = iks_insert(tag, "vid:payload-type");
2856
2857 iks_insert_attrib(payload, "id", idbuf);
2858 iks_insert_attrib(payload, "name", payloads[x].name);
2859
2860 if (payloads[x].type == LDL_PAYLOAD_VIDEO && video_call) {
2861 if (payloads[x].width) {
2862 sprintf(idbuf, "%d", payloads[x].width);
2863 iks_insert_attrib(payload, "width", idbuf);
2864 }
2865 if (payloads[x].height) {
2866 sprintf(idbuf, "%d", payloads[x].height);
2867 iks_insert_attrib(payload, "height", idbuf);
2868 }
2869 if (payloads[x].framerate) {
2870 sprintf(idbuf, "%d", payloads[x].framerate);
2871 iks_insert_attrib(payload, "framerate", idbuf);
2872 }
2873 }
2874
2875 }
2876
2877
2878 //if (vid_mux) {
2879 // iks_insert(tag, "rtcp-mux");
2880 //}
2881
2882 //payload = iks_insert(tag, "vid:src-id");
2883 //iks_insert_cdata(payload, "123456789", 0);
2884
2885
2886 //iks_insert_attrib(payload, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
2887 //iks_insert(payload, "vid:usage");
2888 }
2889 }
2890
2891 for (x = 0; x < plen; x++) {
2892 char idbuf[80];
2893
2894 if (payloads[x].type == LDL_PAYLOAD_VIDEO && !video_call) {
2895 continue;
2896 }
2897
2898 sprintf(idbuf, "%d", payloads[x].id);
2899
2900 if (payloads[x].type == LDL_PAYLOAD_AUDIO) {
2901
2902 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2903 char ratebuf[80];
2904 char buf[80];
2905 iks *param;
2906
2907 jpayload = iks_insert(jin_audio_desc, "rtp:payload-type");
2908 iks_insert_attrib(jpayload, "id", idbuf);
2909 sprintf(ratebuf, "%d", payloads[x].rate);
2910 iks_insert_attrib(jpayload, "name", payloads[x].name);
2911 iks_insert_attrib(jpayload, "clockrate", ratebuf);
2912 param = iks_insert(jpayload, "rtp:parameter");
2913 iks_insert_attrib(param, "name", "bitrate");
2914 sprintf(buf, "%d", payloads[x].bps);
2915 iks_insert_attrib(param, "value", buf);
2916
2917 sprintf(buf, "%d", payloads[x].ptime);
2918 iks_insert_attrib(jpayload, "ptime", ratebuf);
2919 iks_insert_attrib(jpayload, "maxptime", ratebuf);
2920
2921 }
2922
2923 } else if (payloads[x].type == LDL_PAYLOAD_VIDEO && video_call) {
2924
2925 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2926 char buf[80];
2927 iks *param;
2928
2929 jpayload = iks_insert(jin_video_desc, "rtp:payload-type");
2930 iks_insert_attrib(jpayload, "id", idbuf);
2931 iks_insert_attrib(jpayload, "name", payloads[x].name);
2932 param = iks_insert(jpayload, "rtp:parameter");
2933 iks_insert_attrib(param, "name", "width");
2934 sprintf(buf, "%d", payloads[x].width);
2935 iks_insert_attrib(param, "value", buf);
2936
2937
2938 param = iks_insert(jpayload, "rtp:parameter");
2939 iks_insert_attrib(param, "name", "height");
2940 sprintf(buf, "%d", payloads[x].height);
2941 iks_insert_attrib(param, "value", buf);
2942
2943 param = iks_insert(jpayload, "rtp:parameter");
2944 iks_insert_attrib(param, "name", "framerate");
2945 sprintf(buf, "%d", payloads[x].framerate);
2946 iks_insert_attrib(param, "value", buf);
2947
2948 }
2949 }
2950
2951 if (compat) {
2952
2953 if (payloads[x].type == LDL_PAYLOAD_AUDIO) {
2954
2955 payload = iks_insert(tag, "pho:payload-type");
2956
2957 iks_insert_attrib(payload, "id", idbuf);
2958 iks_insert_attrib(payload, "name", payloads[x].name);
2959
2960 if (payloads[x].rate) {
2961 sprintf(idbuf, "%d", payloads[x].rate);
2962 iks_insert_attrib(payload, "clockrate", idbuf);
2963 }
2964
2965 if (payloads[x].bps) {
2966 sprintf(idbuf, "%d", payloads[x].bps);
2967 iks_insert_attrib(payload, "bitrate", idbuf);
2968 }
2969
2970 iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone");
2971 }
2972 }
2973 //if (payloads[x].id == 34) payloads[x].id = 98; /* XXX */
2974
2975 }
2976
2977 if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2978 if (jin_video_desc && video_crypto_data) {
2979 payload = iks_insert(jin_video_desc, "rtp:encryption");
2980 crypto = iks_insert(payload, "rtp:crypto");
2981 iks_insert_attrib(crypto, "crypto-suite", video_crypto_data->suite);
2982 iks_insert_attrib(crypto, "key-params", video_crypto_data->key);
2983 iks_insert_attrib(crypto, "tag", video_crypto_data->tag);
2984 }
2985
2986
2987 if (jin_audio_desc && audio_crypto_data) {
2988 payload = iks_insert(jin_audio_desc, "rtp:encryption");
2989 crypto = iks_insert(payload, "rtp:crypto");
2990 iks_insert_attrib(crypto, "crypto-suite", audio_crypto_data->suite);
2991 iks_insert_attrib(crypto, "key-params", audio_crypto_data->key);
2992 iks_insert_attrib(crypto, "tag", audio_crypto_data->tag);
2993 }
2994 }
2995
2996 //if (aud_mux) {
2997 // iks_insert(tag, "rtcp-mux");
2998 //}
2999
3000 //payload = iks_insert(tag, "pho:src-id");
3001 //iks_insert_cdata(payload, "987654321", 0);
3002 //iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone");
3003
3004 //payload = iks_insert(tag, "rtp:encryption");
3005 //iks_insert_attrib(payload, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
3006 //u = iks_insert(payload, "pho:usage");
3007 //iks_insert_attrib(u, "xmlns:pho", "http://www.google.com/session/phone");
3008
3009 #if 0
3010 if (description == LDL_DESCRIPTION_INITIATE) {
3011 tp = iks_insert (sess, "transport");
3012 iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p");
3013 }
3014 #endif
3015
3016
3017 schedule_packet(session->handle, id, iq, LDL_RETRY);
3018
3019 return id;
3020 }
3021
ldl_session_get_state(ldl_session_t * session)3022 ldl_state_t ldl_session_get_state(ldl_session_t *session)
3023 {
3024 return session->state;
3025 }
3026
ldl_session_get_candidates(ldl_session_t * session,ldl_transport_type_t tport,ldl_candidate_t ** candidates,unsigned int * len)3027 ldl_status ldl_session_get_candidates(ldl_session_t *session, ldl_transport_type_t tport, ldl_candidate_t **candidates, unsigned int *len)
3028 {
3029 assert(tport < LDL_TPORT_MAX);
3030
3031 if (session->candidate_len[tport]) {
3032 *candidates = session->candidates[tport];
3033 *len = session->candidate_len[tport];
3034 return LDL_STATUS_SUCCESS;
3035 } else {
3036 *candidates = NULL;
3037 *len = 0;
3038 return LDL_STATUS_FALSE;
3039 }
3040 }
3041
ldl_session_get_payloads(ldl_session_t * session,ldl_payload_t ** payloads,unsigned int * len)3042 ldl_status ldl_session_get_payloads(ldl_session_t *session, ldl_payload_t **payloads, unsigned int *len)
3043 {
3044 if (session->payload_len) {
3045 *payloads = session->payloads;
3046 *len = session->payload_len;
3047 return LDL_STATUS_SUCCESS;
3048 } else {
3049 *payloads = NULL;
3050 *len = 0;
3051 return LDL_STATUS_FALSE;
3052 }
3053 }
3054
ldl_global_terminate(void)3055 ldl_status ldl_global_terminate(void)
3056 {
3057 if (globals.flag_mutex) {
3058 ldl_clear_flag_locked((&globals), LDL_FLAG_READY);
3059 } else {
3060 ldl_clear_flag((&globals), LDL_FLAG_READY);
3061 }
3062 return LDL_STATUS_SUCCESS;
3063 }
3064
ldl_global_init(int debug)3065 ldl_status ldl_global_init(int debug)
3066 {
3067 if (ldl_test_flag((&globals), LDL_FLAG_INIT)) {
3068 return LDL_STATUS_FALSE;
3069 }
3070
3071 if (apr_initialize() != LDL_STATUS_SUCCESS) {
3072 apr_terminate();
3073 return LDL_STATUS_MEMERR;
3074 }
3075
3076 memset(&globals, 0, sizeof(globals));
3077
3078 if (apr_pool_create(&globals.memory_pool, NULL) != LDL_STATUS_SUCCESS) {
3079 globals.logger(DL_LOG_CRIT, "Could not allocate memory pool\n");
3080 return LDL_STATUS_MEMERR;
3081 }
3082
3083 apr_thread_mutex_create(&globals.flag_mutex, APR_THREAD_MUTEX_NESTED, globals.memory_pool);
3084 globals.log_stream = stdout;
3085 globals.debug = debug;
3086 globals.id = 300;
3087 globals.logger = default_logger;
3088 globals.avatar_hash = apr_hash_make(globals.memory_pool);
3089 ldl_set_flag_locked((&globals), LDL_FLAG_INIT);
3090 ldl_set_flag_locked((&globals), LDL_FLAG_READY);
3091
3092 return LDL_STATUS_SUCCESS;
3093 }
3094
ldl_global_destroy(void)3095 ldl_status ldl_global_destroy(void)
3096 {
3097 if (!ldl_test_flag(&globals, LDL_FLAG_INIT)) {
3098 return LDL_STATUS_FALSE;
3099 }
3100
3101 apr_pool_destroy(globals.memory_pool);
3102 ldl_clear_flag(&globals, LDL_FLAG_INIT);
3103 apr_terminate();
3104
3105 return LDL_STATUS_SUCCESS;
3106 }
3107
ldl_global_set_log_stream(FILE * log_stream)3108 void ldl_global_set_log_stream(FILE *log_stream)
3109 {
3110 assert(ldl_test_flag(&globals, LDL_FLAG_INIT));
3111
3112 globals.log_stream = log_stream;
3113 }
3114
ldl_handle_ready(ldl_handle_t * handle)3115 int8_t ldl_handle_ready(ldl_handle_t *handle)
3116 {
3117 return (int8_t) (ldl_test_flag(handle, LDL_FLAG_RUNNING) && ldl_test_flag((&globals), LDL_FLAG_READY));
3118 }
3119
ldl_handle_init(ldl_handle_t ** handle,char * login,char * password,char * server,ldl_user_flag_t flags,char * status_msg,char * priority,ldl_loop_callback_t loop_callback,ldl_session_callback_t session_callback,ldl_response_callback_t response_callback,void * private_info)3120 ldl_status ldl_handle_init(ldl_handle_t **handle,
3121 char *login,
3122 char *password,
3123 char *server,
3124 ldl_user_flag_t flags,
3125 char *status_msg,
3126 char *priority,
3127 ldl_loop_callback_t loop_callback,
3128 ldl_session_callback_t session_callback,
3129 ldl_response_callback_t response_callback,
3130 void *private_info)
3131 {
3132 apr_pool_t *pool;
3133 assert(ldl_test_flag(&globals, LDL_FLAG_INIT));
3134 *handle = NULL;
3135
3136 if ((apr_pool_create(&pool, globals.memory_pool)) != LDL_STATUS_SUCCESS) {
3137 return LDL_STATUS_MEMERR;
3138 }
3139
3140 if (!login) {
3141 globals.logger(DL_LOG_ERR, "No login supplied!\n");
3142 return LDL_STATUS_FALSE;
3143 }
3144
3145 if (!password) {
3146 globals.logger(DL_LOG_ERR, "No password supplied!\n");
3147 return LDL_STATUS_FALSE;
3148 }
3149
3150
3151 if ((*handle = apr_palloc(pool, sizeof(ldl_handle_t)))) {
3152 ldl_handle_t *new_handle = *handle;
3153 memset(new_handle, 0, sizeof(ldl_handle_t));
3154 new_handle->log_stream = globals.log_stream;
3155 new_handle->login = apr_pstrdup(pool, login);
3156 new_handle->password = apr_pstrdup(pool, password);
3157
3158 if (server) {
3159 char *p;
3160
3161 new_handle->server = apr_pstrdup(pool, server);
3162 if ((p = strchr(new_handle->server, ':'))) {
3163 *p++ = '\0';
3164 new_handle->port = (uint16_t)atoi(p);
3165 }
3166 }
3167
3168 if (status_msg) {
3169 new_handle->status_msg = apr_pstrdup(pool, status_msg);
3170 }
3171
3172 if (priority) {
3173 new_handle->priority = apr_pstrdup(pool, priority);
3174 }
3175
3176 if (loop_callback) {
3177 new_handle->loop_callback = loop_callback;
3178 }
3179
3180 if (session_callback) {
3181 new_handle->session_callback = session_callback;
3182 }
3183
3184 if (response_callback) {
3185 new_handle->response_callback = response_callback;
3186 }
3187
3188 new_handle->private_info = private_info;
3189 new_handle->pool = pool;
3190 new_handle->flags |= flags;
3191 apr_queue_create(&new_handle->queue, LDL_HANDLE_QLEN, new_handle->pool);
3192 apr_queue_create(&new_handle->retry_queue, LDL_HANDLE_QLEN, new_handle->pool);
3193 new_handle->features |= IKS_STREAM_BIND|IKS_STREAM_SESSION;
3194
3195 if (new_handle->flags & LDL_FLAG_SASL_PLAIN) {
3196 new_handle->features |= IKS_STREAM_SASL_PLAIN;
3197 } else if (new_handle->flags & LDL_FLAG_SASL_MD5) {
3198 new_handle->features |= IKS_STREAM_SASL_MD5;
3199 }
3200
3201 new_handle->sessions = apr_hash_make(new_handle->pool);
3202 new_handle->retry_hash = apr_hash_make(new_handle->pool);
3203 new_handle->probe_hash = apr_hash_make(new_handle->pool);
3204 new_handle->sub_hash = apr_hash_make(new_handle->pool);
3205 apr_thread_mutex_create(&new_handle->lock, APR_THREAD_MUTEX_NESTED, new_handle->pool);
3206 apr_thread_mutex_create(&new_handle->flag_mutex, APR_THREAD_MUTEX_NESTED, new_handle->pool);
3207
3208 return LDL_STATUS_SUCCESS;
3209 }
3210
3211 return LDL_STATUS_FALSE;
3212 }
3213
ldl_handle_run(ldl_handle_t * handle)3214 void ldl_handle_run(ldl_handle_t *handle)
3215 {
3216 ldl_clear_flag_locked(handle, LDL_FLAG_STOPPED);
3217 ldl_set_flag_locked(handle, LDL_FLAG_RUNNING);
3218 xmpp_connect(handle, handle->login, handle->password);
3219 ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
3220 }
3221
ldl_handle_running(ldl_handle_t * handle)3222 int ldl_handle_running(ldl_handle_t *handle)
3223 {
3224 return ldl_test_flag(handle, LDL_FLAG_RUNNING) ? 1 : 0;
3225 }
3226
3227
ldl_session_set_gateway(ldl_session_t * session)3228 void ldl_session_set_gateway(ldl_session_t *session)
3229 {
3230 ldl_set_flag(session, LDL_FLAG_GATEWAY);
3231 }
3232
ldl_session_gateway(ldl_session_t * session)3233 int ldl_session_gateway(ldl_session_t *session)
3234 {
3235 return ldl_test_flag(session, LDL_FLAG_GATEWAY) ? 1 : 0;
3236 }
3237
ldl_handle_connected(ldl_handle_t * handle)3238 int ldl_handle_connected(ldl_handle_t *handle)
3239 {
3240 return ldl_test_flag(handle, LDL_FLAG_CONNECTED) ? 1 : 0;
3241 }
3242
ldl_handle_authorized(ldl_handle_t * handle)3243 int ldl_handle_authorized(ldl_handle_t *handle)
3244 {
3245 return ldl_test_flag(handle, LDL_FLAG_AUTHORIZED) ? 1 : 0;
3246 }
3247
ldl_handle_stop(ldl_handle_t * handle)3248 void ldl_handle_stop(ldl_handle_t *handle)
3249 {
3250 ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
3251 #if 0
3252 if (ldl_test_flag(handle, LDL_FLAG_TLS)) {
3253 int fd;
3254 if ((fd = iks_fd(handle->parser)) > -1) {
3255 shutdown(fd, 0x02);
3256 }
3257 }
3258 #endif
3259
3260 while(!ldl_test_flag(handle, LDL_FLAG_STOPPED)) {
3261 microsleep(100);
3262 }
3263
3264 }
3265
ldl_handle_destroy(ldl_handle_t ** handle)3266 ldl_status ldl_handle_destroy(ldl_handle_t **handle)
3267 {
3268 apr_pool_t *pool = (*handle)->pool;
3269
3270 ldl_handle_stop(*handle);
3271 ldl_flush_queue(*handle, 1);
3272
3273
3274 apr_pool_destroy(pool);
3275 *handle = NULL;
3276 return LDL_STATUS_SUCCESS;
3277 }
3278
3279
ldl_handle_set_log_stream(ldl_handle_t * handle,FILE * log_stream)3280 void ldl_handle_set_log_stream(ldl_handle_t *handle, FILE *log_stream)
3281 {
3282 assert(ldl_test_flag(&globals, LDL_FLAG_INIT));
3283
3284 handle->log_stream = log_stream;
3285 }
3286
3287 /* For Emacs:
3288 * Local Variables:
3289 * mode:c
3290 * indent-tabs-mode:t
3291 * tab-width:4
3292 * c-basic-offset:4
3293 * End:
3294 * For VIM:
3295 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
3296 */
3297