1 /*
2 * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2013-2018, Grasshopper
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 mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18 *
19 * The Initial Developer of the Original Code is Grasshopper
20 * Portions created by the Initial Developer are Copyright (C)
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 * Chris Rienzo <chris.rienzo@grasshopper.com>
25 *
26 * mod_rayo.c -- Rayo server / node implementation. Allows MxN clustering of FreeSWITCH and Rayo Clients (like Adhearsion)
27 *
28 */
29 #include <switch.h>
30 #include <iksemel.h>
31
32 #include "mod_rayo.h"
33 #include "rayo_components.h"
34 #include "rayo_elements.h"
35 #include "xmpp_streams.h"
36
37 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown);
38 SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load);
39 SWITCH_MODULE_RUNTIME_FUNCTION(mod_rayo_runtime);
40 SWITCH_MODULE_DEFINITION(mod_rayo, mod_rayo_load, mod_rayo_shutdown, mod_rayo_runtime);
41
42 #define RAYO_CAUSE_HANGUP SWITCH_CAUSE_NORMAL_CLEARING
43 #define RAYO_CAUSE_DECLINE SWITCH_CAUSE_CALL_REJECTED
44 #define RAYO_CAUSE_BUSY SWITCH_CAUSE_USER_BUSY
45 #define RAYO_CAUSE_ERROR SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE
46
47 #define RAYO_END_REASON_HANGUP "hungup"
48 #define RAYO_END_REASON_HANGUP_LOCAL "hangup-command"
49 #define RAYO_END_REASON_TIMEOUT "timeout"
50 #define RAYO_END_REASON_BUSY "busy"
51 #define RAYO_END_REASON_REJECT "rejected"
52 #define RAYO_END_REASON_ERROR "error"
53
54 #define RAYO_SIP_REQUEST_HEADER "sip_h_"
55 #define RAYO_SIP_RESPONSE_HEADER "sip_rh_"
56 #define RAYO_SIP_PROVISIONAL_RESPONSE_HEADER "sip_ph_"
57 #define RAYO_SIP_BYE_RESPONSE_HEADER "sip_bye_h_"
58
59 #define RAYO_CONFIG_FILE "rayo.conf"
60
61 #define JOINED_CALL 1
62 #define JOINED_MIXER 2
63
64 #define OFFER_ALL 0
65 #define OFFER_FIRST 1
66 #define OFFER_RANDOM 2
67
68 struct rayo_actor;
69 struct rayo_client;
70 struct rayo_call;
71
72 #define rayo_call_get_uuid(call) RAYO_ID(call)
73
74 /**
75 * Function pointer wrapper for the handlers hash
76 */
77 struct rayo_xmpp_handler {
78 const char *from_type;
79 const char *from_subtype;
80 const char *to_type;
81 const char *to_subtype;
82 rayo_actor_xmpp_handler fn;
83 };
84
85 /**
86 * Client availability
87 */
88 enum presence_status {
89 PS_UNKNOWN = -1,
90 PS_OFFLINE = 0,
91 PS_ONLINE = 1
92 };
93
94 /**
95 * A xmpp peer server that routes messages to/from clients
96 */
97 struct rayo_peer_server {
98 /** base class */
99 struct rayo_actor base;
100 /** clients connected via this server */
101 switch_hash_t *clients;
102 };
103 #define RAYO_PEER_SERVER(x) ((struct rayo_peer_server *)x)
104
105 /**
106 * A Rayo client that controls calls
107 */
108 struct rayo_client {
109 /** base class */
110 struct rayo_actor base;
111 /** availability */
112 enum presence_status availability;
113 /** set if reachable via s2s */
114 struct rayo_peer_server *peer_server;
115 /** domain or full JID to route to */
116 const char *route;
117 /** time when last probe was sent */
118 switch_time_t last_probe;
119 };
120 #define RAYO_CLIENT(x) ((struct rayo_client *)x)
121
122 /**
123 * A call controlled by a Rayo client
124 */
125 struct rayo_call {
126 /** actor base class */
127 struct rayo_actor base;
128 /** Definitive controlling party JID */
129 char *dcp_jid;
130 /** Potential controlling parties (have sent offers to) */
131 switch_hash_t *pcps;
132 /** Available controlling parties (not sent offers to) */
133 switch_hash_t *acps;
134 /** Number of available controlling parties */
135 int num_acps;
136 /** current idle start time */
137 switch_time_t idle_start_time;
138 /** true if fax is in progress */
139 int faxing;
140 /** 1 if joined to call, 2 if joined to mixer */
141 int joined;
142 /** pending join */
143 iks *pending_join_request;
144 /** ID of joined party TODO this will be many mixers / calls */
145 const char *joined_id;
146 /** set if response needs to be sent to IQ request */
147 const char *dial_request_id;
148 /** channel destroy event */
149 switch_event_t *end_event;
150 /** True if ringing event sent to client */
151 int ringing_sent;
152 /** true if rayo app has started */
153 int rayo_app_started;
154 /** delayed delivery of answer event because rayo APP wasn't started yet */
155 switch_event_t *answer_event;
156 /** True if request to create this call failed */
157 int dial_request_failed;
158 };
159
160 /**
161 * A conference
162 */
163 struct rayo_mixer {
164 /** actor base class */
165 struct rayo_actor base;
166 /** member JIDs */
167 switch_hash_t *members;
168 /** subscriber JIDs */
169 switch_hash_t *subscribers;
170 };
171
172 /**
173 * A member of a mixer
174 */
175 struct rayo_mixer_member {
176 /** JID of member */
177 const char *jid;
178 /** Controlling party JID */
179 const char *dcp_jid;
180 };
181
182 /**
183 * A subscriber to mixer events
184 */
185 struct rayo_mixer_subscriber {
186 /** JID of client */
187 const char *jid;
188 /** Number of client's calls in mixer */
189 int ref_count;
190 };
191
192 /**
193 * Module state
194 */
195 static struct {
196 /** module memory pool */
197 switch_memory_pool_t *pool;
198 /** Rayo <iq> set commands mapped to functions */
199 switch_hash_t *command_handlers;
200 /** Rayo <presence> events mapped to functions */
201 switch_hash_t *event_handlers;
202 /** Active Rayo actors mapped by JID */
203 switch_hash_t *actors;
204 /** Rayo actors pending destruction */
205 switch_hash_t *destroy_actors;
206 /** Active Rayo actors mapped by internal ID */
207 switch_hash_t *actors_by_id;
208 /** synchronizes access to actors */
209 switch_mutex_t *actors_mutex;
210 /** map of DCP JID to client */
211 switch_hash_t *clients_roster;
212 /** synchronizes access to available clients */
213 switch_mutex_t *clients_mutex;
214 /** server for calls/mixers/etc */
215 struct rayo_actor *server;
216 /** Maximum idle time before call is considered abandoned */
217 int max_idle_ms;
218 /** Conference profile to use for mixers */
219 char *mixer_conf_profile;
220 /** to URI prefixes mapped to gateways */
221 switch_hash_t *dial_gateways;
222 /** synchronizes access to dial gateways */
223 switch_mutex_t *dial_gateways_mutex;
224 /** console command aliases */
225 switch_hash_t *cmd_aliases;
226 /** global console */
227 struct rayo_client *console;
228 /** XMPP context */
229 struct xmpp_stream_context *xmpp_context;
230 /** number of message threads */
231 int num_message_threads;
232 /** message delivery queue */
233 switch_queue_t *msg_queue;
234 /** in progress offer queue */
235 switch_queue_t *offer_queue;
236 /** shutdown flag */
237 int shutdown;
238 /** prevents context shutdown until all threads are finished */
239 switch_thread_rwlock_t *shutdown_rwlock;
240 /** if true, URI is put in from/to of offer if available */
241 int offer_uri;
242 /** if true, pause inbound calling if all clients are offline */
243 int pause_when_offline;
244 /** flag to reduce log noise */
245 int offline_logged;
246 /** if true, channel variables are added to offer */
247 int add_variables_to_offer;
248 /** if true, channel variables are added to answered, ringing, end events */
249 int add_variables_to_events;
250 /** How to distribute offers to clients */
251 int offer_algorithm;
252 /** How long to wait for offer response before retrying */
253 int offer_timeout_us;
254 } globals;
255
256 /**
257 * An outbound dial gateway
258 */
259 struct dial_gateway {
260 /** URI prefix to match */
261 const char *uri_prefix;
262 /** dial prefix to match */
263 const char *dial_prefix;
264 /** number of digits to strip from dialstring */
265 int strip;
266 };
267
268 static void rayo_call_send(struct rayo_actor *call, struct rayo_message *msg);
269 static void rayo_server_send(struct rayo_actor *server, struct rayo_message *msg);
270 static void rayo_mixer_send(struct rayo_actor *mixer, struct rayo_message *msg);
271 static void rayo_component_send(struct rayo_actor *component, struct rayo_message *msg);
272 static void rayo_client_send(struct rayo_actor *client, struct rayo_message *msg);
273 static void rayo_console_client_send(struct rayo_actor *client, struct rayo_message *msg);
274
275 static void on_client_presence(struct rayo_client *rclient, iks *node);
276
277 typedef switch_bool_t (* rayo_actor_match_fn)(struct rayo_actor *);
278
279 static switch_bool_t is_call_actor(struct rayo_actor *actor);
280
281 static void rayo_call_send_end(struct rayo_call *call, switch_event_t *event, int local_hangup, const char *cause_str, const char *cause_q850_str);
282
283
284 /**
285 * Entity features returned by service discovery
286 */
287 struct entity_identity {
288 /** identity category */
289 const char *category;
290 /** identity type */
291 const char *type;
292 };
293
294 static struct entity_identity rayo_server_identity = { "server", "im" };
295 static const char *rayo_server_features[] = { IKS_NS_XMPP_ENTITY_CAPABILITIES, IKS_NS_XMPP_DISCO, RAYO_NS, RAYO_CPA_NS, RAYO_FAX_NS, 0 };
296
297 static struct entity_identity rayo_mixer_identity = { "client", "rayo_mixer" };
298 static const char *rayo_mixer_features[] = { 0 };
299
300 static struct entity_identity rayo_call_identity = { "client", "rayo_call" };
301 static const char *rayo_call_features[] = { 0 };
302
303 /**
304 * Calculate SHA-1 hash of entity capabilities
305 * @param identity of entity
306 * @param features of identity (NULL terminated)
307 * @return base64 hash (free when done)
308 */
calculate_entity_sha1_ver(struct entity_identity * identity,const char ** features)309 static char *calculate_entity_sha1_ver(struct entity_identity *identity, const char **features)
310 {
311 int i;
312 const char *feature;
313 char ver[SHA_1_HASH_BUF_SIZE + 1] = { 0 };
314 iksha *sha;
315
316 sha = iks_sha_new();
317 iks_sha_hash(sha, (const unsigned char *)identity->category, strlen(identity->category), 0);
318 iks_sha_hash(sha, (const unsigned char *)"/", 1, 0);
319 iks_sha_hash(sha, (const unsigned char *)identity->type, strlen(identity->type), 0);
320 iks_sha_hash(sha, (const unsigned char *)"//", 2, 0);
321 i = 0;
322 while ((feature = features[i++])) {
323 iks_sha_hash(sha, (const unsigned char *)"<", 1, 0);
324 iks_sha_hash(sha, (const unsigned char *)feature, strlen(feature), 0);
325 }
326 iks_sha_hash(sha, (const unsigned char *)"<", 1, 1);
327 iks_sha_print_base64(sha, ver);
328 iks_sha_delete(sha);
329
330 return strdup(ver);
331 }
332
333 /**
334 * @param msg to check
335 * @return true if message was sent by admin client (console)
336 */
is_admin_client_message(struct rayo_message * msg)337 static int is_admin_client_message(struct rayo_message *msg)
338 {
339 return !zstr(msg->from_jid) && !strcmp(RAYO_JID(globals.console), msg->from_jid);
340 }
341
342 /**
343 * @param msg to check
344 * @return true if from/to bare JIDs match
345 */
is_internal_message(struct rayo_message * msg)346 static int is_internal_message(struct rayo_message *msg)
347 {
348 return msg->from && msg->to && (iks_id_cmp(msg->from, msg->to, IKS_ID_PARTIAL) == 0);
349 }
350
351 /**
352 * Presence status
353 * @param status the presence status
354 * @return the string value of status
355 */
presence_status_to_string(enum presence_status status)356 static const char *presence_status_to_string(enum presence_status status)
357 {
358 switch(status) {
359 case PS_OFFLINE: return "OFFLINE";
360 case PS_ONLINE: return "ONLINE";
361 case PS_UNKNOWN: return "UNKNOWN";
362 }
363 return "UNKNOWN";
364 }
365
366 /**
367 * Get rayo cause code from FS hangup cause
368 * @param cause FS hangup cause
369 * @return rayo end cause
370 */
switch_cause_to_rayo_cause(switch_call_cause_t cause)371 static const char *switch_cause_to_rayo_cause(switch_call_cause_t cause)
372 {
373 switch (cause) {
374 case SWITCH_CAUSE_NONE:
375 case SWITCH_CAUSE_NORMAL_CLEARING:
376 return RAYO_END_REASON_HANGUP;
377
378 case SWITCH_CAUSE_UNALLOCATED_NUMBER:
379 case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
380 case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
381 case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
382 return RAYO_END_REASON_ERROR;
383
384 case SWITCH_CAUSE_CALL_AWARDED_DELIVERED:
385 return RAYO_END_REASON_HANGUP;
386
387 case SWITCH_CAUSE_USER_BUSY:
388 return RAYO_END_REASON_BUSY;
389
390 case SWITCH_CAUSE_NO_USER_RESPONSE:
391 case SWITCH_CAUSE_NO_ANSWER:
392 return RAYO_END_REASON_TIMEOUT;
393
394 case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
395 return RAYO_END_REASON_ERROR;
396
397 case SWITCH_CAUSE_CALL_REJECTED:
398 return RAYO_END_REASON_REJECT;
399
400 case SWITCH_CAUSE_NUMBER_CHANGED:
401 case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION:
402 case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR:
403 case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
404 case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
405 return RAYO_END_REASON_ERROR;
406
407 case SWITCH_CAUSE_FACILITY_REJECTED:
408 return RAYO_END_REASON_REJECT;
409
410 case SWITCH_CAUSE_RESPONSE_TO_STATUS_ENQUIRY:
411 case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
412 return RAYO_END_REASON_HANGUP;
413
414 case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
415 case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
416 case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE:
417 case SWITCH_CAUSE_SWITCH_CONGESTION:
418 case SWITCH_CAUSE_ACCESS_INFO_DISCARDED:
419 case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
420 case SWITCH_CAUSE_PRE_EMPTED:
421 case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
422 case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
423 case SWITCH_CAUSE_INCOMING_CALL_BARRED:
424 case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH:
425 case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL:
426 case SWITCH_CAUSE_SERVICE_UNAVAILABLE:
427 case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL:
428 case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
429 case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
430 case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED:
431 case SWITCH_CAUSE_INVALID_CALL_REFERENCE:
432 case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
433 case SWITCH_CAUSE_INVALID_MSG_UNSPECIFIED:
434 case SWITCH_CAUSE_MANDATORY_IE_MISSING:
435 return RAYO_END_REASON_ERROR;
436
437 case SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST:
438 case SWITCH_CAUSE_WRONG_MESSAGE:
439 case SWITCH_CAUSE_IE_NONEXIST:
440 case SWITCH_CAUSE_INVALID_IE_CONTENTS:
441 case SWITCH_CAUSE_WRONG_CALL_STATE:
442 case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
443 case SWITCH_CAUSE_MANDATORY_IE_LENGTH_ERROR:
444 case SWITCH_CAUSE_PROTOCOL_ERROR:
445 return RAYO_END_REASON_ERROR;
446
447 case SWITCH_CAUSE_INTERWORKING:
448 case SWITCH_CAUSE_SUCCESS:
449 case SWITCH_CAUSE_ORIGINATOR_CANCEL:
450 return RAYO_END_REASON_HANGUP;
451
452 case SWITCH_CAUSE_CRASH:
453 case SWITCH_CAUSE_SYSTEM_SHUTDOWN:
454 case SWITCH_CAUSE_LOSE_RACE:
455 case SWITCH_CAUSE_MANAGER_REQUEST:
456 case SWITCH_CAUSE_BLIND_TRANSFER:
457 case SWITCH_CAUSE_ATTENDED_TRANSFER:
458 case SWITCH_CAUSE_ALLOTTED_TIMEOUT:
459 case SWITCH_CAUSE_USER_CHALLENGE:
460 case SWITCH_CAUSE_MEDIA_TIMEOUT:
461 case SWITCH_CAUSE_PICKED_OFF:
462 case SWITCH_CAUSE_USER_NOT_REGISTERED:
463 case SWITCH_CAUSE_PROGRESS_TIMEOUT:
464 case SWITCH_CAUSE_INVALID_GATEWAY:
465 case SWITCH_CAUSE_GATEWAY_DOWN:
466 case SWITCH_CAUSE_INVALID_URL:
467 case SWITCH_CAUSE_INVALID_PROFILE:
468 case SWITCH_CAUSE_NO_PICKUP:
469 case SWITCH_CAUSE_SRTP_READ_ERROR:
470 return RAYO_END_REASON_ERROR;
471 default:
472 break;
473 }
474 return RAYO_END_REASON_HANGUP;
475 }
476
477 /**
478 * Add <header> to node
479 * @param node to add <header> to
480 * @param name of header
481 * @param value of header
482 */
add_header(iks * node,const char * name,const char * value)483 static void add_header(iks *node, const char *name, const char *value)
484 {
485 if (!zstr(name) && !zstr(value)) {
486 iks *header = iks_insert(node, "header");
487 iks_insert_attrib(header, "name", name);
488 iks_insert_attrib(header, "value", value);
489 }
490 }
491
492 /**
493 * Add SIP <header>s to node
494 * @param node to add <header> to
495 * @param event source
496 * @param add_variables true if channel variables should be added
497 */
add_headers_to_event(iks * node,switch_event_t * event,int add_variables)498 static void add_headers_to_event(iks *node, switch_event_t *event, int add_variables)
499 {
500 switch_event_header_t *header;
501 /* get all variables prefixed with sip_h_ */
502 for (header = event->headers; header; header = header->next) {
503 if (!strncmp("variable_sip_h_", header->name, 15)) {
504 if (!zstr(header->name)) {
505 add_header(node, header->name + 15, header->value);
506 }
507 } else if (add_variables && !strncmp("variable_", header->name, 9)) {
508 if (!zstr(header->name)) {
509 char header_name[1024];
510 snprintf(header_name, 1024, "variable-%s", header->name + 9);
511 add_header(node, header_name, header->value);
512 }
513 }
514 }
515 }
516
517 /**
518 * Add SIP <header>s to node
519 * @param node to add <header> to
520 * @param add_variables true if channel variables should be added
521 */
add_channel_headers_to_event(iks * node,switch_channel_t * channel,int add_variables)522 static void add_channel_headers_to_event(iks *node, switch_channel_t *channel, int add_variables)
523 {
524 switch_event_header_t *var;
525
526 /* add all SIP header variables and (if configured) all other variables */
527 for (var = switch_channel_variable_first(channel); var; var = var->next) {
528 if (!strncmp("sip_h_", var->name, 6)) {
529 add_header(node, var->name + 6, var->value);
530 }
531 if (add_variables) {
532 char var_name[1024];
533 snprintf(var_name, 1024, "variable-%s", var->name);
534 add_header(node, var_name, var->value);
535 }
536 }
537 switch_channel_variable_last(channel);
538 }
539
pause_inbound_calling(void)540 static void pause_inbound_calling(void)
541 {
542 int32_t arg = 1;
543 switch_mutex_lock(globals.clients_mutex);
544 switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
545 if (!globals.offline_logged) {
546 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Pausing inbound calling\n");
547 globals.offline_logged = 1;
548 }
549 switch_mutex_unlock(globals.clients_mutex);
550 }
551
resume_inbound_calling(void)552 static void resume_inbound_calling(void)
553 {
554 int32_t arg = 0;
555 switch_mutex_lock(globals.clients_mutex);
556 switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
557 if (globals.offline_logged) {
558 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Resuming inbound calling\n");
559 globals.offline_logged = 0;
560 }
561 switch_mutex_unlock(globals.clients_mutex);
562 }
563
564 /**
565 * Check online status of rayo client(s) and pause/resume the server
566 */
pause_when_offline(void)567 static void pause_when_offline(void)
568 {
569 if (globals.pause_when_offline) {
570 int is_online = 0;
571 switch_hash_index_t *hi;
572
573 switch_mutex_lock(globals.clients_mutex);
574
575 for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) {
576 const void *key;
577 void *client;
578 switch_core_hash_this(hi, &key, NULL, &client);
579 switch_assert(client);
580 if (RAYO_CLIENT(client)->availability == PS_ONLINE) {
581 is_online = 1;
582 break;
583 }
584 }
585 switch_safe_free(hi);
586
587 if (is_online) {
588 resume_inbound_calling();
589 } else {
590 pause_inbound_calling();
591 }
592
593 switch_mutex_unlock(globals.clients_mutex);
594 }
595 }
596
597 /**
598 * Send event to clients
599 * @param from event sender
600 * @param rayo_event the event to send
601 * @param online_only only send to online clients
602 */
broadcast_event(struct rayo_actor * from,iks * rayo_event,int online_only)603 static void broadcast_event(struct rayo_actor *from, iks *rayo_event, int online_only)
604 {
605 switch_hash_index_t *hi = NULL;
606 switch_mutex_lock(globals.clients_mutex);
607 for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) {
608 struct rayo_client *rclient;
609 const void *key;
610 void *val;
611 switch_core_hash_this(hi, &key, NULL, &val);
612 rclient = (struct rayo_client *)val;
613 switch_assert(rclient);
614
615 if (!online_only || rclient->availability == PS_ONLINE) {
616 iks_insert_attrib(rayo_event, "to", RAYO_JID(rclient));
617 RAYO_SEND_MESSAGE_DUP(from, RAYO_JID(rclient), rayo_event);
618 }
619 }
620 switch_mutex_unlock(globals.clients_mutex);
621 }
622
623 /**
624 * Add an outbound dialing gateway
625 * @param uri_prefix to match
626 * @param dial_prefix to use
627 * @param strip number of digits to strip from dialstring
628 */
dial_gateway_add(const char * uri_prefix,const char * dial_prefix,int strip)629 static void dial_gateway_add(const char *uri_prefix, const char *dial_prefix, int strip)
630 {
631 struct dial_gateway *gateway = switch_core_alloc(globals.pool, sizeof(*gateway));
632 gateway->uri_prefix = uri_prefix ? switch_core_strdup(globals.pool, uri_prefix) : "";
633 gateway->dial_prefix = dial_prefix ? switch_core_strdup(globals.pool, dial_prefix) : "";
634 gateway->strip = strip > 0 ? strip : 0;
635 switch_core_hash_insert(globals.dial_gateways, uri_prefix, gateway);
636 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dial-gateway uriprefix = %s, dialprefix = %s, strip = %i\n", uri_prefix, dial_prefix, strip);
637 }
638
639 /**
640 * Find outbound dial gateway for the specified dialstring
641 */
dial_gateway_find(const char * uri)642 static struct dial_gateway *dial_gateway_find(const char *uri)
643 {
644 switch_hash_index_t *hi = NULL;
645 int match_len = 0;
646 struct dial_gateway *gateway = (struct dial_gateway *)switch_core_hash_find(globals.dial_gateways, "default");
647
648 /* find longest prefix match */
649 switch_mutex_lock(globals.dial_gateways_mutex);
650 for (hi = switch_core_hash_first(globals.dial_gateways); hi; hi = switch_core_hash_next(&hi)) {
651 struct dial_gateway *candidate = NULL;
652 const void *prefix;
653 int prefix_len = 0;
654 void *val;
655 switch_core_hash_this(hi, &prefix, NULL, &val);
656 candidate = (struct dial_gateway *)val;
657 switch_assert(candidate);
658
659 prefix_len = strlen(prefix);
660 if (!zstr(prefix) && !strncmp(prefix, uri, prefix_len) && prefix_len > match_len) {
661 match_len = prefix_len;
662 gateway = candidate;
663 }
664 }
665 switch_mutex_unlock(globals.dial_gateways_mutex);
666 return gateway;
667 }
668
669 /**
670 * Add command handler function
671 * @param name the command name
672 * @param handler the command handler function
673 */
rayo_command_handler_add(const char * name,struct rayo_xmpp_handler * handler)674 static void rayo_command_handler_add(const char *name, struct rayo_xmpp_handler *handler)
675 {
676 char full_name[1024];
677 full_name[1023] = '\0';
678 snprintf(full_name, sizeof(full_name) - 1, "%s:%s:%s", handler->to_type, handler->to_subtype, name);
679 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding command: %s\n", full_name);
680 switch_core_hash_insert(globals.command_handlers, full_name, handler);
681 }
682
683 /**
684 * Add command handler function
685 * @param type the actor type
686 * @param subtype the actor subtype
687 * @param name the command name
688 * @param fn the command callback function
689 */
rayo_actor_command_handler_add(const char * type,const char * subtype,const char * name,rayo_actor_xmpp_handler fn)690 void rayo_actor_command_handler_add(const char *type, const char *subtype, const char *name, rayo_actor_xmpp_handler fn)
691 {
692 struct rayo_xmpp_handler *handler = switch_core_alloc(globals.pool, sizeof (*handler));
693 handler->to_type = zstr(type) ? "" : switch_core_strdup(globals.pool, type);
694 handler->to_subtype = zstr(subtype) ? "" : switch_core_strdup(globals.pool, subtype);
695 handler->fn = fn;
696 rayo_command_handler_add(name, handler);
697 }
698
699 /**
700 * Get command handler function from hash
701 * @param hash the hash to search
702 * @param msg the command
703 * @return the command handler function or NULL
704 */
rayo_actor_command_handler_find(struct rayo_actor * actor,struct rayo_message * msg)705 rayo_actor_xmpp_handler rayo_actor_command_handler_find(struct rayo_actor *actor, struct rayo_message *msg)
706 {
707 iks *iq = msg->payload;
708 const char *iq_type = iks_find_attrib_soft(iq, "type");
709 iks *command = iks_first_tag(iq);
710 const char *name = "";
711 const char *namespace = "";
712 struct rayo_xmpp_handler *handler = NULL;
713 char full_name[1024];
714
715 full_name[1023] = '\0';
716 if (command) {
717 name = iks_name(command);
718 namespace = iks_find_attrib_soft(command, "xmlns");
719 if (zstr(name)) {
720 name = "";
721 }
722 }
723
724 snprintf(full_name, sizeof(full_name) - 1, "%s:%s:%s:%s:%s", actor->type, actor->subtype, iq_type, namespace, name);
725 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, looking for %s command\n", RAYO_JID(actor), full_name);
726 handler = (struct rayo_xmpp_handler *)switch_core_hash_find(globals.command_handlers, full_name);
727 if (handler) {
728 return handler->fn;
729 }
730
731 return NULL;
732 }
733
734 /**
735 * Add event handler function
736 * @param name the event name
737 * @param handler the event handler function
738 */
rayo_event_handler_add(const char * name,struct rayo_xmpp_handler * handler)739 static void rayo_event_handler_add(const char *name, struct rayo_xmpp_handler *handler)
740 {
741 char full_name[1024];
742 full_name[1023] = '\0';
743 snprintf(full_name, sizeof(full_name) - 1, "%s:%s:%s:%s:%s", handler->from_type, handler->from_subtype, handler->to_type, handler->to_subtype, name);
744 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding event: %s\n", full_name);
745 switch_core_hash_insert(globals.event_handlers, full_name, handler);
746 }
747
748 /**
749 * Add event handler function
750 * @param from_type the source actor type
751 * @param from_subtype the source actor subtype
752 * @param to_type the destination actor type
753 * @param to_subtype the destination actor subtype
754 * @param name the event name
755 * @param fn the event callback function
756 */
rayo_actor_event_handler_add(const char * from_type,const char * from_subtype,const char * to_type,const char * to_subtype,const char * name,rayo_actor_xmpp_handler fn)757 void rayo_actor_event_handler_add(const char *from_type, const char *from_subtype, const char *to_type, const char *to_subtype, const char *name, rayo_actor_xmpp_handler fn)
758 {
759 struct rayo_xmpp_handler *handler = switch_core_alloc(globals.pool, sizeof (*handler));
760 handler->from_type = zstr(from_type) ? "" : switch_core_strdup(globals.pool, from_type);
761 handler->from_subtype = zstr(from_subtype) ? "" : switch_core_strdup(globals.pool, from_subtype);
762 handler->to_type = zstr(to_type) ? "" : switch_core_strdup(globals.pool, to_type);
763 handler->to_subtype = zstr(to_subtype) ? "" : switch_core_strdup(globals.pool, to_subtype);
764 handler->fn = fn;
765 rayo_event_handler_add(name, handler);
766 }
767
768 /**
769 * Get event handler function from hash
770 * @param actor the event destination
771 * @param msg the event
772 * @return the event handler function or NULL
773 */
rayo_actor_event_handler_find(struct rayo_actor * actor,struct rayo_message * msg)774 rayo_actor_xmpp_handler rayo_actor_event_handler_find(struct rayo_actor *actor, struct rayo_message *msg)
775 {
776 iks *presence = msg->payload;
777 iks *event = iks_first_tag(presence);
778 if (event) {
779 struct rayo_xmpp_handler *handler = NULL;
780 const char *presence_type = iks_find_attrib_soft(presence, "type");
781 const char *event_name = iks_name(event);
782 const char *event_namespace = iks_find_attrib_soft(event, "xmlns");
783 char full_name[1024];
784 full_name[1023] = '\0';
785 if (zstr(event_name)) {
786 return NULL;
787 }
788 snprintf(full_name, sizeof(full_name) - 1, "%s:%s:%s:%s:%s:%s:%s", msg->from_type, msg->from_subtype, actor->type, actor->subtype, presence_type, event_namespace, event_name);
789 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s => %s, looking for %s event handler\n", msg->from_jid, RAYO_JID(actor), full_name);
790 handler = (struct rayo_xmpp_handler *)switch_core_hash_find(globals.event_handlers, full_name);
791 if (handler) {
792 return handler->fn;
793 }
794 } else {
795 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s => %s, event missing child element\n", msg->from_jid, RAYO_JID(actor));
796 }
797 return NULL;
798 }
799
800 /**
801 * Clean up a message
802 * @param msg to destroy
803 */
rayo_message_destroy(struct rayo_message * msg)804 void rayo_message_destroy(struct rayo_message *msg)
805 {
806 if (msg) {
807 if (msg->payload) {
808 iks_delete(msg->payload);
809 }
810 switch_safe_free(msg->to_jid);
811 switch_safe_free(msg->from_jid);
812 switch_safe_free(msg->from_type);
813 switch_safe_free(msg->from_subtype);
814 switch_safe_free(msg->file);
815 free(msg);
816 }
817 }
818
819 /**
820 * Remove payload from message
821 */
rayo_message_remove_payload(struct rayo_message * msg)822 iks *rayo_message_remove_payload(struct rayo_message *msg)
823 {
824 iks *payload = msg->payload;
825 msg->payload = NULL;
826 msg->from = NULL;
827 msg->to = NULL;
828 return payload;
829 }
830
831 /**
832 * Thread that delivers internal XMPP messages
833 * @param thread this thread
834 * @param obj unused
835 * @return NULL
836 */
deliver_message_thread(switch_thread_t * thread,void * obj)837 static void *SWITCH_THREAD_FUNC deliver_message_thread(switch_thread_t *thread, void *obj)
838 {
839 struct rayo_message *msg = NULL;
840 switch_thread_rwlock_rdlock(globals.shutdown_rwlock);
841 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New message delivery thread\n");
842 while (!globals.shutdown) {
843 if (switch_queue_pop(globals.msg_queue, (void *)&msg) == SWITCH_STATUS_SUCCESS) {
844 struct rayo_actor *actor = RAYO_LOCATE(msg->to_jid);
845 if (actor) {
846 /* deliver to actor */
847 switch_mutex_lock(actor->mutex);
848 switch_log_printf(SWITCH_CHANNEL_ID_LOG, msg->file, "", msg->line, "", SWITCH_LOG_DEBUG, "Deliver %s => %s %s\n", msg->from_jid, msg->to_jid, iks_string(iks_stack(msg->payload), msg->payload));
849 actor->send_fn(actor, msg);
850 switch_mutex_unlock(actor->mutex);
851 RAYO_RELEASE(actor);
852 } else if (!msg->is_reply) {
853 /* unknown actor */
854 RAYO_SEND_REPLY(globals.server, msg->from_jid, iks_new_error(msg->payload, STANZA_ERROR_ITEM_NOT_FOUND));
855 }
856 rayo_message_destroy(msg);
857 }
858 }
859
860 /* clean up remaining messages */
861 while(switch_queue_trypop(globals.msg_queue, (void *)&msg) == SWITCH_STATUS_SUCCESS) {
862 rayo_message_destroy(msg);
863 }
864
865 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Message delivery thread finished\n");
866 switch_thread_rwlock_unlock(globals.shutdown_rwlock);
867 return NULL;
868 }
869
870 /**
871 * Create a new message thread
872 * @param pool to use
873 */
start_deliver_message_thread(switch_memory_pool_t * pool)874 static void start_deliver_message_thread(switch_memory_pool_t *pool)
875 {
876 switch_thread_t *thread;
877 switch_threadattr_t *thd_attr = NULL;
878 switch_threadattr_create(&thd_attr, pool);
879 switch_threadattr_detach_set(thd_attr, 1);
880 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
881 switch_thread_create(&thread, thd_attr, deliver_message_thread, NULL, pool);
882 }
883
884 /**
885 * Stop all threads
886 */
stop_all_threads(void)887 static void stop_all_threads(void)
888 {
889 globals.shutdown = 1;
890 if (globals.msg_queue) {
891 switch_queue_interrupt_all(globals.msg_queue);
892 }
893 if (globals.offer_queue) {
894 switch_queue_interrupt_all(globals.offer_queue);
895 }
896 if (globals.shutdown_rwlock) {
897 switch_thread_rwlock_wrlock(globals.shutdown_rwlock);
898 }
899 }
900
901 /**
902 * Send message to actor addressed by JID
903 * @param from actor sending the message
904 * @param to destination JID
905 * @param payload the message payload to deliver
906 * @param dup true if payload is to be copied
907 * @param reply true if a reply
908 * @param file file name
909 * @param line line number
910 */
rayo_message_send(struct rayo_actor * from,const char * to,iks * payload,int dup,int reply,const char * file,int line)911 void rayo_message_send(struct rayo_actor *from, const char *to, iks *payload, int dup, int reply, const char *file, int line)
912 {
913 const char *msg_name;
914 struct rayo_message *msg = malloc(sizeof(*msg));
915 switch_assert(msg);
916 if (dup) {
917 msg->payload = iks_copy(payload);
918 } else {
919 msg->payload = payload;
920 }
921 msg->is_reply = reply;
922 msg->to_jid = strdup(zstr(to) ? "" : to);
923 if (!zstr(msg->to_jid)) {
924 msg->to = iks_id_new(iks_stack(msg->payload), msg->to_jid);
925 }
926 msg->from_jid = strdup(RAYO_JID(from));
927 if (!zstr(msg->from_jid)) {
928 msg->from = iks_id_new(iks_stack(msg->payload), msg->from_jid);
929 }
930 msg->from_type = strdup(zstr(from->type) ? "" : from->type);
931 msg->from_subtype = strdup(zstr(from->subtype) ? "" : from->subtype);
932 msg->file = strdup(file);
933 msg->line = line;
934
935 /* add timestamp to presence events */
936 msg_name = iks_name(msg->payload);
937 if (!zstr(msg_name) && !strcmp("presence", msg_name)) {
938 /* don't add timestamp if there already is one */
939 iks *delay = iks_find(msg->payload, "delay");
940 if (!delay || strcmp("urn:xmpp:delay", iks_find_attrib_soft(delay, "xmlns"))) {
941 switch_time_exp_t tm;
942 char timestamp[80];
943 switch_size_t retsize;
944 delay = iks_insert(msg->payload, "delay");
945 iks_insert_attrib(delay, "xmlns", "urn:xmpp:delay");
946 switch_time_exp_tz(&tm, switch_time_now(), 0);
947 switch_strftime_nocheck(timestamp, &retsize, sizeof(timestamp), "%Y-%m-%dT%TZ", &tm);
948 iks_insert_attrib_printf(delay, "stamp", "%s", timestamp);
949 }
950 }
951
952 if (switch_queue_trypush(globals.msg_queue, msg) != SWITCH_STATUS_SUCCESS) {
953 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to queue message!\n");
954 rayo_message_destroy(msg);
955 }
956 }
957
958 /**
959 * Get access to Rayo actor with JID.
960 * @param jid the JID
961 * @return the actor or NULL. Call RAYO_RELEASE() when done with pointer.
962 */
rayo_actor_locate(const char * jid,const char * file,int line)963 struct rayo_actor *rayo_actor_locate(const char *jid, const char *file, int line)
964 {
965 struct rayo_actor *actor = NULL;
966 switch_mutex_lock(globals.actors_mutex);
967 if (!strncmp("xmpp:", jid, 5)) {
968 jid = jid + 5;
969 }
970 actor = (struct rayo_actor *)switch_core_hash_find(globals.actors, jid);
971 if (actor) {
972 if (!actor->destroy) {
973 actor->ref_count++;
974 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Locate (jid) %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count);
975 } else {
976 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_WARNING, "Locate (jid) %s: already marked for destruction!\n", jid);
977 actor = NULL;
978 }
979 }
980 switch_mutex_unlock(globals.actors_mutex);
981 return actor;
982 }
983
984 /**
985 * Get exclusive access to Rayo actor with internal ID
986 * @param id the internal ID
987 * @return the actor or NULL. Call RAYO_RELEASE() when done with pointer.
988 */
rayo_actor_locate_by_id(const char * id,const char * file,int line)989 struct rayo_actor *rayo_actor_locate_by_id(const char *id, const char *file, int line)
990 {
991 struct rayo_actor *actor = NULL;
992 if (!zstr(id)) {
993 switch_mutex_lock(globals.actors_mutex);
994 actor = (struct rayo_actor *)switch_core_hash_find(globals.actors_by_id, id);
995 if (actor) {
996 if (!actor->destroy) {
997 actor->ref_count++;
998 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Locate (id) %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count);
999 } else {
1000 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_WARNING, "Locate (id) %s: already marked for destruction!\n", id);
1001 actor = NULL;
1002 }
1003 }
1004 switch_mutex_unlock(globals.actors_mutex);
1005 }
1006 return actor;
1007 }
1008
1009 /**
1010 * Destroy a rayo actor
1011 */
rayo_actor_destroy(struct rayo_actor * actor,const char * file,int line)1012 void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int line)
1013 {
1014 switch_memory_pool_t *pool = actor->pool;
1015 switch_mutex_lock(globals.actors_mutex);
1016 if (!actor->destroy) {
1017 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Destroy %s requested: ref_count = %i\n", RAYO_JID(actor), actor->ref_count);
1018 switch_core_hash_delete(globals.actors, RAYO_JID(actor));
1019 if (!zstr(actor->id)) {
1020 switch_core_hash_delete(globals.actors_by_id, actor->id);
1021 }
1022 }
1023 actor->destroy = 1;
1024 if (actor->ref_count <= 0) {
1025 if (actor->ref_count < 0) {
1026 /* too many unlocks detected! */
1027 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_WARNING, "Destroying %s, ref_count = %i\n", RAYO_JID(actor), actor->ref_count);
1028 } else {
1029 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Destroying %s\n", RAYO_JID(actor));
1030 }
1031 switch_core_hash_delete(globals.destroy_actors, RAYO_JID(actor));
1032 switch_mutex_unlock(globals.actors_mutex);
1033 /* safe to destroy parent now */
1034 if (actor->cleanup_fn) {
1035 actor->cleanup_fn(actor);
1036 }
1037 if (actor->parent) {
1038 RAYO_RELEASE(actor->parent);
1039 }
1040 switch_core_destroy_memory_pool(&pool);
1041 } else {
1042 switch_core_hash_insert(globals.destroy_actors, RAYO_JID(actor), actor);
1043 switch_mutex_unlock(globals.actors_mutex);
1044 }
1045 }
1046
1047 /**
1048 * Increment actor ref count - locks from destruction.
1049 */
rayo_actor_retain(struct rayo_actor * actor,const char * file,int line)1050 void rayo_actor_retain(struct rayo_actor *actor, const char *file, int line)
1051 {
1052 if (actor) {
1053 switch_mutex_lock(globals.actors_mutex);
1054 actor->ref_count++;
1055 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Lock %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count);
1056 switch_mutex_unlock(globals.actors_mutex);
1057 }
1058 }
1059
1060 /**
1061 * Release rayo actor reference
1062 */
rayo_actor_release(struct rayo_actor * actor,const char * file,int line)1063 void rayo_actor_release(struct rayo_actor *actor, const char *file, int line)
1064 {
1065 if (actor) {
1066 switch_mutex_lock(globals.actors_mutex);
1067 actor->ref_count--;
1068 if (actor->ref_count < 0) {
1069 /* too many unlocks detected! */
1070 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_WARNING, "Release %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count);
1071 } else {
1072 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Release %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count);
1073 }
1074 if (actor->ref_count <= 0 && actor->destroy) {
1075 rayo_actor_destroy(actor, file, line);
1076 }
1077 switch_mutex_unlock(globals.actors_mutex);
1078 }
1079 }
1080
1081 /**
1082 * Get next number in sequence
1083 */
rayo_actor_seq_next(struct rayo_actor * actor)1084 int rayo_actor_seq_next(struct rayo_actor *actor)
1085 {
1086 int seq;
1087 switch_mutex_lock(actor->mutex);
1088 seq = actor->seq++;
1089 switch_mutex_unlock(actor->mutex);
1090 return seq;
1091 }
1092
1093 #define RAYO_CALL_LOCATE(call_uri) rayo_call_locate(call_uri, __FILE__, __LINE__)
1094 /**
1095 * Get access to Rayo call data. Use to access call data outside channel thread.
1096 * @param call_uri the Rayo XMPP URI
1097 * @return the call or NULL.
1098 */
rayo_call_locate(const char * call_uri,const char * file,int line)1099 static struct rayo_call *rayo_call_locate(const char *call_uri, const char *file, int line)
1100 {
1101 struct rayo_actor *actor = rayo_actor_locate(call_uri, file, line);
1102 if (actor && is_call_actor(actor)) {
1103 return RAYO_CALL(actor);
1104 } else if (actor) {
1105 RAYO_RELEASE(actor);
1106 }
1107 return NULL;
1108 }
1109
1110 #define RAYO_CALL_LOCATE_BY_ID(call_uuid) rayo_call_locate_by_id(call_uuid, __FILE__, __LINE__)
1111 /**
1112 * Get access to Rayo call data. Use to access call data outside channel thread.
1113 * @param call_uuid the FreeSWITCH call UUID
1114 * @return the call or NULL.
1115 */
rayo_call_locate_by_id(const char * call_uuid,const char * file,int line)1116 static struct rayo_call *rayo_call_locate_by_id(const char *call_uuid, const char *file, int line)
1117 {
1118 struct rayo_actor *actor = rayo_actor_locate_by_id(call_uuid, file, line);
1119 if (actor && is_call_actor(actor)) {
1120 return RAYO_CALL(actor);
1121 } else if (actor) {
1122 RAYO_RELEASE(actor);
1123 }
1124 return NULL;
1125 }
1126
1127 /**
1128 * Send <end> event to DCP and PCPs
1129 */
rayo_call_send_end(struct rayo_call * call,switch_event_t * event,int local_hangup,const char * cause_str,const char * cause_q850_str)1130 static void rayo_call_send_end(struct rayo_call *call, switch_event_t *event, int local_hangup, const char *cause_str, const char *cause_q850_str)
1131 {
1132 int no_offered_clients = 1;
1133 switch_hash_index_t *hi = NULL;
1134 iks *revent;
1135 iks *end;
1136 const char *dcp_jid = rayo_call_get_dcp_jid(call);
1137
1138 /* build call end event */
1139 revent = iks_new_presence("end", RAYO_NS, RAYO_JID(call), "foo");
1140 iks_insert_attrib(revent, "type", "unavailable");
1141 end = iks_find(revent, "end");
1142
1143 if (local_hangup) {
1144 iks_insert(end, RAYO_END_REASON_HANGUP_LOCAL);
1145 } else {
1146 /* remote hangup... translate to specific rayo reason */
1147 iks *reason;
1148 switch_call_cause_t cause = SWITCH_CAUSE_NONE;
1149 if (!zstr(cause_str)) {
1150 cause = switch_channel_str2cause(cause_str);
1151 }
1152 reason = iks_insert(end, switch_cause_to_rayo_cause(cause));
1153 if (!zstr(cause_q850_str)) {
1154 iks_insert_attrib(reason, "platform-code", cause_q850_str);
1155 }
1156 }
1157
1158 #if 0
1159 if (event) {
1160 char *event_str;
1161 if (switch_event_serialize(event, &event_str, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
1162 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "%s\n", event_str);
1163 switch_safe_free(event_str);
1164 }
1165 }
1166 #endif
1167
1168 /* add signaling headers */
1169 if (event) {
1170 add_headers_to_event(end, event, globals.add_variables_to_events);
1171 }
1172
1173 /* send <end> to all offered clients */
1174 for (hi = switch_core_hash_first(call->pcps); hi; hi = switch_core_hash_next(&hi)) {
1175 const void *key;
1176 void *val;
1177 const char *client_jid = NULL;
1178 switch_core_hash_this(hi, &key, NULL, &val);
1179 client_jid = (const char *)key;
1180 switch_assert(client_jid);
1181 iks_insert_attrib(revent, "to", client_jid);
1182 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "Sending <end> to offered client %s\n", client_jid);
1183 RAYO_SEND_MESSAGE_DUP(call, client_jid, revent);
1184 no_offered_clients = 0;
1185 }
1186
1187 if (no_offered_clients && !zstr(dcp_jid)) {
1188 /* send to DCP only */
1189 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "Sending <end> to DCP %s\n", dcp_jid);
1190 iks_insert_attrib(revent, "to", dcp_jid);
1191 RAYO_SEND_MESSAGE_DUP(call, dcp_jid, revent);
1192 }
1193
1194 iks_delete(revent);
1195 }
1196
1197 /**
1198 * Fire <end> event when call is cleaned up completely
1199 */
rayo_call_cleanup(struct rayo_actor * actor)1200 static void rayo_call_cleanup(struct rayo_actor *actor)
1201 {
1202 struct rayo_call *call = RAYO_CALL(actor);
1203 switch_event_t *event = call->end_event;
1204 const char *dcp_jid = rayo_call_get_dcp_jid(call);
1205
1206 if (!event || call->dial_request_failed) {
1207 /* destroyed before FS session was created (in originate, for example) */
1208 goto done;
1209 }
1210
1211 /* send call unjoined event, if not already sent */
1212 if (call->joined && call->joined_id) {
1213 if (!zstr(dcp_jid)) {
1214 iks *unjoined;
1215 iks *uevent = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(call), dcp_jid);
1216 unjoined = iks_find(uevent, "unjoined");
1217 iks_insert_attrib_printf(unjoined, "call-uri", "%s", call->joined_id);
1218 RAYO_SEND_MESSAGE(call, dcp_jid, uevent);
1219 }
1220 }
1221
1222 rayo_call_send_end(call,
1223 event,
1224 switch_true(switch_event_get_header(event, "variable_rayo_local_hangup")),
1225 switch_event_get_header(event, "variable_hangup_cause"),
1226 switch_event_get_header(event, "variable_hangup_cause_q850"));
1227
1228 done:
1229
1230 /* lost the race: pending join failed... send IQ result to client now. */
1231 if (call->pending_join_request) {
1232 iks *request = call->pending_join_request;
1233 iks *result = iks_new_error_detailed(request, STANZA_ERROR_ITEM_NOT_FOUND, "call ended");
1234 call->pending_join_request = NULL;
1235 RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
1236 iks_delete(call->pending_join_request);
1237 }
1238
1239 if (event) {
1240 switch_event_destroy(&event);
1241 }
1242 if (call->answer_event) {
1243 switch_event_destroy(&call->answer_event);
1244 }
1245 switch_core_hash_destroy(&call->pcps);
1246 switch_core_hash_destroy(&call->acps);
1247 }
1248
1249 /**
1250 * @param call the Rayo call
1251 * @return the Rayo call DCP JID
1252 */
rayo_call_get_dcp_jid(struct rayo_call * call)1253 const char *rayo_call_get_dcp_jid(struct rayo_call *call)
1254 {
1255 return call->dcp_jid;
1256 }
1257
1258 /**
1259 * @param call the Rayo call
1260 * @return true if joined (or a join is in progress)
1261 */
rayo_call_is_joined(struct rayo_call * call)1262 int rayo_call_is_joined(struct rayo_call *call)
1263 {
1264 return call->joined || call->pending_join_request;
1265 }
1266
1267 /**
1268 * @param call to check if faxing
1269 * @return true if faxing is in progress
1270 */
rayo_call_is_faxing(struct rayo_call * call)1271 int rayo_call_is_faxing(struct rayo_call *call)
1272 {
1273 return call->faxing;
1274 }
1275
1276 /**
1277 * Set faxing flag
1278 * @param call the call to flag
1279 * @param faxing true if faxing is in progress
1280 */
rayo_call_set_faxing(struct rayo_call * call,int faxing)1281 void rayo_call_set_faxing(struct rayo_call *call, int faxing)
1282 {
1283 call->faxing = faxing;
1284 }
1285
1286 #define RAYO_MIXER_LOCATE(mixer_name) rayo_mixer_locate(mixer_name, __FILE__, __LINE__)
1287 /**
1288 * Get access to Rayo mixer data.
1289 * @param mixer_name the mixer name
1290 * @return the mixer or NULL. Call RAYO_RELEASE() when done with mixer pointer.
1291 */
rayo_mixer_locate(const char * mixer_name,const char * file,int line)1292 static struct rayo_mixer *rayo_mixer_locate(const char *mixer_name, const char *file, int line)
1293 {
1294 struct rayo_actor *actor = rayo_actor_locate_by_id(mixer_name, file, line);
1295 if (actor && !strcmp(RAT_MIXER, actor->type)) {
1296 return RAYO_MIXER(actor);
1297 } else if (actor) {
1298 RAYO_RELEASE(actor);
1299 }
1300 return NULL;
1301 }
1302
1303 /**
1304 * Default message handler - drops messages
1305 */
rayo_actor_send_ignore(struct rayo_actor * to,struct rayo_message * msg)1306 void rayo_actor_send_ignore(struct rayo_actor *to, struct rayo_message *msg)
1307 {
1308 switch_log_printf(SWITCH_CHANNEL_ID_LOG, msg->file, "", msg->line, "", SWITCH_LOG_WARNING, "%s, dropping unexpected message to %s.\n", msg->from_jid, RAYO_JID(to));
1309 }
1310
1311 #define RAYO_ACTOR_INIT(actor, pool, type, subtype, id, jid, cleanup, send) rayo_actor_init(actor, pool, type, subtype, id, jid, cleanup, send, NULL, __FILE__, __LINE__)
1312 #define RAYO_ACTOR_INIT_PARENT(actor, pool, type, subtype, id, jid, cleanup, send, parent) rayo_actor_init(actor, pool, type, subtype, id, jid, cleanup, send, parent, __FILE__, __LINE__)
1313
1314 /**
1315 * Initialize a rayo actor
1316 * @param actor to initialize
1317 * @param pool to use
1318 * @param type of actor (MIXER, CALL, SERVER, COMPONENT)
1319 * @param subtype of actor (input/output/prompt)
1320 * @param id internal ID
1321 * @param jid external ID
1322 * @param cleanup function
1323 * @param send sent message handler
1324 * @param parent of actor
1325 * @param file that called this function
1326 * @param line that called this function
1327 * @return the actor or NULL if JID conflict
1328 */
rayo_actor_init(struct rayo_actor * actor,switch_memory_pool_t * pool,const char * type,const char * subtype,const char * id,const char * jid,rayo_actor_cleanup_fn cleanup,rayo_actor_send_fn send,struct rayo_actor * parent,const char * file,int line)1329 static struct rayo_actor *rayo_actor_init(struct rayo_actor *actor, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, const char *jid, rayo_actor_cleanup_fn cleanup, rayo_actor_send_fn send, struct rayo_actor *parent, const char *file, int line)
1330 {
1331 char *domain;
1332 actor->type = switch_core_strdup(pool, type);
1333 actor->subtype = switch_core_strdup(pool, subtype);
1334 actor->pool = pool;
1335 if (!zstr(id)) {
1336 actor->id = switch_core_strdup(pool, id);
1337 }
1338 /* TODO validate JID with regex */
1339 if (!zstr(jid)) {
1340 RAYO_JID(actor) = switch_core_strdup(pool, jid);
1341 if (!(domain = strrchr(RAYO_JID(actor), '@'))) {
1342 RAYO_DOMAIN(actor) = RAYO_JID(actor);
1343 } else if (!zstr(++domain)) {
1344 RAYO_DOMAIN(actor) = switch_core_strdup(pool, domain);
1345 /* strip resource from domain if it exists */
1346 domain = strrchr(RAYO_DOMAIN(actor), '/');
1347 if (domain) {
1348 *domain = '\0';
1349 }
1350 }
1351 }
1352 actor->seq = 1;
1353 actor->ref_count = 1;
1354 actor->destroy = 0;
1355 actor->cleanup_fn = cleanup;
1356 if (send == NULL) {
1357 actor->send_fn = rayo_actor_send_ignore;
1358 } else {
1359 actor->send_fn = send;
1360 }
1361
1362 actor->parent = parent;
1363 if (!actor->parent) {
1364 switch_mutex_init(&actor->mutex, SWITCH_MUTEX_NESTED, pool);
1365 } else {
1366 /* inherit mutex from parent */
1367 actor->mutex = actor->parent->mutex;
1368
1369 /* prevent parent destruction */
1370 RAYO_RETAIN(actor->parent);
1371 }
1372
1373 /* add to hash of actors, so commands can route to call */
1374 switch_mutex_lock(globals.actors_mutex);
1375 if (!zstr(jid)) {
1376 if (switch_core_hash_find(globals.actors, RAYO_JID(actor))) {
1377 /* duplicate JID, give up! */
1378 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_NOTICE, "JID conflict! %s\n", RAYO_JID(actor));
1379 switch_mutex_unlock(globals.actors_mutex);
1380 if (actor->parent) {
1381 /* unlink from parent */
1382 RAYO_RELEASE(actor->parent);
1383 actor->parent = NULL;
1384 }
1385 return NULL;
1386 }
1387 switch_core_hash_insert(globals.actors, RAYO_JID(actor), actor);
1388 }
1389 if (!zstr(id)) {
1390 if (switch_core_hash_find(globals.actors_by_id, actor->id)) {
1391 /* duplicate ID - only log for now... */
1392 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "ID conflict! %s\n", actor->id);
1393 }
1394 switch_core_hash_insert(globals.actors_by_id, actor->id, actor);
1395 }
1396 switch_mutex_unlock(globals.actors_mutex);
1397
1398 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Init %s\n", RAYO_JID(actor));
1399
1400 return actor;
1401 }
1402
1403 /**
1404 * Initialize rayo call
1405 * @return the call or NULL if JID conflict
1406 */
rayo_call_init(struct rayo_call * call,switch_memory_pool_t * pool,const char * uuid,const char * file,int line)1407 static struct rayo_call *rayo_call_init(struct rayo_call *call, switch_memory_pool_t *pool, const char *uuid, const char *file, int line)
1408 {
1409 char *call_jid;
1410 char uuid_id_buf[SWITCH_UUID_FORMATTED_LENGTH + 1];
1411
1412 if (zstr(uuid)) {
1413 switch_uuid_str(uuid_id_buf, sizeof(uuid_id_buf));
1414 uuid = uuid_id_buf;
1415 }
1416 call_jid = switch_mprintf("%s@%s", uuid, RAYO_JID(globals.server));
1417
1418 call = RAYO_CALL(rayo_actor_init(RAYO_ACTOR(call), pool, RAT_CALL, "", uuid, call_jid, rayo_call_cleanup, rayo_call_send, NULL, file, line));
1419 if (call) {
1420 call->dcp_jid = "";
1421 call->idle_start_time = switch_micro_time_now();
1422 call->joined = 0;
1423 call->joined_id = NULL;
1424 call->ringing_sent = 0;
1425 call->pending_join_request = NULL;
1426 call->dial_request_id = NULL;
1427 call->end_event = NULL;
1428 call->dial_request_failed = 0;
1429 call->rayo_app_started = 0;
1430 call->answer_event = NULL;
1431 switch_core_hash_init(&call->pcps);
1432 switch_core_hash_init(&call->acps);
1433 call->num_acps = 0;
1434 }
1435
1436 switch_safe_free(call_jid);
1437
1438 return call;
1439 }
1440
1441 #define rayo_call_create(uuid) _rayo_call_create(uuid, __FILE__, __LINE__)
1442 /**
1443 * Create Rayo call
1444 * @param uuid uuid to assign call, if NULL one is picked
1445 * @param file file that called this function
1446 * @param line number of file that called this function
1447 * @return the call, or NULL if JID conflict
1448 */
_rayo_call_create(const char * uuid,const char * file,int line)1449 static struct rayo_call *_rayo_call_create(const char *uuid, const char *file, int line)
1450 {
1451 switch_memory_pool_t *pool;
1452 struct rayo_call *call;
1453 switch_core_new_memory_pool(&pool);
1454 call = switch_core_alloc(pool, sizeof(*call));
1455 call = rayo_call_init(call, pool, uuid, file, line);
1456 if (!call) {
1457 switch_core_destroy_memory_pool(&pool);
1458 }
1459 return call;
1460 }
1461
1462 /**
1463 * Mixer destructor
1464 */
rayo_mixer_cleanup(struct rayo_actor * actor)1465 static void rayo_mixer_cleanup(struct rayo_actor *actor)
1466 {
1467 struct rayo_mixer *mixer = RAYO_MIXER(actor);
1468 switch_core_hash_destroy(&mixer->members);
1469 switch_core_hash_destroy(&mixer->subscribers);
1470 }
1471
1472 /**
1473 * Initialize mixer
1474 * @return the mixer or NULL if JID conflict
1475 */
rayo_mixer_init(struct rayo_mixer * mixer,switch_memory_pool_t * pool,const char * name,const char * file,int line)1476 static struct rayo_mixer *rayo_mixer_init(struct rayo_mixer *mixer, switch_memory_pool_t *pool, const char *name, const char *file, int line)
1477 {
1478 char *mixer_jid = switch_mprintf("%s@%s", name, RAYO_JID(globals.server));
1479 mixer = RAYO_MIXER(rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, rayo_mixer_cleanup, rayo_mixer_send, NULL, file, line));
1480 if (mixer) {
1481 switch_core_hash_init(&mixer->members);
1482 switch_core_hash_init(&mixer->subscribers);
1483 }
1484 switch_safe_free(mixer_jid);
1485 return mixer;
1486 }
1487
1488 #define rayo_mixer_create(name) _rayo_mixer_create(name, __FILE__, __LINE__)
1489 /**
1490 * Create Rayo mixer
1491 * @param name of this mixer
1492 * @return the mixer or NULL if JID conflict
1493 */
_rayo_mixer_create(const char * name,const char * file,int line)1494 static struct rayo_mixer *_rayo_mixer_create(const char *name, const char *file, int line)
1495 {
1496 switch_memory_pool_t *pool;
1497 struct rayo_mixer *mixer = NULL;
1498 switch_core_new_memory_pool(&pool);
1499 mixer = rayo_mixer_init(switch_core_alloc(pool, sizeof(*mixer)), pool, name, file, line);
1500 if (!mixer) {
1501 switch_core_destroy_memory_pool(&pool);
1502 }
1503 return mixer;
1504 }
1505
1506 /**
1507 * Initialize Rayo component
1508 * @param type of this component
1509 * @param subtype of this component
1510 * @param id internal ID of this component
1511 * @param parent the parent that owns this component
1512 * @param client_jid the client that created this component
1513 * @param cleanup optional cleanup function
1514 * @param file file that called this function
1515 * @param line line number that called this function
1516 * @return the component or NULL if JID conflict
1517 */
_rayo_component_init(struct rayo_component * component,switch_memory_pool_t * pool,const char * type,const char * subtype,const char * id,struct rayo_actor * parent,const char * client_jid,rayo_actor_cleanup_fn cleanup,const char * file,int line)1518 struct rayo_component *_rayo_component_init(struct rayo_component *component, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, struct rayo_actor *parent, const char *client_jid, rayo_actor_cleanup_fn cleanup, const char *file, int line)
1519 {
1520 char *ref = switch_mprintf("%s-%d", subtype, rayo_actor_seq_next(parent));
1521 char *jid = switch_mprintf("%s/%s", RAYO_JID(parent), ref);
1522 if (zstr(id)) {
1523 id = jid;
1524 }
1525
1526 component = RAYO_COMPONENT(rayo_actor_init(RAYO_ACTOR(component), pool, type, subtype, id, jid, cleanup, rayo_component_send, parent, file, line));
1527 if (component) {
1528 component->client_jid = switch_core_strdup(pool, client_jid);
1529 component->ref = switch_core_strdup(pool, ref);
1530 }
1531
1532 switch_safe_free(ref);
1533 switch_safe_free(jid);
1534 return component;
1535 }
1536
1537 /**
1538 * Send XMPP message to client
1539 */
rayo_client_send(struct rayo_actor * client,struct rayo_message * msg)1540 void rayo_client_send(struct rayo_actor *client, struct rayo_message *msg)
1541 {
1542 xmpp_stream_context_send(globals.xmpp_context, RAYO_CLIENT(client)->route, msg->payload);
1543 }
1544
1545 /**
1546 * Cleanup rayo client
1547 */
rayo_client_cleanup(struct rayo_actor * actor)1548 static void rayo_client_cleanup(struct rayo_actor *actor)
1549 {
1550 /* remove session from map */
1551 switch_mutex_lock(globals.clients_mutex);
1552 if (!zstr(RAYO_JID(actor))) {
1553 switch_core_hash_delete(globals.clients_roster, RAYO_JID(actor));
1554 if (RAYO_CLIENT(actor)->peer_server) {
1555 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Removing %s from peer server %s\n", RAYO_JID(actor), RAYO_JID(RAYO_CLIENT(actor)->peer_server));
1556 switch_core_hash_delete(RAYO_CLIENT(actor)->peer_server->clients, RAYO_JID(actor));
1557 }
1558 }
1559 switch_mutex_unlock(globals.clients_mutex);
1560
1561 pause_when_offline();
1562 }
1563
1564 /**
1565 * Initialize rayo client
1566 * @param pool the memory pool for this client
1567 * @param jid for this client
1568 * @param route to this client
1569 * @param availability of client
1570 * @param send message transmission function
1571 * @param peer_server NULL if locally connected client
1572 * @return the new client or NULL if JID conflict
1573 */
rayo_client_init(struct rayo_client * client,switch_memory_pool_t * pool,const char * jid,const char * route,enum presence_status availability,rayo_actor_send_fn send,struct rayo_peer_server * peer_server)1574 static struct rayo_client *rayo_client_init(struct rayo_client *client, switch_memory_pool_t *pool, const char *jid, const char *route, enum presence_status availability, rayo_actor_send_fn send, struct rayo_peer_server *peer_server)
1575 {
1576 client = RAYO_CLIENT(RAYO_ACTOR_INIT(RAYO_ACTOR(client), pool, RAT_CLIENT, "", jid, jid, rayo_client_cleanup, send));
1577 if (client) {
1578 client->availability = availability;
1579 client->peer_server = peer_server;
1580 client->last_probe = 0;
1581 if (route) {
1582 client->route = switch_core_strdup(pool, route);
1583 }
1584
1585 /* make client available for offers */
1586 switch_mutex_lock(globals.clients_mutex);
1587 switch_core_hash_insert(globals.clients_roster, RAYO_JID(client), client);
1588 if (peer_server) {
1589 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding %s to peer server %s\n", RAYO_JID(client), RAYO_JID(peer_server));
1590 switch_core_hash_insert(peer_server->clients, RAYO_JID(client), client);
1591 }
1592 switch_mutex_unlock(globals.clients_mutex);
1593 }
1594
1595 pause_when_offline();
1596
1597 return client;
1598 }
1599
1600 /**
1601 * Create a new Rayo client
1602 * @param jid for this client
1603 * @param route to this client
1604 * @param availability of client
1605 * @param send message transmission function
1606 * @param peer_server NULL if locally connected client
1607 * @return the new client or NULL
1608 */
rayo_client_create(const char * jid,const char * route,enum presence_status availability,rayo_actor_send_fn send,struct rayo_peer_server * peer_server)1609 static struct rayo_client *rayo_client_create(const char *jid, const char *route, enum presence_status availability, rayo_actor_send_fn send, struct rayo_peer_server *peer_server)
1610 {
1611 switch_memory_pool_t *pool;
1612 struct rayo_client *rclient = NULL;
1613
1614 switch_core_new_memory_pool(&pool);
1615 if (!(rclient = switch_core_alloc(pool, sizeof(*rclient)))) {
1616 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n");
1617 return NULL;
1618 }
1619 rclient = rayo_client_init(rclient, pool, jid, route, availability, send, peer_server);
1620 if (!rclient) {
1621 switch_core_destroy_memory_pool(&pool);
1622 }
1623 return rclient;
1624 }
1625
1626 /**
1627 * Send XMPP message to peer server
1628 */
rayo_peer_server_send(struct rayo_actor * server,struct rayo_message * msg)1629 void rayo_peer_server_send(struct rayo_actor *server, struct rayo_message *msg)
1630 {
1631 xmpp_stream_context_send(globals.xmpp_context, RAYO_JID(server), msg->payload);
1632 }
1633
1634 /**
1635 * Destroy peer server and its associated clients
1636 */
rayo_peer_server_cleanup(struct rayo_actor * actor)1637 static void rayo_peer_server_cleanup(struct rayo_actor *actor)
1638 {
1639 switch_hash_index_t *hi = NULL;
1640 struct rayo_peer_server *rserver = RAYO_PEER_SERVER(actor);
1641
1642 /* a little messy... client will remove itself from the peer server when it is destroyed,
1643 * however, there is no guarantee the client will actually be destroyed now so
1644 * the server must remove the client.
1645 */
1646 switch_mutex_lock(globals.clients_mutex);
1647 while ((hi = switch_core_hash_first_iter(rserver->clients, hi))) {
1648 const void *key;
1649 void *client;
1650 switch_core_hash_this(hi, &key, NULL, &client);
1651 switch_assert(client);
1652 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Removing %s from peer server %s\n", RAYO_JID(client), RAYO_JID(rserver));
1653 switch_core_hash_delete(rserver->clients, key);
1654 RAYO_CLIENT(client)->peer_server = NULL;
1655 RAYO_RELEASE(client);
1656 RAYO_DESTROY(client);
1657 }
1658 switch_core_hash_destroy(&rserver->clients);
1659 switch_mutex_unlock(globals.clients_mutex);
1660 }
1661
1662 /**
1663 * Create a new Rayo peer server
1664 * @param jid of this server
1665 * @return the peer server
1666 */
rayo_peer_server_create(const char * jid)1667 static struct rayo_peer_server *rayo_peer_server_create(const char *jid)
1668 {
1669 switch_memory_pool_t *pool;
1670 struct rayo_peer_server *rserver = NULL;
1671
1672 switch_core_new_memory_pool(&pool);
1673 if (!(rserver = switch_core_alloc(pool, sizeof(*rserver)))) {
1674 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n");
1675 return NULL;
1676 }
1677 rserver = RAYO_PEER_SERVER(RAYO_ACTOR_INIT(RAYO_ACTOR(rserver), pool, RAT_PEER_SERVER, "", jid, jid, rayo_peer_server_cleanup, rayo_peer_server_send));
1678 if (rserver) {
1679 switch_core_hash_init(&rserver->clients);
1680 } else {
1681 switch_core_destroy_memory_pool(&pool);
1682 }
1683 return rserver;
1684 }
1685
1686 /**
1687 * Check if message sender has control of offered call.
1688 * @param call the Rayo call
1689 * @param msg the message
1690 * @return 1 if sender has call control, 0 if sender does not have control
1691 */
has_call_control(struct rayo_call * call,struct rayo_message * msg)1692 static int has_call_control(struct rayo_call *call, struct rayo_message *msg)
1693 {
1694 return (!strcmp(rayo_call_get_dcp_jid(call), msg->from_jid) || is_internal_message(msg) || is_admin_client_message(msg));
1695 }
1696
1697 /**
1698 * Check if message sender has control of offered call. Take control if nobody else does.
1699 * @param call the Rayo call
1700 * @param session the session
1701 * @param msg the message
1702 * @return 1 if sender has call control
1703 */
take_call_control(struct rayo_call * call,switch_core_session_t * session,struct rayo_message * msg)1704 static int take_call_control(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg)
1705 {
1706 int control = 0;
1707
1708 /* nobody in charge */
1709 if (zstr(call->dcp_jid)) {
1710 /* was offered to this session? */
1711 if (!zstr(msg->from_jid) && switch_core_hash_find(call->pcps, msg->from_jid)) {
1712 /* take charge */
1713 call->dcp_jid = switch_core_strdup(RAYO_POOL(call), msg->from_jid);
1714 switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_dcp_jid", rayo_call_get_dcp_jid(call));
1715 control = 1;
1716 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_INFO, "%s has control of call\n", rayo_call_get_dcp_jid(call));
1717 }
1718 } else if (has_call_control(call, msg)) {
1719 control = 1;
1720 }
1721
1722 if (!control) {
1723 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_INFO, "%s does not have control of call\n", msg->from_jid);
1724 }
1725
1726 return control;
1727 }
1728
1729 /**
1730 * Check Rayo server command for errors.
1731 * @param server the server
1732 * @param msg the command
1733 * @return 1 if OK
1734 */
rayo_server_command_ok(struct rayo_actor * server,struct rayo_message * msg)1735 static iks *rayo_server_command_ok(struct rayo_actor *server, struct rayo_message *msg)
1736 {
1737 iks *node = msg->payload;
1738 iks *response = NULL;
1739 int bad = zstr(iks_find_attrib(node, "id"));
1740
1741 if (bad) {
1742 response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
1743 }
1744
1745 return response;
1746 }
1747
1748 /**
1749 * Check Rayo call command for errors.
1750 * @param call the Rayo call
1751 * @param session the session
1752 * @param msg the command
1753 * @return 1 if OK
1754 */
rayo_call_command_ok(struct rayo_call * call,switch_core_session_t * session,struct rayo_message * msg)1755 static iks *rayo_call_command_ok(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg)
1756 {
1757 iks *node = msg->payload;
1758 iks *response = NULL;
1759 int bad = zstr(iks_find_attrib(node, "id"));
1760
1761 if (bad) {
1762 response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
1763 } else if (!take_call_control(call, session, msg)) {
1764 response = iks_new_error(node, STANZA_ERROR_CONFLICT);
1765 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, %s conflict\n", msg->from_jid, RAYO_JID(call));
1766 }
1767
1768 return response;
1769 }
1770
1771 /**
1772 * Check Rayo component command for errors.
1773 * @param component the component
1774 * @param msg the command
1775 * @return 0 if error
1776 */
rayo_component_command_ok(struct rayo_component * component,struct rayo_message * msg)1777 static iks *rayo_component_command_ok(struct rayo_component *component, struct rayo_message *msg)
1778 {
1779 iks *node = msg->payload;
1780 iks *response = NULL;
1781 char *from = iks_find_attrib(node, "from");
1782 int bad = zstr(iks_find_attrib(node, "id"));
1783
1784 if (bad) {
1785 response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
1786 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, %s bad request\n", msg->from_jid, RAYO_JID(component));
1787 } else if (strcmp(component->client_jid, from) && !is_admin_client_message(msg) && !is_internal_message(msg)) {
1788 /* does not have control of this component */
1789 response = iks_new_error(node, STANZA_ERROR_CONFLICT);
1790 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, %s conflict\n", msg->from_jid, RAYO_JID(component));
1791 }
1792
1793 return response;
1794 }
1795
1796 /**
1797 * Handle server message
1798 */
rayo_server_send(struct rayo_actor * server,struct rayo_message * msg)1799 void rayo_server_send(struct rayo_actor *server, struct rayo_message *msg)
1800 {
1801 iks *response = NULL;
1802 rayo_actor_xmpp_handler handler = NULL;
1803 iks *iq = msg->payload;
1804
1805 if (!strcmp("presence", iks_name(iq))) {
1806 /* this is a hack - message from internal console */
1807 struct rayo_actor *client = RAYO_LOCATE(msg->from_jid);
1808 if (client) {
1809 if (!strcmp(RAT_CLIENT, client->type)) {
1810 on_client_presence(RAYO_CLIENT(client), iq);
1811 }
1812 RAYO_RELEASE(client);
1813 }
1814 return;
1815 }
1816
1817 /* is this a command a server supports? */
1818 handler = rayo_actor_command_handler_find(server, msg);
1819 if (!handler) {
1820 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no handler function for command to %s\n", msg->from_jid, RAYO_JID(server));
1821 if (!msg->is_reply) {
1822 RAYO_SEND_REPLY(server, msg->from_jid, iks_new_error(iq, STANZA_ERROR_FEATURE_NOT_IMPLEMENTED));
1823 }
1824 return;
1825 }
1826
1827 /* is the command valid? */
1828 if (!(response = rayo_server_command_ok(server, msg))) {
1829 response = handler(server, msg, NULL);
1830 }
1831
1832 if (response) {
1833 if (!msg->is_reply) {
1834 RAYO_SEND_REPLY(server, msg->from_jid, response);
1835 } else {
1836 iks_delete(response);
1837 }
1838 }
1839 }
1840
1841 /**
1842 * Handle call message
1843 */
rayo_call_send(struct rayo_actor * call,struct rayo_message * msg)1844 void rayo_call_send(struct rayo_actor *call, struct rayo_message *msg)
1845 {
1846 rayo_actor_xmpp_handler handler = NULL;
1847 iks *stanza = msg->payload;
1848 switch_core_session_t *session;
1849 iks *response = NULL;
1850
1851 if (!strcmp("message", iks_name(stanza))) {
1852 const char *type = iks_find_attrib_soft(stanza, "type");
1853
1854 if (!strcmp("normal", type)) {
1855 const char *body = iks_find_cdata(stanza, "body");
1856 if (!zstr(body)) {
1857 switch_event_t *event;
1858 if (switch_event_create(&event, SWITCH_EVENT_SEND_MESSAGE) == SWITCH_STATUS_SUCCESS) {
1859 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "content-type", "text/plain");
1860 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "uuid", rayo_call_get_uuid(RAYO_CALL(call)));
1861 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", iks_find_cdata(stanza, "subject"));
1862 switch_event_add_body(event, "%s", body);
1863 switch_event_fire(&event);
1864 }
1865 } else if (!msg->is_reply) {
1866 RAYO_SEND_REPLY(call, msg->from_jid, iks_new_error_detailed(stanza, STANZA_ERROR_BAD_REQUEST, "missing body"));
1867 }
1868 } else if (!msg->is_reply) {
1869 RAYO_SEND_REPLY(call, msg->from_jid, iks_new_error(stanza, STANZA_ERROR_FEATURE_NOT_IMPLEMENTED));
1870 }
1871 return;
1872 }
1873
1874 /* is this a command a call supports? */
1875 handler = rayo_actor_command_handler_find(call, msg);
1876 if (!handler) {
1877 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no handler function for command\n", RAYO_JID(call));
1878 if (!msg->is_reply) {
1879 RAYO_SEND_REPLY(call, msg->from_jid, iks_new_error(stanza, STANZA_ERROR_FEATURE_NOT_IMPLEMENTED));
1880 }
1881 return;
1882 }
1883
1884 /* is the session still available? */
1885 session = switch_core_session_locate(rayo_call_get_uuid(RAYO_CALL(call)));
1886 if (!session) {
1887 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, session not found\n", RAYO_JID(call));
1888 if (!msg->is_reply) {
1889 RAYO_SEND_REPLY(call, msg->from_jid, iks_new_error(stanza, STANZA_ERROR_ITEM_NOT_FOUND));
1890 }
1891 return;
1892 }
1893
1894 /* is the command valid? */
1895 if (!(response = rayo_call_command_ok(RAYO_CALL(call), session, msg))) {
1896 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, executing command\n", RAYO_JID(call));
1897 response = handler(call, msg, session);
1898 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, done executing command\n", RAYO_JID(call));
1899 }
1900 switch_core_session_rwunlock(session);
1901
1902 if (response) {
1903 if (!msg->is_reply) {
1904 RAYO_SEND_REPLY(call, msg->from_jid, response);
1905 } else {
1906 iks_delete(response);
1907 }
1908 }
1909 }
1910
1911 /**
1912 * Handle mixer message
1913 */
rayo_mixer_send(struct rayo_actor * mixer,struct rayo_message * msg)1914 void rayo_mixer_send(struct rayo_actor *mixer, struct rayo_message *msg)
1915 {
1916 rayo_actor_xmpp_handler handler = NULL;
1917 iks *iq = msg->payload;
1918 iks *response = NULL;
1919
1920 /* is this a command a mixer supports? */
1921 handler = rayo_actor_command_handler_find(mixer, msg);
1922 if (!handler) {
1923 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no handler function for command\n", RAYO_JID(mixer));
1924 if (!msg->is_reply) {
1925 RAYO_SEND_REPLY(mixer, msg->from_jid, iks_new_error(iq, STANZA_ERROR_FEATURE_NOT_IMPLEMENTED));
1926 }
1927 return;
1928 }
1929
1930 /* execute the command */
1931 response = handler(mixer, msg, NULL);
1932 if (response) {
1933 if (!msg->is_reply) {
1934 RAYO_SEND_REPLY(mixer, msg->from_jid, response);
1935 } else {
1936 iks_delete(response);
1937 }
1938 }
1939 }
1940
1941 /**
1942 * Handle mixer message
1943 */
rayo_component_send(struct rayo_actor * component,struct rayo_message * msg)1944 void rayo_component_send(struct rayo_actor *component, struct rayo_message *msg)
1945 {
1946 rayo_actor_xmpp_handler handler = NULL;
1947 iks *xml_msg = msg->payload;
1948 iks *response = NULL;
1949
1950 if (!strcmp("iq", iks_name(xml_msg))) {
1951 /* is this a command a component supports? */
1952 handler = rayo_actor_command_handler_find(component, msg);
1953 if (!handler) {
1954 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no component handler function for command\n", RAYO_JID(component));
1955 if (!msg->is_reply) {
1956 RAYO_SEND_REPLY(component, msg->from_jid, iks_new_error(xml_msg, STANZA_ERROR_FEATURE_NOT_IMPLEMENTED));
1957 }
1958 return;
1959 }
1960
1961 /* is the command valid? */
1962 if (!(response = rayo_component_command_ok(RAYO_COMPONENT(component), msg))) {
1963 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, executing command\n", RAYO_JID(component));
1964 response = handler(component, msg, NULL);
1965 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, done executing command\n", RAYO_JID(component));
1966 }
1967
1968 if (response) {
1969 if (!msg->is_reply) {
1970 RAYO_SEND_REPLY(component, msg->from_jid, response);
1971 } else {
1972 iks_delete(response);
1973 }
1974 return;
1975 }
1976 } else if (!strcmp("presence", iks_name(xml_msg))) {
1977 /* is this an event the component wants? */
1978 handler = rayo_actor_event_handler_find(component, msg);
1979 if (!handler) {
1980 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no component handler function for event\n", RAYO_JID(component));
1981 return;
1982 }
1983
1984 /* forward the event */
1985 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, forwarding event\n", RAYO_JID(component));
1986 response = handler(component, msg, NULL);
1987 if (response) {
1988 if (!msg->is_reply) {
1989 RAYO_SEND_REPLY(component, msg->from_jid, response);
1990 } else {
1991 iks_delete(response);
1992 }
1993 }
1994 }
1995 }
1996
1997 /**
1998 * Add signaling headers to channel -- only works on SIP
1999 * @param session the channel
2000 * @param iq_cmd the request containing <header>
2001 * @param type header type
2002 */
add_signaling_headers(switch_core_session_t * session,iks * iq_cmd,const char * type)2003 static void add_signaling_headers(switch_core_session_t *session, iks *iq_cmd, const char *type)
2004 {
2005 switch_channel_t *channel = switch_core_session_get_channel(session);
2006 iks *header = NULL;
2007 for (header = iks_find(iq_cmd, "header"); header; header = iks_next_tag(header)) {
2008 if (!strcmp("header", iks_name(header))) {
2009 const char *name = iks_find_attrib_soft(header, "name");
2010 const char *value = iks_find_attrib_soft(header, "value");
2011 if (!zstr(name) && !zstr(value)) {
2012 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding header: %s: %s\n", name, value);
2013 switch_channel_set_variable_name_printf(channel, value, "%s%s", type, name);
2014 }
2015 }
2016 }
2017 }
2018
2019 /**
2020 * Handle <iq><accept> request
2021 * @param call the Rayo call
2022 * @param session the session
2023 * @param node the <iq> node
2024 */
on_rayo_accept(struct rayo_actor * call,struct rayo_message * msg,void * session_data)2025 static iks *on_rayo_accept(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
2026 {
2027 iks *node = msg->payload;
2028 switch_core_session_t *session = (switch_core_session_t *)session_data;
2029 iks *response = NULL;
2030
2031 /* send ringing */
2032 add_signaling_headers(session, iks_find(node, "accept"), RAYO_SIP_RESPONSE_HEADER);
2033 switch_channel_pre_answer(switch_core_session_get_channel(session));
2034 response = iks_new_iq_result(node);
2035 return response;
2036 }
2037
2038 /**
2039 * Handle <iq><answer> request
2040 * @param call the Rayo call
2041 * @param session the session
2042 * @param node the <iq> node
2043 */
on_rayo_answer(struct rayo_actor * call,struct rayo_message * msg,void * session_data)2044 static iks *on_rayo_answer(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
2045 {
2046 iks *node = msg->payload;
2047 switch_core_session_t *session = (switch_core_session_t *)session_data;
2048 iks *response = NULL;
2049
2050 /* send answer to call */
2051 add_signaling_headers(session, iks_find(node, "answer"), RAYO_SIP_RESPONSE_HEADER);
2052 switch_channel_answer(switch_core_session_get_channel(session));
2053 response = iks_new_iq_result(node);
2054 return response;
2055 }
2056
2057 /**
2058 * Handle <iq><redirect> request
2059 * @param call the Rayo call
2060 * @param session the session
2061 * @param node the <iq> node
2062 */
on_rayo_redirect(struct rayo_actor * call,struct rayo_message * msg,void * session_data)2063 static iks *on_rayo_redirect(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
2064 {
2065 iks *node = msg->payload;
2066 switch_core_session_t *session = (switch_core_session_t *)session_data;
2067 switch_channel_t *channel = switch_core_session_get_channel(session);
2068 iks *response = NULL;
2069 iks *redirect = iks_find(node, "redirect");
2070 char *redirect_to = iks_find_attrib(redirect, "to");
2071
2072 if (zstr(redirect_to)) {
2073 response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "Missing redirect to attrib");
2074 } else if (switch_channel_test_flag(channel, CF_ANSWERED)) {
2075 /* call is answered- must deflect */
2076 switch_core_session_message_t msg = { 0 };
2077 add_signaling_headers(session, redirect, RAYO_SIP_REQUEST_HEADER);
2078 msg.from = __FILE__;
2079 msg.string_arg = switch_core_session_strdup(session, redirect_to);
2080 msg.message_id = SWITCH_MESSAGE_INDICATE_DEFLECT;
2081 switch_core_session_receive_message(session, &msg);
2082 response = iks_new_iq_result(node);
2083 } else if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
2084 /* Inbound call not answered - redirect */
2085 switch_core_session_message_t msg = { 0 };
2086 add_signaling_headers(session, redirect, RAYO_SIP_RESPONSE_HEADER);
2087 msg.from = __FILE__;
2088 msg.string_arg = switch_core_session_strdup(session, redirect_to);
2089 msg.message_id = SWITCH_MESSAGE_INDICATE_REDIRECT;
2090 switch_core_session_receive_message(session, &msg);
2091 response = iks_new_iq_result(node);
2092 } else {
2093 response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "Call must be answered");
2094 }
2095 return response;
2096 }
2097
2098 /**
2099 * Handle <iq><hangup> or <iq><reject> request
2100 * @param call the Rayo call
2101 * @param session the session
2102 * @param node the <iq> node
2103 */
on_rayo_hangup(struct rayo_actor * call,struct rayo_message * msg,void * session_data)2104 static iks *on_rayo_hangup(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
2105 {
2106 iks *node = msg->payload;
2107 switch_core_session_t *session = (switch_core_session_t *)session_data;
2108 iks *response = NULL;
2109 iks *hangup = iks_first_tag(node);
2110 iks *reason = iks_first_tag(hangup);
2111 int hangup_cause = RAYO_CAUSE_HANGUP;
2112
2113 /* get hangup cause */
2114 if (!reason && !strcmp("hangup", iks_name(hangup))) {
2115 /* no reason in <hangup> */
2116 hangup_cause = RAYO_CAUSE_HANGUP;
2117 } else if (reason && !strcmp("reject", iks_name(hangup))) {
2118 char *reason_name = iks_name(reason);
2119 /* reason required for <reject> */
2120 if (!strcmp("busy", reason_name)) {
2121 hangup_cause = RAYO_CAUSE_BUSY;
2122 } else if (!strcmp("decline", reason_name)) {
2123 hangup_cause = RAYO_CAUSE_DECLINE;
2124 } else if (!strcmp("error", reason_name)) {
2125 hangup_cause = RAYO_CAUSE_ERROR;
2126 } else {
2127 response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "invalid reject reason");
2128 }
2129 } else {
2130 response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
2131 }
2132
2133 /* do hangup */
2134 if (!response) {
2135 switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_local_hangup", "true");
2136 add_signaling_headers(session, hangup, RAYO_SIP_REQUEST_HEADER);
2137 add_signaling_headers(session, hangup, RAYO_SIP_RESPONSE_HEADER);
2138 switch_ivr_kill_uuid(rayo_call_get_uuid(call), hangup_cause);
2139 response = iks_new_iq_result(node);
2140 }
2141
2142 return response;
2143 }
2144
2145 /**
2146 * Join calls together
2147 * @param call the call that joins
2148 * @param session the session
2149 * @param msg the rayo join message
2150 * @param call_uri to join
2151 * @param media mode (direct/bridge)
2152 * @return the response
2153 */
join_call(struct rayo_call * call,switch_core_session_t * session,struct rayo_message * msg,const char * call_uri,const char * media)2154 static iks *join_call(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *call_uri, const char *media)
2155 {
2156 iks *node = msg->payload;
2157 iks *response = NULL;
2158 /* take call out of media path if media = "direct" */
2159 int do_direct = !strcmp("direct", media);
2160
2161 /* check if joining to rayo call */
2162 struct rayo_call *b_call = RAYO_CALL_LOCATE(call_uri);
2163 if (b_call) {
2164 if (!call->rayo_app_started) {
2165 /* A-leg not under rayo control yet */
2166 response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "a-leg is not ready to join");
2167 } else if (!b_call->rayo_app_started) {
2168 /* B-leg not under rayo control yet */
2169 response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "b-leg is not ready to join");
2170 } else if (!has_call_control(b_call, msg)) {
2171 /* not allowed to join to this call */
2172 response = iks_new_error(node, STANZA_ERROR_NOT_ALLOWED);
2173 } else if (b_call->joined) {
2174 /* don't support multiple joined calls */
2175 response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported");
2176 } else {
2177 /* bridge this call to call-uri */
2178 if (do_direct) {
2179 switch_channel_set_flag(switch_core_session_get_channel(session), CF_BYPASS_MEDIA_AFTER_BRIDGE);
2180 } else {
2181 switch_channel_clear_flag(switch_core_session_get_channel(session), CF_BYPASS_MEDIA_AFTER_BRIDGE);
2182 switch_channel_pre_answer(switch_core_session_get_channel(session));
2183 }
2184 call->pending_join_request = iks_copy(node);
2185 if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) != SWITCH_STATUS_SUCCESS) {
2186 iks *request = call->pending_join_request;
2187 iks *result = iks_new_error(request, STANZA_ERROR_SERVICE_UNAVAILABLE);
2188 call->pending_join_request = NULL;
2189 RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
2190 iks_delete(call->pending_join_request);
2191 }
2192 }
2193 RAYO_RELEASE(b_call);
2194 } else {
2195 /* not a rayo call */
2196 response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is gone");
2197 }
2198 return response;
2199 }
2200
2201 /**
2202 * Execute command on session's conference
2203 * @param session to execute conference API on
2204 * @param conf_name of conference
2205 * @param command to send to conference
2206 * @param node IQ request
2207 * @return response on failure
2208 */
exec_conference_api(switch_core_session_t * session,const char * conf_name,const char * command,iks * node)2209 static iks *exec_conference_api(switch_core_session_t *session, const char *conf_name, const char *command, iks *node)
2210 {
2211 iks *response = NULL;
2212 switch_stream_handle_t stream = { 0 };
2213 const char *conf_member_id = switch_channel_get_variable(switch_core_session_get_channel(session), "conference_member_id");
2214 SWITCH_STANDARD_STREAM(stream);
2215 switch_api_execute("conference", switch_core_session_sprintf(session, "%s %s %s", conf_name, command, conf_member_id), NULL, &stream);
2216 if (!zstr(stream.data) && strncmp("OK", stream.data, 2)) {
2217 response = iks_new_error_detailed_printf(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "%s", stream.data);
2218 }
2219 switch_safe_free(stream.data);
2220 return response;
2221 }
2222
2223 /**
2224 * Execute conference app on session
2225 * @param session to execute conference API on
2226 * @param command to send to conference (conference name, member flags, etc)
2227 * @param node IQ request
2228 * @return response on failure
2229 */
exec_conference_app(switch_core_session_t * session,const char * command,iks * node)2230 static iks *exec_conference_app(switch_core_session_t *session, const char *command, iks *node)
2231 {
2232 iks *response = NULL;
2233 switch_event_t *execute_event = NULL;
2234 switch_channel_t *channel = switch_core_session_get_channel(session);
2235
2236 /* conference requires local media on channel */
2237 if (!switch_channel_media_ready(channel) && switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
2238 /* shit */
2239 response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to start media");
2240 return response;
2241 }
2242
2243 /* send execute conference event to session */
2244 if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
2245 switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
2246 switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "conference");
2247 switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", command);
2248 //switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event_uuid", uuid);
2249 switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
2250 if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
2251 switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
2252 }
2253
2254 if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
2255 response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to join mixer (queue event failed)");
2256 if (execute_event) {
2257 switch_event_destroy(&execute_event);
2258 }
2259 return response;
2260 }
2261 }
2262 return response;
2263 }
2264
2265 /**
2266 * Join call to a mixer
2267 * @param call the call that joins
2268 * @param session the session
2269 * @param msg the join request
2270 * @param mixer_name the mixer to join
2271 * @param direction the media direction
2272 * @return the response
2273 */
join_mixer(struct rayo_call * call,switch_core_session_t * session,struct rayo_message * msg,const char * mixer_name,const char * direction)2274 static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *mixer_name, const char *direction)
2275 {
2276 iks *node = msg->payload;
2277 iks *response = NULL;
2278
2279 if (!call->rayo_app_started) {
2280 /* A-leg not under rayo control yet */
2281 response = iks_new_error_detailed(node, STANZA_ERROR_UNEXPECTED_REQUEST, "call is not ready to join");
2282 } else if (call->joined_id) {
2283 /* adjust join conference params */
2284 if (!strcmp("duplex", direction)) {
2285 if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
2286 (response = exec_conference_api(session, mixer_name, "undeaf", node))) {
2287 return response;
2288 }
2289 } else if (!strcmp("recv", direction)) {
2290 if ((response = exec_conference_api(session, mixer_name, "mute", node)) ||
2291 (response = exec_conference_api(session, mixer_name, "undeaf", node))) {
2292 return response;
2293 }
2294 } else {
2295 if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
2296 (response = exec_conference_api(session, mixer_name, "deaf", node))) {
2297 return response;
2298 }
2299 }
2300 response = iks_new_iq_result(node);
2301 } else {
2302 /* join new conference */
2303 const char *conf_args = switch_core_session_sprintf(session, "%s@%s", mixer_name, globals.mixer_conf_profile);
2304 if (!strcmp("send", direction)) {
2305 conf_args = switch_core_session_sprintf(session, "%s+flags{deaf}", conf_args);
2306 } else if (!strcmp("recv", direction)) {
2307 conf_args = switch_core_session_sprintf(session, "%s+flags{mute}", conf_args);
2308 }
2309
2310 call->pending_join_request = iks_copy(node);
2311 response = exec_conference_app(session, conf_args, node);
2312 if (response) {
2313 iks_delete(call->pending_join_request);
2314 call->pending_join_request = NULL;
2315 }
2316 }
2317 return response;
2318 }
2319
2320 /**
2321 * Handle <iq><join> request
2322 * @param call the Rayo call
2323 * @param session the session
2324 * @param msg the rayo join message
2325 */
on_rayo_join(struct rayo_actor * call,struct rayo_message * msg,void * session_data)2326 static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
2327 {
2328 switch_core_session_t *session = (switch_core_session_t *)session_data;
2329 iks *response = NULL;
2330 iks *join = iks_find(msg->payload, "join");
2331 const char *join_id;
2332 const char *mixer_name;
2333 const char *call_uri;
2334
2335 /* validate input attributes */
2336 if (!VALIDATE_RAYO_JOIN(join)) {
2337 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad join attrib\n");
2338 response = iks_new_error(msg->payload, STANZA_ERROR_BAD_REQUEST);
2339 goto done;
2340 }
2341 mixer_name = iks_find_attrib(join, "mixer-name");
2342 call_uri = iks_find_attrib(join, "call-uri");
2343
2344 if (!zstr(mixer_name)) {
2345 join_id = mixer_name;
2346 } else {
2347 join_id = call_uri;
2348 }
2349
2350 /* can't join both mixer and call */
2351 if (!zstr(mixer_name) && !zstr(call_uri)) {
2352 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive");
2353 goto done;
2354 }
2355
2356 /* need to join *something* */
2357 if (zstr(mixer_name) && zstr(call_uri)) {
2358 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required");
2359 goto done;
2360 }
2361
2362 if ((RAYO_CALL(call)->joined == JOINED_CALL) ||
2363 (RAYO_CALL(call)->joined == JOINED_MIXER && strcmp(RAYO_CALL(call)->joined_id, join_id))) {
2364 /* already joined */
2365 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_CONFLICT, "call is already joined");
2366 goto done;
2367 }
2368
2369 if (rayo_call_is_faxing(RAYO_CALL(call))) {
2370 /* can't join a call while it's faxing */
2371 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "fax is in progress");
2372 goto done;
2373 }
2374
2375 if (RAYO_CALL(call)->pending_join_request) {
2376 /* don't allow concurrent join requests */
2377 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending");
2378 goto done;
2379 }
2380
2381 if (!zstr(mixer_name)) {
2382 /* join conference */
2383 response = join_mixer(RAYO_CALL(call), session, msg, mixer_name, iks_find_attrib(join, "direction"));
2384 } else {
2385 /* bridge calls */
2386 response = join_call(RAYO_CALL(call), session, msg, call_uri, iks_find_attrib(join, "media"));
2387 }
2388
2389 done:
2390 return response;
2391 }
2392
2393 /**
2394 * unjoin call to a bridge
2395 * @param call the call that unjoined
2396 * @param session the session
2397 * @param msg the unjoin request
2398 * @param call_uri the b-leg xmpp URI
2399 * @return the response
2400 */
unjoin_call(struct rayo_call * call,switch_core_session_t * session,struct rayo_message * msg,const char * call_uri)2401 static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *call_uri)
2402 {
2403 iks *node = msg->payload;
2404 iks *response = NULL;
2405
2406 if (!strcmp(call_uri, call->joined_id)) {
2407 /* unbridge call */
2408 call->pending_join_request = iks_copy(node);
2409 switch_ivr_park_session(session);
2410 } else {
2411 /* not bridged or wrong b-leg URI */
2412 response = iks_new_error_detailed_printf(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "expected URI: %s", call->joined_id);
2413 }
2414
2415 return response;
2416 }
2417
2418 /**
2419 * unjoin call to a mixer
2420 * @param call the call that unjoined
2421 * @param session the session
2422 * @param msg the unjoin request
2423 * @param mixer_name the mixer name
2424 * @return the response
2425 */
unjoin_mixer(struct rayo_call * call,switch_core_session_t * session,struct rayo_message * msg,const char * mixer_name)2426 static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *mixer_name)
2427 {
2428 switch_channel_t *channel = switch_core_session_get_channel(session);
2429 const char *conf_member_id = switch_channel_get_variable(channel, "conference_member_id");
2430 const char *conf_name = switch_channel_get_variable(channel, "conference_name");
2431 iks *node = msg->payload;
2432 iks *response = NULL;
2433
2434 /* not conferenced, or wrong conference */
2435 if (zstr(conf_name) || strcmp(mixer_name, conf_name)) {
2436 response = iks_new_error_detailed_printf(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to %s", mixer_name);
2437 goto done;
2438 } else if (zstr(conf_member_id)) {
2439 /* shouldn't happen */
2440 response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "channel doesn't have conference member ID");
2441 goto done;
2442 }
2443
2444 /* kick the member */
2445 response = exec_conference_api(session, mixer_name, "hup", node);
2446 if (!response) {
2447 /* ack command */
2448 response = iks_new_iq_result(node);
2449 }
2450
2451 done:
2452
2453 return response;
2454 }
2455
2456 /**
2457 * Handle <iq><unjoin> request
2458 * @param call the Rayo call
2459 * @param session the session
2460 * @param node the <iq> node
2461 */
on_rayo_unjoin(struct rayo_actor * call,struct rayo_message * msg,void * session_data)2462 static iks *on_rayo_unjoin(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
2463 {
2464 switch_core_session_t *session = (switch_core_session_t *)session_data;
2465 iks *response = NULL;
2466 iks *unjoin = iks_find(msg->payload, "unjoin");
2467 const char *call_uri = iks_find_attrib(unjoin, "call-uri");
2468 const char *mixer_name = iks_find_attrib(unjoin, "mixer-name");
2469
2470 if (!zstr(call_uri) && !zstr(mixer_name)) {
2471 response = iks_new_error(msg->payload, STANZA_ERROR_BAD_REQUEST);
2472 } else if (RAYO_CALL(call)->pending_join_request) {
2473 /* need to let pending request finish first */
2474 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending");
2475 } else if (!RAYO_CALL(call)->joined) {
2476 /* not joined to anything */
2477 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to anything");
2478 } else if (RAYO_CALL(call)->joined == JOINED_MIXER && !zstr(call_uri)) {
2479 /* joined to mixer, not call */
2480 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to call");
2481 } else if (RAYO_CALL(call)->joined == JOINED_CALL && !zstr(mixer_name)) {
2482 /* joined to call, not mixer */
2483 response = iks_new_error_detailed(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to mixer");
2484 } else if (!zstr(call_uri)) {
2485 response = unjoin_call(RAYO_CALL(call), session, msg, call_uri);
2486 } else if (!zstr(mixer_name)) {
2487 response = unjoin_mixer(RAYO_CALL(call), session, msg, mixer_name);
2488 } else {
2489 /* unjoin everything */
2490 if (RAYO_CALL(call)->joined == JOINED_MIXER) {
2491 response = unjoin_mixer(RAYO_CALL(call), session, msg, RAYO_CALL(call)->joined_id);
2492 } else if (RAYO_CALL(call)->joined == JOINED_CALL) {
2493 response = unjoin_call(RAYO_CALL(call), session, msg, RAYO_CALL(call)->joined_id);
2494 } else {
2495 /* shouldn't happen */
2496 response = iks_new_error(msg->payload, STANZA_ERROR_INTERNAL_SERVER_ERROR);
2497 }
2498 }
2499
2500 return response;
2501 }
2502
2503 /**
2504 * @return 1 if display name is valid
2505 */
is_valid_display_name(char * display)2506 static int is_valid_display_name(char *display)
2507 {
2508 if (zstr(display)) {
2509 return 0;
2510 }
2511 return 1;
2512 }
2513
2514 /**
2515 * @return 1 if SIP URI is valid
2516 */
is_valid_sip_uri(char * uri)2517 static int is_valid_sip_uri(char *uri)
2518 {
2519 /* just some basic checks to prevent failure when passing URI as caller ID */
2520 if (zstr(uri) || strchr(uri, '<') || strchr(uri, '>')) {
2521 return 0;
2522 }
2523 return 1;
2524 }
2525
2526 #define RAYO_URI_SCHEME_UNKNOWN 0
2527 #define RAYO_URI_SCHEME_TEL 1
2528 #define RAYO_URI_SCHEME_SIP 2
2529
2530 /**
2531 * Parse dial "from" parameter
2532 * @param pool to use
2533 * @param from the parameter to parse
2534 * @param uri the URI
2535 * @param display the display name
2536 * @return scheme
2537 */
parse_dial_from(switch_memory_pool_t * pool,const char * from,char ** uri,char ** display)2538 static int parse_dial_from(switch_memory_pool_t *pool, const char *from, char **uri, char **display)
2539 {
2540 if (!zstr(from)) {
2541 char *l_display = switch_core_strdup(pool, from);
2542 char *l_uri;
2543
2544 *display = NULL;
2545 *uri = NULL;
2546
2547 /* TODO regex would be better */
2548
2549 /* split display-name and URI */
2550 l_uri = strrchr(l_display, ' ');
2551 if (l_uri) {
2552 *l_uri++ = '\0';
2553 if (!zstr(l_display)) {
2554 /* remove "" from display-name */
2555 if (l_display[0] == '"') {
2556 int len;
2557 *l_display++ = '\0';
2558 len = strlen(l_display);
2559 if (len < 2 || l_display[len - 1] != '"') {
2560 return RAYO_URI_SCHEME_UNKNOWN;
2561 }
2562 l_display[len - 1] = '\0';
2563 }
2564 if (!is_valid_display_name(l_display)) {
2565 return RAYO_URI_SCHEME_UNKNOWN;
2566 }
2567 *display = l_display;
2568 }
2569 } else {
2570 l_uri = l_display;
2571 }
2572 if (zstr(l_uri)) {
2573 return RAYO_URI_SCHEME_UNKNOWN;
2574 }
2575
2576 /* remove <> from URI */
2577 if (l_uri[0] == '<') {
2578 int len;
2579 *l_uri++ = '\0';
2580 len = strlen(l_uri);
2581 if (len < 2 || l_uri[len - 1] != '>') {
2582 return RAYO_URI_SCHEME_UNKNOWN;
2583 }
2584 l_uri[len - 1] = '\0';
2585 if (zstr(l_uri)) {
2586 return RAYO_URI_SCHEME_UNKNOWN;
2587 }
2588 }
2589 *uri = l_uri;
2590
2591 /* figure out URI scheme and validate it */
2592 if (!strncmp("sip:", l_uri, 4) || !strncmp("sips:", l_uri, 5)) {
2593 /* validate SIP URI */
2594 if (is_valid_sip_uri(l_uri)) {
2595 return RAYO_URI_SCHEME_SIP;
2596 }
2597 } else if (!strncmp("tel:", l_uri, 4)) {
2598 l_uri += 4;
2599 *uri = l_uri;
2600 }
2601 if (!zstr(l_uri)) {
2602 return RAYO_URI_SCHEME_TEL;
2603 }
2604 }
2605 return RAYO_URI_SCHEME_UNKNOWN;
2606 }
2607
2608 struct dial_thread_data {
2609 switch_memory_pool_t *pool;
2610 iks *node;
2611 };
2612
2613
2614 /**
2615 * Thread that handles originating new calls
2616 * @param thread this thread
2617 * @param obj the Rayo client
2618 * @return NULL
2619 */
rayo_dial_thread(switch_thread_t * thread,void * user)2620 static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void *user)
2621 {
2622 struct dial_thread_data *dtdata = (struct dial_thread_data *)user;
2623 iks *iq = dtdata->node;
2624 iks *dial = iks_find(iq, "dial");
2625 iks *response = NULL;
2626 const char *dcp_jid = iks_find_attrib(iq, "from");
2627 const char *dial_to = iks_find_attrib(dial, "to");
2628 char *dial_to_dup = NULL;
2629 const char *dial_from = iks_find_attrib(dial, "from");
2630 const char *dial_timeout_ms = iks_find_attrib(dial, "timeout");
2631 const char *requested_call_uri = iks_find_attrib(dial, "uri");
2632 const char *uuid = NULL;
2633 switch_event_t *originate_vars = NULL;
2634 struct dial_gateway *gateway = NULL;
2635 struct rayo_call *call = NULL;
2636 uint32_t dial_timeout_sec = 0;
2637
2638 /* TODO dial_to needs validation */
2639
2640 /* Check if optional URI is valid. */
2641 if (!zstr(requested_call_uri)) {
2642
2643 /* Split node and domain from URI */
2644 char *requested_call_uri_dup = switch_core_strdup(dtdata->pool, requested_call_uri);
2645 char *requested_call_uri_domain = strchr(requested_call_uri_dup, '@');
2646 if (requested_call_uri_domain) {
2647 *requested_call_uri_domain = '\0';
2648 requested_call_uri_domain++;
2649 }
2650
2651 /* is domain missing */
2652 if (zstr(requested_call_uri_domain)) {
2653 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Bad uri");
2654 goto done;
2655 }
2656
2657 /* is domain correct? */
2658 if (strcmp(requested_call_uri_domain, RAYO_JID(globals.server))) {
2659 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Bad uri (invalid domain)");
2660 goto done;
2661 }
2662
2663 /* is node identifier missing? */
2664 if (zstr(requested_call_uri_dup)) {
2665 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Bad uri (missing node)");
2666 goto done;
2667 }
2668
2669 /* strip optional xmpp: from node identifier */
2670 if (!strncasecmp("xmpp:", requested_call_uri_dup, 5)) {
2671 requested_call_uri_dup += 5;
2672 if (zstr(requested_call_uri_dup)) {
2673 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Bad uri (missing node)");
2674 goto done;
2675 }
2676 }
2677
2678 /* success! */
2679 uuid = requested_call_uri_dup;
2680 }
2681
2682 /* create call and link to DCP */
2683 call = rayo_call_create(uuid);
2684 if (!call) {
2685 response = iks_new_error(iq, STANZA_ERROR_CONFLICT);
2686 goto done;
2687 }
2688 call->dcp_jid = switch_core_strdup(RAYO_POOL(call), dcp_jid);
2689 call->dial_request_id = switch_core_strdup(RAYO_POOL(call), iks_find_attrib_soft(iq, "id"));
2690 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_INFO, "%s has control of call\n", dcp_jid);
2691 uuid = switch_core_strdup(dtdata->pool, rayo_call_get_uuid(call));
2692
2693 /* create container for origination variables */
2694 if (switch_event_create_plain(&originate_vars, SWITCH_EVENT_CHANNEL_DATA) != SWITCH_STATUS_SUCCESS) {
2695 abort();
2696 }
2697
2698 /* add dialstring vars to origination variables */
2699 if (*dial_to == '{') {
2700 dial_to_dup = switch_core_strdup(dtdata->pool, dial_to);
2701 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: parsing dialstring channel variables\n");
2702 switch_event_create_brackets(dial_to_dup, '{', '}', ',', &originate_vars, (char **)&dial_to, SWITCH_FALSE);
2703 }
2704
2705 /* set originate channel variables */
2706 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "origination_uuid", rayo_call_get_uuid(call));
2707 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "rayo_dcp_jid", dcp_jid);
2708 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "rayo_call_jid", RAYO_JID(call));
2709
2710 if (!zstr(dial_from)) {
2711 char *from_uri = NULL;
2712 char *from_display;
2713 int scheme = parse_dial_from(dtdata->pool, dial_from, &from_uri, &from_display);
2714 if (scheme == RAYO_URI_SCHEME_UNKNOWN) {
2715 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Bad from URI");
2716 goto done;
2717 } else if (scheme == RAYO_URI_SCHEME_SIP) {
2718 /* SIP URI */
2719 if (!zstr(from_uri)) {
2720 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "sip_from_uri", from_uri);
2721 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: sip_from_uri=%s\n", from_uri);
2722 }
2723 if (!zstr(from_display)) {
2724 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "sip_from_display", from_display);
2725 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: sip_from_display=%s\n", from_display);
2726 }
2727 }
2728 if (!zstr(from_uri)) {
2729 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "origination_caller_id_number", from_uri);
2730 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: origination_caller_id_number=%s\n", from_uri);
2731 }
2732 if (!zstr(from_display)) {
2733 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "origination_caller_id_name", from_display);
2734 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: origination_caller_id_name=%s\n", from_display);
2735 } else if (scheme == RAYO_URI_SCHEME_TEL && !zstr(from_uri)) {
2736 /* set caller ID name to same as number if telephone number and a name wasn't specified */
2737 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, "origination_caller_id_name", from_uri);
2738 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: origination_caller_id_name=%s\n", from_uri);
2739 }
2740 }
2741 if (!zstr(dial_timeout_ms) && switch_is_number(dial_timeout_ms)) {
2742 dial_timeout_sec = round((double)atoi(dial_timeout_ms) / 1000.0);
2743 }
2744
2745 /* set outbound signaling headers - only works on SIP */
2746 {
2747 iks *header = NULL;
2748 for (header = iks_find(dial, "header"); header; header = iks_next_tag(header)) {
2749 if (!strcmp("header", iks_name(header))) {
2750 const char *name = iks_find_attrib_soft(header, "name");
2751 const char *value = iks_find_attrib_soft(header, "value");
2752 if (!zstr(name) && !zstr(value)) {
2753 char *header_name = switch_core_sprintf(dtdata->pool, "%s%s", RAYO_SIP_REQUEST_HEADER, name);
2754 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: Adding SIP header: %s: %s\n", name, value);
2755 switch_event_add_header_string(originate_vars, SWITCH_STACK_BOTTOM, header_name, value);
2756 }
2757 }
2758 }
2759 }
2760
2761 /* build dialstring and dial call */
2762 gateway = dial_gateway_find(dial_to);
2763 if (gateway) {
2764 iks *join = iks_find(dial, "join");
2765 const char *dial_to_stripped = dial_to + gateway->strip;
2766 switch_core_session_t *called_session = NULL;
2767 switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
2768 const char *dialstring = NULL;
2769
2770 if (join) {
2771 /* check join args */
2772 const char *call_uri = iks_find_attrib(join, "call-uri");
2773 const char *mixer_name = iks_find_attrib(join, "mixer-name");
2774
2775 if (!zstr(call_uri) && !zstr(mixer_name)) {
2776 /* can't join both */
2777 response = iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
2778 goto done;
2779 } else if (zstr(call_uri) && zstr(mixer_name)) {
2780 /* nobody to join to? */
2781 response = iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
2782 goto done;
2783 } else if (!zstr(call_uri)) {
2784 /* bridge */
2785 struct rayo_call *peer_call = RAYO_CALL_LOCATE(call_uri);
2786 /* is peer call available? */
2787 if (!peer_call) {
2788 response = iks_new_error_detailed(iq, STANZA_ERROR_SERVICE_UNAVAILABLE, "peer call not found");
2789 goto done;
2790 } else if (peer_call->joined) {
2791 response = iks_new_error_detailed(iq, STANZA_ERROR_SERVICE_UNAVAILABLE, "peer call already joined");
2792 RAYO_RELEASE(peer_call);
2793 goto done;
2794 }
2795 switch_event_add_header(originate_vars, SWITCH_STACK_BOTTOM, "rayo_origination_args", "bridge %s", rayo_call_get_uuid(peer_call));
2796 RAYO_RELEASE(peer_call);
2797 } else {
2798 /* conference */
2799 switch_event_add_header(originate_vars, SWITCH_STACK_BOTTOM, "rayo_origination_args", "conference %s@%s", mixer_name, globals.mixer_conf_profile);
2800 }
2801 }
2802
2803 dialstring = switch_core_sprintf(dtdata->pool, "%s%s", gateway->dial_prefix, dial_to_stripped);
2804 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "dial: Using dialstring: %s\n", dialstring);
2805
2806 /* <iq><ref> response will be sent when originate event is received- otherwise error is returned */
2807 if (switch_ivr_originate(NULL, &called_session, &cause, dialstring, dial_timeout_sec, NULL, NULL, NULL, NULL, originate_vars, SOF_NONE, NULL, NULL) == SWITCH_STATUS_SUCCESS && called_session) {
2808 /* start APP */
2809 switch_caller_extension_t *extension = NULL;
2810 switch_channel_t *called_channel = switch_core_session_get_channel(called_session);
2811 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "dial: Call originated\n");
2812 if ((extension = switch_caller_extension_new(called_session, "rayo", NULL)) == 0) {
2813 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_CRIT, "Memory Error!\n");
2814 abort();
2815 }
2816 switch_caller_extension_add_application(called_session, extension, "rayo", NULL);
2817 switch_channel_set_caller_extension(called_channel, extension);
2818 switch_channel_set_state(called_channel, CS_EXECUTE);
2819 switch_core_session_rwunlock(called_session);
2820 } else {
2821 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "dial: Failed to originate call: %s\n", switch_channel_cause2str(cause));
2822 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
2823 if (!zstr(call->dial_request_id)) {
2824 call->dial_request_failed = 1;
2825 call->dial_request_id = NULL;
2826
2827 /* map failure reason to iq error */
2828 switch (cause) {
2829 case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
2830 /* out of sessions, typically */
2831 response = iks_new_error_detailed(iq, STANZA_ERROR_RESOURCE_CONSTRAINT, "DESTINATION_OUT_OF_ORDER");
2832 break;
2833 case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
2834 case SWITCH_CAUSE_USER_NOT_REGISTERED: {
2835 /* call session was never created, so we must fake it so that a call error is sent and
2836 not a dial error */
2837 /* send ref response to DCP immediately followed with failure */
2838 iks *ref;
2839 iks *ref_response = iks_new("iq");
2840 iks_insert_attrib(ref_response, "from", RAYO_JID(globals.server));
2841 iks_insert_attrib(ref_response, "to", dcp_jid);
2842 iks_insert_attrib(ref_response, "id", iks_find_attrib_soft(iq, "id"));
2843 iks_insert_attrib(ref_response, "type", "result");
2844 ref = iks_insert(ref_response, "ref");
2845 iks_insert_attrib(ref, "xmlns", RAYO_NS);
2846 iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(call));
2847 RAYO_SEND_MESSAGE(globals.server, dcp_jid, ref_response);
2848
2849 /* send subscriber-absent call hangup reason */
2850 rayo_call_send_end(call, NULL, 0, "SUBSCRIBER_ABSENT", "20");
2851
2852 /* destroy call */
2853 RAYO_DESTROY(call);
2854 RAYO_RELEASE(call);
2855 break;
2856 }
2857 case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR:
2858 /* max forwards */
2859 response = iks_new_error_detailed(iq, STANZA_ERROR_RESOURCE_CONSTRAINT, "EXCHANGE_ROUTING_ERROR");
2860 break;
2861 case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
2862 /* unsupported endpoint type */
2863 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "CHAN_NOT_IMPLEMENTED");
2864 break;
2865 case SWITCH_CAUSE_INVALID_URL:
2866 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "INVALID_URL");
2867 break;
2868 case SWITCH_CAUSE_INVALID_GATEWAY:
2869 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "INVALID_GATEWAY");
2870 break;
2871 case SWITCH_CAUSE_INVALID_PROFILE:
2872 response = iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "INVALID_PROFILE");
2873 break;
2874 case SWITCH_CAUSE_SYSTEM_SHUTDOWN:
2875 response = iks_new_error_detailed(iq, STANZA_ERROR_RESOURCE_CONSTRAINT, "SYSTEM_SHUTDOWN");
2876 break;
2877 case SWITCH_CAUSE_GATEWAY_DOWN:
2878 response = iks_new_error_detailed(iq, STANZA_ERROR_RESOURCE_CONSTRAINT, "GATEWAY_DOWN");
2879 break;
2880 case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
2881 response = iks_new_error_detailed(iq, STANZA_ERROR_RESOURCE_CONSTRAINT, "INVALID_NUMBER_FORMAT");
2882 break;
2883 default:
2884 response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, switch_channel_cause2str(cause));
2885 break;
2886 }
2887 }
2888 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
2889 }
2890 } else {
2891 /* will only happen if misconfigured */
2892 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_CRIT, "dial: No dial gateway found for %s!\n", dial_to);
2893 call->dial_request_failed = 1;
2894 call->dial_request_id = NULL;
2895 response = iks_new_error_detailed_printf(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "dial: No dial gateway found for %s!\n", dial_to);
2896 goto done;
2897 }
2898
2899 done:
2900
2901 /* response when error */
2902 if (response) {
2903 /* send response to client */
2904 RAYO_SEND_REPLY(globals.server, iks_find_attrib(response, "to"), response);
2905
2906 /* destroy call */
2907 if (call) {
2908 RAYO_DESTROY(call);
2909 RAYO_RELEASE(call);
2910 }
2911 }
2912
2913 iks_delete(iq);
2914
2915 if (originate_vars) {
2916 switch_event_destroy(&originate_vars);
2917 }
2918
2919 {
2920 switch_memory_pool_t *pool = dtdata->pool;
2921 switch_core_destroy_memory_pool(&pool);
2922 }
2923
2924 return NULL;
2925 }
2926
2927 /**
2928 * Dial a new call
2929 * @param server handling the call
2930 * @param msg the request
2931 */
on_rayo_dial(struct rayo_actor * server,struct rayo_message * msg,void * data)2932 static iks *on_rayo_dial(struct rayo_actor *server, struct rayo_message *msg, void *data)
2933 {
2934 iks *node = msg->payload;
2935 switch_thread_t *thread;
2936 switch_threadattr_t *thd_attr = NULL;
2937 iks *dial = iks_find(node, "dial");
2938 iks *response = NULL;
2939 const char *dial_to = iks_find_attrib(dial, "to");
2940
2941 if (zstr(dial_to)) {
2942 response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "missing dial to attribute");
2943 } else if (strchr(dial_to, ' ')) {
2944 response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "malformed dial string");
2945 } else {
2946 switch_memory_pool_t *pool;
2947 struct dial_thread_data *dtdata = NULL;
2948 switch_core_new_memory_pool(&pool);
2949 dtdata = switch_core_alloc(pool, sizeof(*dtdata));
2950 dtdata->pool = pool;
2951 dtdata->node = iks_copy(node);
2952
2953 iks_insert_attrib(dtdata->node, "from", msg->from_jid); /* save DCP jid in case it isn't specified */
2954
2955 /* start dial thread */
2956 switch_threadattr_create(&thd_attr, pool);
2957 switch_threadattr_detach_set(thd_attr, 1);
2958 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
2959 switch_thread_create(&thread, thd_attr, rayo_dial_thread, dtdata, pool);
2960 }
2961
2962 return response;
2963 }
2964
2965 struct exec_thread_data {
2966 switch_memory_pool_t *pool;
2967 iks *node;
2968 };
2969
2970 /**
2971 * Thread that handles executing server APIs
2972 * @param thread this thread
2973 * @param user the API request
2974 * @return NULL
2975 */
rayo_exec_thread(switch_thread_t * thread,void * user)2976 static void *SWITCH_THREAD_FUNC rayo_exec_thread(switch_thread_t *thread, void *user)
2977 {
2978 struct exec_thread_data *etdata = (struct exec_thread_data *)user;
2979 iks *response = NULL;
2980 iks *exec = iks_find(etdata->node, "exec");
2981 const char *api = iks_find_attrib(exec, "api");
2982 const char *args = iks_find_attrib_soft(exec, "args");
2983 switch_stream_handle_t stream = { 0 };
2984 SWITCH_STANDARD_STREAM(stream);
2985
2986 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BGAPI EXEC: %s %s\n", api, args);
2987 if (switch_api_execute(api, args, NULL, &stream) != SWITCH_STATUS_SUCCESS) {
2988 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BGAPI EXEC FAILURE\n");
2989 response = iks_new_error_detailed(etdata->node, STANZA_ERROR_BAD_REQUEST, "Failed to execute API");
2990 } else {
2991 iks *api_result = NULL;
2992 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BGAPI EXEC RESULT: %s\n", (char *)stream.data);
2993 response = iks_new_iq_result(etdata->node);
2994 api_result = iks_insert(response, "response");
2995 iks_insert_attrib(api_result, "xmlns", RAYO_NS);
2996 iks_insert_attrib(api_result, "response", zstr((char *)stream.data) ? "" : (char *)stream.data);
2997 }
2998
2999 RAYO_SEND_REPLY(globals.server, iks_find_attrib(response, "to"), response);
3000
3001 switch_safe_free(stream.data);
3002 {
3003 switch_memory_pool_t *pool = etdata->pool;
3004 switch_core_destroy_memory_pool(&pool);
3005 }
3006 return NULL;
3007 }
3008
3009 /**
3010 * Execute an API on the server
3011 * @param server handling the call
3012 * @param msg the request
3013 */
on_rayo_exec(struct rayo_actor * server,struct rayo_message * msg,void * data)3014 static iks *on_rayo_exec(struct rayo_actor *server, struct rayo_message *msg, void *data)
3015 {
3016 iks *node = msg->payload;
3017 switch_thread_t *thread;
3018 switch_threadattr_t *thd_attr = NULL;
3019 iks *exec = iks_find(node, "exec");
3020 iks *response = NULL;
3021 const char *api = iks_find_attrib_soft(exec, "api");
3022
3023 if (zstr(api)) {
3024 response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "missing <exec> api attribute");
3025 } else {
3026 struct exec_thread_data *etdata = NULL;
3027 switch_memory_pool_t *pool = NULL;
3028 switch_core_new_memory_pool(&pool);
3029 etdata = switch_core_alloc(pool, sizeof(*etdata));
3030 etdata->pool = pool;
3031 etdata->node = iks_copy(node);
3032
3033 /* start exec thread */
3034 switch_threadattr_create(&thd_attr, pool);
3035 switch_threadattr_detach_set(thd_attr, 1);
3036 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
3037 switch_thread_create(&thread, thd_attr, rayo_exec_thread, etdata, pool);
3038 }
3039 return response;
3040 }
3041
3042 /**
3043 * Handle <iq><ping> request
3044 * @param rclient the Rayo client
3045 * @param server the Rayo server
3046 * @param node the <iq> node
3047 * @return NULL
3048 */
on_iq_xmpp_ping(struct rayo_actor * server,struct rayo_message * msg,void * data)3049 static iks *on_iq_xmpp_ping(struct rayo_actor *server, struct rayo_message *msg, void *data)
3050 {
3051 iks *node = msg->payload;
3052 iks *pong = iks_new("iq");
3053 char *from = iks_find_attrib(node, "from");
3054 char *to = iks_find_attrib(node, "to");
3055
3056 if (zstr(from)) {
3057 from = msg->from_jid;
3058 }
3059
3060 if (zstr(to)) {
3061 to = RAYO_JID(server);
3062 }
3063
3064 iks_insert_attrib(pong, "type", "result");
3065 iks_insert_attrib(pong, "from", to);
3066 iks_insert_attrib(pong, "to", from);
3067 iks_insert_attrib(pong, "id", iks_find_attrib(node, "id"));
3068
3069 return pong;
3070 }
3071
3072 /**
3073 * Handle service discovery request
3074 * @param rclient the Rayo client
3075 * @param server the Rayo server
3076 * @param node the <iq> node
3077 * @return NULL
3078 */
on_iq_get_xmpp_disco(struct rayo_actor * server,struct rayo_message * msg,void * data)3079 static iks *on_iq_get_xmpp_disco(struct rayo_actor *server, struct rayo_message *msg, void *data)
3080 {
3081 iks *node = msg->payload;
3082 iks *response = NULL;
3083 iks *x;
3084 iks *feature;
3085 iks *identity;
3086 int i = 0;
3087 const char *feature_string;
3088 response = iks_new_iq_result(node);
3089 x = iks_insert(response, "query");
3090 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_DISCO);
3091 identity = iks_insert(x, "identity");
3092 iks_insert_attrib(identity, "category", rayo_server_identity.category);
3093 iks_insert_attrib(identity, "type", rayo_server_identity.type);
3094 i = 0;
3095 while((feature_string = rayo_server_features[i++])) {
3096 feature = iks_insert(x, "feature");
3097 iks_insert_attrib(feature, "var", feature_string);
3098 }
3099
3100 /* TODO The response MUST also include features for the application formats and transport methods supported by
3101 * the responding entity, as described in the relevant specifications.
3102 */
3103
3104 return response;
3105 }
3106
3107 /**
3108 * Handle message from client
3109 * @param rclient that sent the command
3110 * @param message the message
3111 */
on_client_message(struct rayo_client * rclient,iks * message)3112 static void on_client_message(struct rayo_client *rclient, iks *message)
3113 {
3114 const char *to = iks_find_attrib(message, "to");
3115
3116 /* must be directed to a client */
3117 if (zstr(to)) {
3118 return;
3119 }
3120
3121 /* assume client source */
3122 if (zstr(iks_find_attrib(message, "from"))) {
3123 iks_insert_attrib(message, "from", RAYO_JID(rclient));
3124 }
3125
3126 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, recv message, availability = %s\n", RAYO_JID(rclient), presence_status_to_string(rclient->availability));
3127
3128 RAYO_SEND_MESSAGE_DUP(rclient, to, message);
3129 }
3130
3131 /**
3132 * Handle <presence> message from a client
3133 * @param rclient the client
3134 * @param node the presence message
3135 */
on_client_presence(struct rayo_client * rclient,iks * node)3136 static void on_client_presence(struct rayo_client *rclient, iks *node)
3137 {
3138 char *type = iks_find_attrib(node, "type");
3139 enum presence_status status = PS_UNKNOWN;
3140
3141 /*
3142 From RFC-6121:
3143 Entity is available when <presence/> received.
3144 Entity is unavailable when <presence type='unavailable'/> is received.
3145
3146 From Rayo-XEP:
3147 Entity is available when <presence to='foo' from='bar'><show>chat</show></presence> is received.
3148 Entity is unavailable when <presence to='foo' from='bar'><show>dnd</show></presence> is received.
3149 */
3150
3151 /* figure out if online/offline */
3152 if (zstr(type)) {
3153 /* <presence><show>chat</show></presence> */
3154 char *status_str = iks_find_cdata(node, "show");
3155 if (!zstr(status_str)) {
3156 if (!strcmp("chat", status_str)) {
3157 status = PS_ONLINE;
3158 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s got chat presence\n", RAYO_JID(rclient));
3159 } else if (!strcmp("dnd", status_str)) {
3160 status = PS_OFFLINE;
3161 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s got dnd presence\n", RAYO_JID(rclient));
3162 }
3163 } else {
3164 /* <presence/> */
3165 status = PS_ONLINE;
3166 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s got empty presence\n", RAYO_JID(rclient));
3167 }
3168 } else if (!strcmp("unavailable", type)) {
3169 status = PS_OFFLINE;
3170 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s got unavailable presence\n", RAYO_JID(rclient));
3171 } else if (!strcmp("error", type)) {
3172 /* TODO presence error */
3173 } else if (!strcmp("probe", type)) {
3174 /* TODO presence probe */
3175 } else if (!strcmp("subscribe", type)) {
3176 /* TODO presence subscribe */
3177 } else if (!strcmp("subscribed", type)) {
3178 /* TODO presence subscribed */
3179 } else if (!strcmp("unsubscribe", type)) {
3180 /* TODO presence unsubscribe */
3181 } else if (!strcmp("unsubscribed", type)) {
3182 /* TODO presence unsubscribed */
3183 }
3184
3185 if (status == PS_ONLINE && rclient->availability != PS_ONLINE) {
3186 rclient->availability = PS_ONLINE;
3187 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s is ONLINE\n", RAYO_JID(rclient));
3188 } else if (status == PS_OFFLINE && rclient->availability != PS_OFFLINE) {
3189 rclient->availability = PS_OFFLINE;
3190 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s is OFFLINE\n", RAYO_JID(rclient));
3191 }
3192
3193 /* destroy if not a local client (connected via peer_server) and is OFFLINE */
3194 if (rclient->peer_server && rclient->availability == PS_OFFLINE) {
3195 RAYO_DESTROY(rclient);
3196 RAYO_RELEASE(rclient);
3197 }
3198
3199 pause_when_offline();
3200 }
3201
3202 /**
3203 * Handle command from client
3204 * @param rclient that sent the command
3205 * @param iq the command
3206 */
rayo_client_command_recv(struct rayo_client * rclient,iks * iq)3207 static void rayo_client_command_recv(struct rayo_client *rclient, iks *iq)
3208 {
3209 iks *command = iks_first_tag(iq);
3210 const char *to = iks_find_attrib(iq, "to");
3211
3212 /* assume server destination */
3213 if (zstr(to)) {
3214 to = RAYO_JID(globals.server);
3215 iks_insert_attrib(iq, "to", to);
3216 }
3217
3218 /* assume client source */
3219 if (zstr(iks_find_attrib(iq, "from"))) {
3220 iks_insert_attrib(iq, "from", RAYO_JID(rclient));
3221 }
3222
3223 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, recv iq, availability = %s\n", RAYO_JID(rclient), presence_status_to_string(rclient->availability));
3224
3225 if (command) {
3226 RAYO_SEND_MESSAGE_DUP(rclient, to, iq);
3227 } else {
3228 const char *type = iks_find_attrib_soft(iq, "type");
3229 if (strcmp("error", type) && strcmp("result", type)) {
3230 RAYO_SEND_REPLY(globals.server, RAYO_JID(rclient), iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "empty IQ request"));
3231 }
3232 }
3233 }
3234
3235 /**
3236 * Send event to mixer subscribers
3237 * @param mixer the mixer
3238 * @param rayo_event the event to send
3239 */
broadcast_mixer_event(struct rayo_mixer * mixer,iks * rayo_event)3240 static void broadcast_mixer_event(struct rayo_mixer *mixer, iks *rayo_event)
3241 {
3242 switch_hash_index_t *hi = NULL;
3243 switch_mutex_lock(RAYO_ACTOR(mixer)->mutex);
3244 for (hi = switch_core_hash_first(mixer->subscribers); hi; hi = switch_core_hash_next(&hi)) {
3245 const void *key;
3246 void *val;
3247 struct rayo_mixer_subscriber *subscriber;
3248 switch_core_hash_this(hi, &key, NULL, &val);
3249 subscriber = (struct rayo_mixer_subscriber *)val;
3250 switch_assert(subscriber);
3251 iks_insert_attrib(rayo_event, "to", subscriber->jid);
3252 RAYO_SEND_MESSAGE_DUP(mixer, subscriber->jid, rayo_event);
3253 }
3254 switch_mutex_unlock(RAYO_ACTOR(mixer)->mutex);
3255 }
3256
3257 /**
3258 * Handle mixer delete member event
3259 */
on_mixer_delete_member_event(struct rayo_mixer * mixer,switch_event_t * event)3260 static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_t *event)
3261 {
3262 iks *delete_member_event, *x;
3263 const char *uuid = switch_event_get_header(event, "Unique-ID");
3264 struct rayo_call *call;
3265 struct rayo_mixer_member *member;
3266 struct rayo_mixer_subscriber *subscriber;
3267
3268 /* not a rayo mixer */
3269 if (!mixer) {
3270 return;
3271 }
3272
3273 /* remove member from mixer */
3274 switch_mutex_lock(RAYO_ACTOR(mixer)->mutex);
3275 member = (struct rayo_mixer_member *)switch_core_hash_find(mixer->members, uuid);
3276 if (!member) {
3277 /* not a member */
3278 switch_mutex_unlock(RAYO_ACTOR(mixer)->mutex);
3279 return;
3280 }
3281 switch_core_hash_delete(mixer->members, uuid);
3282 switch_mutex_unlock(RAYO_ACTOR(mixer)->mutex);
3283
3284 /* flag call as available to join another mixer */
3285 call = RAYO_CALL_LOCATE_BY_ID(uuid);
3286 if (call) {
3287 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
3288 call->joined = 0;
3289 call->joined_id = NULL;
3290 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
3291 RAYO_RELEASE(call);
3292 }
3293
3294 /* send mixer unjoined event to member DCP */
3295 delete_member_event = iks_new_presence("unjoined", RAYO_NS, member->jid, member->dcp_jid);
3296 x = iks_find(delete_member_event, "unjoined");
3297 iks_insert_attrib(x, "mixer-name", rayo_mixer_get_name(mixer));
3298 RAYO_SEND_MESSAGE(mixer, member->dcp_jid, delete_member_event);
3299
3300 /* broadcast member unjoined event to subscribers */
3301 delete_member_event = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(mixer), "");
3302 x = iks_find(delete_member_event, "unjoined");
3303 iks_insert_attrib_printf(x, "call-uri", "xmpp:%s@%s", uuid, RAYO_JID(globals.server));
3304 broadcast_mixer_event(mixer, delete_member_event);
3305 iks_delete(delete_member_event);
3306
3307 /* remove member DCP as subscriber to mixer */
3308 switch_mutex_lock(RAYO_ACTOR(mixer)->mutex);
3309 subscriber = (struct rayo_mixer_subscriber *)switch_core_hash_find(mixer->subscribers, member->dcp_jid);
3310 if (subscriber) {
3311 subscriber->ref_count--;
3312 if (subscriber->ref_count <= 0) {
3313 switch_core_hash_delete(mixer->subscribers, member->dcp_jid);
3314 }
3315 }
3316 switch_mutex_unlock(RAYO_ACTOR(mixer)->mutex);
3317 }
3318
3319 /**
3320 * Handle mixer destroy event
3321 */
on_mixer_destroy_event(struct rayo_mixer * mixer,switch_event_t * event)3322 static void on_mixer_destroy_event(struct rayo_mixer *mixer, switch_event_t *event)
3323 {
3324 if (mixer) {
3325 iks *presence;
3326
3327 /* notify online clients of mixer destruction */
3328 presence = iks_new("presence");
3329 iks_insert_attrib(presence, "from", RAYO_JID(mixer));
3330 iks_insert_attrib(presence, "type", "unavailable");
3331 broadcast_event(RAYO_ACTOR(mixer), presence, 1);
3332 iks_delete(presence);
3333
3334 /* remove from hash and destroy */
3335 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, destroying mixer: %s\n", RAYO_JID(mixer), rayo_mixer_get_name(mixer));
3336 RAYO_RELEASE(mixer); /* release original lock */
3337 RAYO_DESTROY(mixer);
3338 } else {
3339 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "destroy: NULL mixer\n");
3340 }
3341 }
3342
3343 /**
3344 * Handle mixer add member event
3345 */
on_mixer_add_member_event(struct rayo_mixer * mixer,switch_event_t * event)3346 static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *event)
3347 {
3348 iks *add_member_event = NULL, *x;
3349 const char *uuid = switch_event_get_header(event, "Unique-ID");
3350 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
3351 struct rayo_mixer *lmixer = NULL;
3352
3353 if (!mixer) {
3354 char *ver;
3355 iks *presence, *c;
3356
3357 /* new mixer */
3358 const char *mixer_name = switch_event_get_header(event, "Conference-Name");
3359 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "creating mixer: %s\n", mixer_name);
3360 mixer = rayo_mixer_create(mixer_name);
3361 if (mixer) {
3362 /* notify online clients of mixer presence */
3363 ver = calculate_entity_sha1_ver(&rayo_mixer_identity, rayo_mixer_features);
3364
3365 presence = iks_new_presence("c", IKS_NS_XMPP_ENTITY_CAPABILITIES, RAYO_JID(mixer), "");
3366 c = iks_find(presence, "c");
3367 iks_insert_attrib(c, "hash", "sha-1");
3368 iks_insert_attrib(c, "node", RAYO_MIXER_NS);
3369 iks_insert_attrib(c, "ver", ver);
3370 free(ver);
3371
3372 broadcast_event(RAYO_ACTOR(mixer), presence, 1);
3373 } else {
3374 /* must have lost the race to another add member event... there should be a mixer with mixer_name already */
3375 mixer = lmixer = RAYO_MIXER_LOCATE(mixer_name);
3376 if (!mixer) {
3377 /* this is unexpected */
3378 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to find mixer: %s\n", mixer_name);
3379 return;
3380 }
3381 }
3382 }
3383
3384 if (call) {
3385 struct rayo_mixer_member *member = NULL;
3386 /* add member DCP as subscriber to mixer */
3387 struct rayo_mixer_subscriber *subscriber;
3388 switch_mutex_lock(RAYO_ACTOR(mixer)->mutex);
3389 subscriber = (struct rayo_mixer_subscriber *)switch_core_hash_find(mixer->subscribers, call->dcp_jid);
3390 if (!subscriber) {
3391 subscriber = switch_core_alloc(RAYO_POOL(mixer), sizeof(*subscriber));
3392 subscriber->ref_count = 0;
3393 subscriber->jid = switch_core_strdup(RAYO_POOL(mixer), call->dcp_jid);
3394 switch_core_hash_insert(mixer->subscribers, call->dcp_jid, subscriber);
3395 }
3396 subscriber->ref_count++;
3397
3398 /* add call as member of mixer */
3399 member = switch_core_alloc(RAYO_POOL(mixer), sizeof(*member));
3400 member->jid = switch_core_strdup(RAYO_POOL(mixer), RAYO_JID(call));
3401 member->dcp_jid = subscriber->jid;
3402 switch_core_hash_insert(mixer->members, uuid, member);
3403
3404 switch_mutex_unlock(RAYO_ACTOR(mixer)->mutex);
3405
3406 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
3407 call->joined = JOINED_MIXER;
3408 call->joined_id = switch_core_strdup(RAYO_POOL(call), rayo_mixer_get_name(mixer));
3409
3410 /* send IQ result to client now. */
3411 if (call->pending_join_request) {
3412 iks *request = call->pending_join_request;
3413 iks *result = iks_new_iq_result(request);
3414 iks *ref = iks_insert(result, "ref");
3415 iks_insert_attrib(ref, "xmlns", RAYO_NS);
3416 iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(mixer));
3417 call->pending_join_request = NULL;
3418 RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
3419 iks_delete(request);
3420 }
3421 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
3422
3423 /* send mixer joined event to member DCP */
3424 add_member_event = iks_new_presence("joined", RAYO_NS, RAYO_JID(call), call->dcp_jid);
3425 x = iks_find(add_member_event, "joined");
3426 iks_insert_attrib(x, "mixer-name", rayo_mixer_get_name(mixer));
3427 RAYO_SEND_MESSAGE(call, call->dcp_jid, add_member_event);
3428
3429 RAYO_RELEASE(call);
3430 }
3431
3432 /* broadcast member joined event to subscribers */
3433 add_member_event = iks_new_presence("joined", RAYO_NS, RAYO_JID(mixer), "");
3434 x = iks_find(add_member_event, "joined");
3435 iks_insert_attrib_printf(x, "call-uri", "xmpp:%s@%s", uuid, RAYO_JID(globals.server));
3436 broadcast_mixer_event(mixer, add_member_event);
3437 iks_delete(add_member_event);
3438
3439 if (lmixer) {
3440 RAYO_RELEASE(lmixer);
3441 }
3442 }
3443
3444 /**
3445 * Receives mixer events from FreeSWITCH core and routes them to the proper Rayo client(s).
3446 * @param event received from FreeSWITCH core. It will be destroyed by the core after this function returns.
3447 */
route_mixer_event(switch_event_t * event)3448 static void route_mixer_event(switch_event_t *event)
3449 {
3450 const char *action = switch_event_get_header(event, "Action");
3451 const char *profile = switch_event_get_header(event, "Conference-Profile-Name");
3452 const char *mixer_name = switch_event_get_header(event, "Conference-Name");
3453 struct rayo_mixer *mixer = NULL;
3454
3455 if (strcmp(profile, globals.mixer_conf_profile)) {
3456 /* don't care about other conferences */
3457 goto done;
3458 }
3459
3460 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "looking for mixer: %s\n", mixer_name);
3461 mixer = RAYO_MIXER_LOCATE(mixer_name);
3462
3463 if (!strcmp("add-member", action)) {
3464 on_mixer_add_member_event(mixer, event);
3465 } else if (!strcmp("conference-destroy", action)) {
3466 on_mixer_destroy_event(mixer, event);
3467 } else if (!strcmp("del-member", action)) {
3468 on_mixer_delete_member_event(mixer, event);
3469 }
3470 /* TODO speaking events */
3471
3472 done:
3473 RAYO_RELEASE(mixer);
3474 }
3475
3476 /**
3477 * Handle call originate event - create rayo call and send <iq><ref> to client.
3478 * @param rclient The Rayo client
3479 * @param event the originate event
3480 */
on_call_originate_event(struct rayo_client * rclient,switch_event_t * event)3481 static void on_call_originate_event(struct rayo_client *rclient, switch_event_t *event)
3482 {
3483 const char *uuid = switch_event_get_header(event, "Unique-ID");
3484 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
3485
3486 if (call) {
3487 iks *response, *ref;
3488
3489 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Got originate event\n");
3490
3491 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
3492 if (!zstr(call->dial_request_id)) {
3493 /* send response to DCP */
3494 response = iks_new("iq");
3495 iks_insert_attrib(response, "from", RAYO_JID(globals.server));
3496 iks_insert_attrib(response, "to", rayo_call_get_dcp_jid(call));
3497 iks_insert_attrib(response, "id", call->dial_request_id);
3498 iks_insert_attrib(response, "type", "result");
3499 ref = iks_insert(response, "ref");
3500 iks_insert_attrib(ref, "xmlns", RAYO_NS);
3501
3502 iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(call));
3503 RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), response);
3504 call->dial_request_id = NULL;
3505 }
3506 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
3507 }
3508 RAYO_RELEASE(call);
3509 }
3510
3511 /**
3512 * Handle call end event
3513 * @param event the hangup event
3514 */
on_call_end_event(switch_event_t * event)3515 static void on_call_end_event(switch_event_t *event)
3516 {
3517 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
3518
3519 if (call) {
3520 #if 0
3521 char *event_str;
3522 if (switch_event_serialize(event, &event_str, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
3523 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_DEBUG, "%s\n", event_str);
3524 switch_safe_free(event_str);
3525 }
3526 #endif
3527 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Got channel destroy event\n");
3528
3529 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
3530 if (zstr(call->dial_request_id) && !call->dial_request_failed) {
3531 switch_event_dup(&call->end_event, event);
3532 RAYO_DESTROY(call);
3533 RAYO_RELEASE(call); /* decrement ref from creation */
3534 }
3535 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
3536 RAYO_RELEASE(call); /* decrement this ref */
3537 }
3538 }
3539
3540 /**
3541 * Handle call answer event
3542 * @param rclient the Rayo client
3543 * @param event the answer event
3544 */
on_call_answer_event(struct rayo_client * rclient,switch_event_t * event)3545 static void on_call_answer_event(struct rayo_client *rclient, switch_event_t *event)
3546 {
3547 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
3548 if (call) {
3549 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
3550 if (call->rayo_app_started) {
3551 iks *revent = iks_new_presence("answered", RAYO_NS,
3552 switch_event_get_header(event, "variable_rayo_call_jid"),
3553 switch_event_get_header(event, "variable_rayo_dcp_jid"));
3554 add_headers_to_event(iks_find(revent, "answered"), event, globals.add_variables_to_events);
3555 RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
3556 } else if (!call->answer_event) {
3557 /* delay sending this event until the rayo APP has started */
3558 switch_event_dup(&call->answer_event, event);
3559 }
3560 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
3561 RAYO_RELEASE(call);
3562 }
3563 }
3564
3565 /**
3566 * Handle call ringing event
3567 * @param rclient the Rayo client
3568 * @param event the ringing event
3569 */
on_call_ringing_event(struct rayo_client * rclient,switch_event_t * event)3570 static void on_call_ringing_event(struct rayo_client *rclient, switch_event_t *event)
3571 {
3572 const char *call_direction = switch_event_get_header(event, "Call-Direction");
3573 if (call_direction && !strcmp(call_direction, "outbound")) {
3574 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
3575 if (call) {
3576 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
3577 if (!call->ringing_sent) {
3578 iks *revent = iks_new_presence("ringing", RAYO_NS,
3579 switch_event_get_header(event, "variable_rayo_call_jid"),
3580 switch_event_get_header(event, "variable_rayo_dcp_jid"));
3581 add_headers_to_event(iks_find(revent, "ringing"), event, globals.add_variables_to_events);
3582 call->ringing_sent = 1;
3583 RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
3584 }
3585 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
3586 RAYO_RELEASE(call);
3587 }
3588 }
3589 }
3590
3591 /**
3592 * Handle call bridge event
3593 * @param rclient the Rayo client
3594 * @param event the bridge event
3595 */
on_call_bridge_event(struct rayo_client * rclient,switch_event_t * event)3596 static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *event)
3597 {
3598 const char *a_uuid = switch_event_get_header(event, "Unique-ID");
3599 const char *b_uuid = switch_event_get_header(event, "Bridge-B-Unique-ID");
3600 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(a_uuid);
3601 struct rayo_call *b_call;
3602
3603 if (call) {
3604 iks *revent;
3605 iks *joined;
3606
3607 call->joined = JOINED_CALL;
3608 call->joined_id = switch_core_sprintf(RAYO_POOL(call), "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
3609
3610 /* send IQ result to client now. */
3611 if (call->pending_join_request) {
3612 iks *request = call->pending_join_request;
3613 iks *result = iks_new_iq_result(request);
3614 call->pending_join_request = NULL;
3615 RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
3616 iks_delete(request);
3617 }
3618
3619 b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
3620 if (b_call) {
3621 b_call->joined = JOINED_CALL;
3622 b_call->joined_id = switch_core_sprintf(RAYO_POOL(b_call), "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
3623
3624 /* send IQ result to client now. */
3625 if (b_call->pending_join_request) {
3626 iks *request = b_call->pending_join_request;
3627 iks *result = iks_new_iq_result(request);
3628 b_call->pending_join_request = NULL;
3629 RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
3630 iks_delete(request);
3631 }
3632
3633 /* send B-leg event */
3634 revent = iks_new_presence("joined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
3635 joined = iks_find(revent, "joined");
3636 iks_insert_attrib_printf(joined, "call-uri", "%s", b_call->joined_id);
3637
3638 RAYO_SEND_MESSAGE(b_call, rayo_call_get_dcp_jid(b_call), revent);
3639 RAYO_RELEASE(b_call);
3640 }
3641
3642 /* send A-leg event */
3643 revent = iks_new_presence("joined", RAYO_NS,
3644 switch_event_get_header(event, "variable_rayo_call_jid"),
3645 switch_event_get_header(event, "variable_rayo_dcp_jid"));
3646 joined = iks_find(revent, "joined");
3647 iks_insert_attrib_printf(joined, "call-uri", "%s", call->joined_id);
3648
3649 RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
3650
3651 RAYO_RELEASE(call);
3652 }
3653 }
3654
3655 /**
3656 * Handle call park event - this is fired after unjoining a call
3657 * @param rclient the Rayo client
3658 * @param event the unbridge event
3659 */
on_call_park_event(struct rayo_client * rclient,switch_event_t * event)3660 static void on_call_park_event(struct rayo_client *rclient, switch_event_t *event)
3661 {
3662 const char *a_uuid = switch_event_get_header(event, "Unique-ID");
3663 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(a_uuid);
3664
3665 if (call) {
3666 if (call->joined) {
3667 iks *revent;
3668 iks *unjoined;
3669 const char *joined_id = call->joined_id;
3670
3671 call->joined = 0;
3672 call->joined_id = NULL;
3673
3674 /* send IQ result to client now. */
3675 if (call->pending_join_request) {
3676 iks *request = call->pending_join_request;
3677 iks *result = iks_new_iq_result(request);
3678 call->pending_join_request = NULL;
3679 RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
3680 iks_delete(request);
3681 }
3682
3683 /* send A-leg event */
3684 revent = iks_new_presence("unjoined", RAYO_NS,
3685 switch_event_get_header(event, "variable_rayo_call_jid"),
3686 switch_event_get_header(event, "variable_rayo_dcp_jid"));
3687 unjoined = iks_find(revent, "unjoined");
3688 iks_insert_attrib_printf(unjoined, "call-uri", "%s", joined_id);
3689 RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
3690 }
3691 RAYO_RELEASE(call);
3692 }
3693 }
3694
3695 /**
3696 * Handle call execute application event
3697 * @param rclient the Rayo client
3698 * @param event the execute event
3699 */
on_call_execute_event(struct rayo_client * rclient,switch_event_t * event)3700 static void on_call_execute_event(struct rayo_client *rclient, switch_event_t *event)
3701 {
3702 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
3703 if (call) {
3704 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute\n", switch_event_get_header(event, "Application"));
3705 RAYO_RELEASE(call);
3706 }
3707 }
3708
3709 /**
3710 * Handle call execute application complete event
3711 * @param rclient the Rayo client
3712 * @param event the execute complete event
3713 */
on_call_execute_complete_event(struct rayo_client * rclient,switch_event_t * event)3714 static void on_call_execute_complete_event(struct rayo_client *rclient, switch_event_t *event)
3715 {
3716 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
3717 if (call) {
3718 const char *app = switch_event_get_header(event, "Application");
3719 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute complete: %s \n",
3720 app,
3721 switch_event_get_header(event, "Application-Response"));
3722 RAYO_RELEASE(call);
3723 }
3724 }
3725
3726 /**
3727 * Handle events to deliver to client connection
3728 * @param rclient the Rayo client connection to receive the event
3729 * @param event the event.
3730 */
rayo_client_handle_event(struct rayo_client * rclient,switch_event_t * event)3731 static void rayo_client_handle_event(struct rayo_client *rclient, switch_event_t *event)
3732 {
3733 if (event) {
3734 switch (event->event_id) {
3735 case SWITCH_EVENT_CHANNEL_ORIGINATE:
3736 on_call_originate_event(rclient, event);
3737 break;
3738 case SWITCH_EVENT_CHANNEL_PROGRESS:
3739 case SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA:
3740 on_call_ringing_event(rclient, event);
3741 break;
3742 case SWITCH_EVENT_CHANNEL_ANSWER:
3743 on_call_answer_event(rclient, event);
3744 break;
3745 case SWITCH_EVENT_CHANNEL_BRIDGE:
3746 on_call_bridge_event(rclient, event);
3747 break;
3748 case SWITCH_EVENT_CHANNEL_PARK:
3749 on_call_park_event(rclient, event);
3750 break;
3751 case SWITCH_EVENT_CHANNEL_EXECUTE:
3752 on_call_execute_event(rclient, event);
3753 break;
3754 case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:
3755 on_call_execute_complete_event(rclient, event);
3756 break;
3757 default:
3758 /* don't care */
3759 break;
3760 }
3761 }
3762 }
3763
3764 /**
3765 * Receives events from FreeSWITCH core and routes them to the proper Rayo client.
3766 * @param event received from FreeSWITCH core. It will be destroyed by the core after this function returns.
3767 */
route_call_event(switch_event_t * event)3768 static void route_call_event(switch_event_t *event)
3769 {
3770 char *uuid = switch_event_get_header(event, "unique-id");
3771 char *dcp_jid = switch_event_get_header(event, "variable_rayo_dcp_jid");
3772 char *event_subclass = switch_event_get_header(event, "Event-Subclass");
3773
3774 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "got event %s %s\n", switch_event_name(event->event_id), zstr(event_subclass) ? "" : event_subclass);
3775
3776 /* this event is for a rayo client */
3777 if (!zstr(dcp_jid)) {
3778 struct rayo_actor *actor;
3779 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "%s rayo event %s\n", dcp_jid, switch_event_name(event->event_id));
3780
3781 actor = RAYO_LOCATE(dcp_jid);
3782 if (actor && !strcmp(RAT_CLIENT, actor->type)) {
3783 /* route to client */
3784 rayo_client_handle_event(RAYO_CLIENT(actor), event);
3785 } else {
3786 /* TODO orphaned call... maybe allow events to queue so they can be delivered on reconnect? */
3787 switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Orphaned call event %s to %s\n", switch_event_name(event->event_id), dcp_jid);
3788 }
3789 RAYO_RELEASE(actor);
3790 }
3791 }
3792
3793 /**
3794 * Create server.
3795 * @param domain the domain name
3796 * @return the domain
3797 */
rayo_server_create(const char * domain)3798 static struct rayo_actor *rayo_server_create(const char *domain)
3799 {
3800 switch_memory_pool_t *pool;
3801 struct rayo_actor *new_server = NULL;
3802
3803 switch_core_new_memory_pool(&pool);
3804 new_server = switch_core_alloc(pool, sizeof(*new_server));
3805 RAYO_ACTOR_INIT(RAYO_ACTOR(new_server), pool, RAT_SERVER, "", domain, domain, NULL, rayo_server_send);
3806
3807 return new_server;
3808 }
3809
3810 /**
3811 * Create an offer for a call
3812 * @param call the call
3813 * @param session the session
3814 * @return the offer
3815 */
rayo_create_offer(struct rayo_call * call,switch_core_session_t * session)3816 static iks *rayo_create_offer(struct rayo_call *call, switch_core_session_t *session)
3817 {
3818 switch_channel_t *channel = switch_core_session_get_channel(session);
3819 switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel);
3820 iks *presence = iks_new("presence");
3821 iks *c = iks_insert(presence, "c");
3822 iks *offer = iks_insert(presence, "offer");
3823 const char *val;
3824 char *ver;
3825
3826 /* <presence> */
3827 iks_insert_attrib(presence, "from", RAYO_JID(call));
3828
3829 /* <c> */
3830 ver = calculate_entity_sha1_ver(&rayo_call_identity, rayo_call_features);
3831 iks_insert_attrib(c, "xmlns", IKS_NS_XMPP_ENTITY_CAPABILITIES);
3832 iks_insert_attrib(c, "hash", "sha-1");
3833 iks_insert_attrib(c, "node", RAYO_CALL_NS);
3834 iks_insert_attrib(c, "ver", ver);
3835 free(ver);
3836
3837 /* <offer> */
3838 iks_insert_attrib(offer, "xmlns", RAYO_NS);
3839 if (globals.offer_uri && (val = switch_channel_get_variable(channel, "sip_from_uri"))) {
3840 /* is a SIP call - pass the URI */
3841 if (!strchr(val, ':')) {
3842 iks_insert_attrib_printf(offer, "from", "sip:%s", val);
3843 } else {
3844 iks_insert_attrib(offer, "from", val);
3845 }
3846 } else {
3847 /* pass caller ID */
3848 iks_insert_attrib(offer, "from", profile->caller_id_number);
3849 }
3850
3851 if (globals.offer_uri && (val = switch_channel_get_variable(channel, "sip_to_uri"))) {
3852 /* is a SIP call - pass the URI */
3853 if (!strchr(val, ':')) {
3854 iks_insert_attrib_printf(offer, "to", "sip:%s", val);
3855 } else {
3856 iks_insert_attrib(offer, "to", val);
3857 }
3858 } else {
3859 /* pass dialed number */
3860 iks_insert_attrib(offer, "to", profile->destination_number);
3861 }
3862
3863 add_header(offer, "from", switch_channel_get_variable(channel, "sip_full_from"));
3864 add_header(offer, "to", switch_channel_get_variable(channel, "sip_full_to"));
3865 add_header(offer, "via", switch_channel_get_variable(channel, "sip_full_via"));
3866 add_channel_headers_to_event(offer, channel, globals.add_variables_to_offer);
3867
3868 return presence;
3869 }
3870
3871 /**
3872 * Monitor rayo call activity - detect idle
3873 */
rayo_call_on_read_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int i)3874 static switch_status_t rayo_call_on_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int i)
3875 {
3876 switch_channel_t *channel = switch_core_session_get_channel(session);
3877 struct rayo_call *call = (struct rayo_call *)switch_channel_get_private(channel, "rayo_call_private");
3878 if (call) {
3879 switch_time_t now = switch_micro_time_now();
3880 switch_time_t idle_start = call->idle_start_time;
3881 int idle_duration_ms = (now - idle_start) / 1000;
3882 /* detect idle session (rayo-client has stopped controlling call) and terminate call */
3883 if (rayo_call_is_joined(call) || rayo_call_is_faxing(call) || RAYO_ACTOR(call)->ref_count > 1) {
3884 call->idle_start_time = now;
3885 } else if (idle_duration_ms > globals.max_idle_ms) {
3886 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ending abandoned call. idle_duration_ms = %i ms\n", idle_duration_ms);
3887 switch_channel_hangup(channel, RAYO_CAUSE_HANGUP);
3888 }
3889 }
3890 return SWITCH_STATUS_SUCCESS;
3891 }
3892
3893 /**
3894 * @param rclient to check
3895 * @param offer_filters optional list of username or username@server to match with client JID.
3896 * @param offer_filter_count
3897 * @return 1 if client is online and optional filter(s) match the client. 0 otherwise.
3898 */
should_offer_to_client(struct rayo_client * rclient,char ** offer_filters,int offer_filter_count)3899 static int should_offer_to_client(struct rayo_client *rclient, char **offer_filters, int offer_filter_count)
3900 {
3901 if (rclient->availability != PS_ONLINE) {
3902 return 0;
3903 }
3904
3905 if (offer_filter_count == 0) {
3906 /* online and no filters to match */
3907 return 1;
3908 } else {
3909 /* check if one of the filters matches the client */
3910 int i;
3911 const char *client_jid = RAYO_JID(rclient);
3912 size_t client_jid_len = strlen(client_jid);
3913 for (i = 0; i < offer_filter_count; i++) {
3914 char *offer_filter = offer_filters[i];
3915 if (!zstr(offer_filter)) {
3916 size_t offer_filter_len = strlen(offer_filter);
3917 if (strchr(offer_filter, '@')) {
3918 if (offer_filter_len <= client_jid_len && !strncmp(offer_filter, client_jid, offer_filter_len)) {
3919 /* username + server match */
3920 return 1;
3921 }
3922 } else if (offer_filter_len < client_jid_len && !strncmp(offer_filter, client_jid, offer_filter_len) && client_jid[offer_filter_len] == '@') {
3923 /* username match */
3924 return 1;
3925 }
3926 }
3927 }
3928 }
3929 return 0;
3930 }
3931
3932 /**
3933 * Offered call information
3934 */
3935 struct offered_call_info {
3936 /** Call JID */
3937 char *call_jid;
3938 /** Time this offer expires */
3939 switch_time_t offer_time;
3940 };
3941
3942 /**
3943 * Deliver offer message to next available client(s)
3944 */
send_offer_to_clients(struct rayo_call * from_call,switch_core_session_t * session)3945 static int send_offer_to_clients(struct rayo_call *from_call, switch_core_session_t *session)
3946 {
3947 int i = 0;
3948 int selection = 0;
3949 int sent = 0;
3950 switch_hash_index_t *hi = NULL;
3951 iks *offer = NULL;
3952
3953 if (from_call->num_acps <= 0) {
3954 return 0;
3955 }
3956
3957 if (globals.offer_algorithm == OFFER_RANDOM) {
3958 /* pick client at (not really) random */
3959 selection = rand() % from_call->num_acps;
3960 } else if (globals.offer_algorithm == OFFER_FIRST) {
3961 /* send to first client */
3962 selection = 0;
3963 } else {
3964 /* send to all clients */
3965 selection = -1;
3966 }
3967
3968 for (hi = switch_core_hash_first(from_call->acps); hi; hi = switch_core_hash_next(&hi)) {
3969 if (i++ == selection || selection == -1) {
3970 const char *to_client_jid = NULL;
3971 const void *key;
3972 void *val;
3973
3974 /* get client jid to send to */
3975 switch_core_hash_this(hi, &key, NULL, &val);
3976 to_client_jid = (const char *)key;
3977 switch_assert(to_client_jid);
3978
3979 /* send offer to client, remembering jid as PCP */
3980 if (!offer) {
3981 offer = rayo_create_offer(from_call, session);
3982 }
3983 switch_core_hash_insert(from_call->pcps, to_client_jid, "1");
3984 iks_insert_attrib(offer, "to", to_client_jid);
3985 RAYO_SEND_MESSAGE_DUP(from_call, to_client_jid, offer);
3986
3987 sent = 1;
3988 from_call->num_acps--;
3989
3990 if (selection != -1) {
3991 break;
3992 }
3993 }
3994 }
3995 switch_safe_free(hi);
3996
3997 if (sent) {
3998 /* remove offered client JID(s) from list of available clients */
3999 hi = NULL;
4000 for (hi = switch_core_hash_first(from_call->pcps); hi; hi = switch_core_hash_next(&hi)) {
4001 const char *to_client_jid = NULL;
4002 const void *key;
4003 void *val;
4004
4005 /* get client jid that was sent offer */
4006 switch_core_hash_this(hi, &key, NULL, &val);
4007 to_client_jid = (const char *)key;
4008 switch_assert(to_client_jid);
4009
4010 /* remove client jid from available controlling parties */
4011 switch_core_hash_delete(from_call->acps, to_client_jid);
4012 }
4013 switch_safe_free(hi);
4014
4015 /* remember when offer was sent for this call to track timeouts */
4016 if (globals.offer_timeout_us > 0) {
4017 struct offered_call_info *offered_call;
4018 switch_zmalloc(offered_call, sizeof(*offered_call));
4019 offered_call->offer_time = switch_micro_time_now();
4020 offered_call->call_jid = strdup(RAYO_JID(from_call));
4021 if (switch_queue_trypush(globals.offer_queue, offered_call) != SWITCH_STATUS_SUCCESS) {
4022 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Failed to queue offered call info! Offer timeout won't work on this call\n");
4023 switch_safe_free(offered_call->call_jid);
4024 switch_safe_free(offered_call);
4025 }
4026 }
4027 }
4028
4029 if (offer) {
4030 iks_delete(offer);
4031 }
4032
4033 return sent;
4034 }
4035
4036 /**
4037 * Thread that monitors for timed out offers
4038 * @param thread this thread
4039 * @param obj unused
4040 * @return NULL
4041 */
offer_timeout_thread(switch_thread_t * thread,void * obj)4042 static void *SWITCH_THREAD_FUNC offer_timeout_thread(switch_thread_t *thread, void *obj)
4043 {
4044 struct offered_call_info *next_offer;
4045 switch_thread_rwlock_rdlock(globals.shutdown_rwlock);
4046 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New offer timeout thread\n");
4047 while (!globals.shutdown) {
4048 if (switch_queue_pop(globals.offer_queue, (void *)&next_offer) == SWITCH_STATUS_SUCCESS) {
4049 switch_time_t now = switch_micro_time_now();
4050 switch_time_t offer_timeout = next_offer->offer_time + globals.offer_timeout_us;
4051
4052 /* wait for timeout */
4053 while (offer_timeout > now && !globals.shutdown) {
4054 switch_time_t remain = offer_timeout - now;
4055 remain = remain > 500000 ? 500000 : remain;
4056 switch_sleep(remain);
4057 now = switch_micro_time_now();
4058 }
4059
4060 /* check if offer was accepted - it is accepted if the call has a DCP (definitive controlling party) */
4061 if (!globals.shutdown) {
4062 struct rayo_call *call = RAYO_CALL_LOCATE(next_offer->call_jid);
4063 if (call) {
4064 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
4065 if (zstr(rayo_call_get_dcp_jid(call))) {
4066 switch_core_session_t *session = switch_core_session_locate(rayo_call_get_uuid(call));
4067 if (session) {
4068 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, offer timeout\n", RAYO_JID(call));
4069 if (!send_offer_to_clients(call, session)) {
4070 /* nobody to offer to, end call */
4071 switch_channel_t *channel = switch_core_session_get_channel(session);
4072 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no more clients to offer, ending call\n", RAYO_JID(call));
4073 switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
4074 }
4075 switch_core_session_rwunlock(session);
4076 }
4077 }
4078 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
4079 RAYO_RELEASE(call);
4080 }
4081 }
4082
4083 switch_safe_free(next_offer->call_jid);
4084 switch_safe_free(next_offer);
4085 }
4086 }
4087
4088 /* clean up queue */
4089 while(switch_queue_trypop(globals.offer_queue, (void *)&next_offer) == SWITCH_STATUS_SUCCESS) {
4090 switch_safe_free(next_offer->call_jid);
4091 switch_safe_free(next_offer);
4092 }
4093
4094 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Offer timeout thread finished\n");
4095 switch_thread_rwlock_unlock(globals.shutdown_rwlock);
4096
4097 return NULL;
4098 }
4099
4100 /**
4101 * Create a new offer timeout thread
4102 * @param pool to use
4103 */
start_offer_timeout_thread(switch_memory_pool_t * pool)4104 static void start_offer_timeout_thread(switch_memory_pool_t *pool)
4105 {
4106 switch_thread_t *thread;
4107 switch_threadattr_t *thd_attr = NULL;
4108 switch_threadattr_create(&thd_attr, pool);
4109 switch_threadattr_detach_set(thd_attr, 1);
4110 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
4111 switch_thread_create(&thread, thd_attr, offer_timeout_thread, NULL, pool);
4112 }
4113
4114 #define RAYO_USAGE "[client username 1,client username n]"
4115 /**
4116 * Offer call and park channel
4117 */
SWITCH_STANDARD_APP(rayo_app)4118 SWITCH_STANDARD_APP(rayo_app)
4119 {
4120 int ok = 0;
4121 switch_channel_t *channel = switch_core_session_get_channel(session);
4122 struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_core_session_get_uuid(session));
4123 const char *app = ""; /* optional app to execute */
4124 const char *app_args = ""; /* app args */
4125
4126 /* don't need to keep call reference count incremented in session- call is destroyed after all apps finish */
4127 if (call) {
4128 RAYO_RELEASE(call);
4129 }
4130
4131 /* is outbound call already under control? */
4132 if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
4133 const char *origination_args = switch_channel_get_variable(channel, "rayo_origination_args");
4134 /* check origination args */
4135 if (!zstr(origination_args)) {
4136 char *argv[2] = { 0 };
4137 char *args = switch_core_session_strdup(session, origination_args);
4138 int argc = switch_separate_string(args, ' ', argv, sizeof(argv) / sizeof(argv[0]));
4139 if (argc) {
4140 if (!strcmp("conference", argv[0])) {
4141 app = "conference";
4142 app_args = argv[1];
4143 } else if (!strcmp("bridge", argv[0])) {
4144 app = "intercept";
4145 app_args = argv[1];
4146 } else {
4147 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Invalid rayo args: %s\n", data);
4148 goto done;
4149 }
4150 }
4151 }
4152 if (!call) {
4153 /* this scenario can only happen if a call was originated through a mechanism other than <dial>
4154 and then the rayo APP was executed to offer control */
4155 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Outbound call that wasn't created with <dial>, will try to offer control\n");
4156 }
4157 ok = 1;
4158 }
4159
4160 if (!call) {
4161 /* offer control */
4162 switch_hash_index_t *hi = NULL;
4163 char *clients_to_offer[16] = { 0 };
4164 int clients_to_offer_count = 0;
4165
4166 call = rayo_call_create(switch_core_session_get_uuid(session));
4167 if (!call) {
4168 /* nothing that can be done to recover... */
4169 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to create call entity!\n");
4170 switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
4171 return;
4172 }
4173
4174 switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_call_jid", RAYO_JID(call));
4175
4176 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Offering call for Rayo 3PCC\n");
4177
4178 if (!zstr(data)) {
4179 char *data_dup = switch_core_session_strdup(session, data);
4180 clients_to_offer_count = switch_separate_string(data_dup, ',', clients_to_offer, sizeof(clients_to_offer) / sizeof(clients_to_offer[0]));
4181 }
4182
4183 /* It is now safe for inbound call to be fully controlled by rayo client */
4184 if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
4185 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
4186 call->rayo_app_started = 1;
4187 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
4188 }
4189
4190 /* Offer call to all (or specified) ONLINE clients */
4191 switch_mutex_lock(globals.clients_mutex);
4192 for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) {
4193 struct rayo_client *rclient;
4194 const void *key;
4195 void *val;
4196 switch_core_hash_this(hi, &key, NULL, &val);
4197 rclient = (struct rayo_client *)val;
4198 switch_assert(rclient);
4199
4200 /* find clients available to take calls */
4201 if (should_offer_to_client(rclient, clients_to_offer, clients_to_offer_count)) {
4202 switch_core_hash_insert(call->acps, RAYO_JID(rclient), "1");
4203 call->num_acps++;
4204 }
4205 }
4206 ok = send_offer_to_clients(call, session);
4207
4208 switch_mutex_unlock(globals.clients_mutex);
4209
4210 /* nobody to offer to */
4211 if (!ok) {
4212 pause_when_offline();
4213 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Rejecting rayo call - there are no online rayo clients to offer call to\n");
4214 switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
4215 }
4216 }
4217
4218 done:
4219
4220 if (ok) {
4221 switch_channel_set_private(switch_core_session_get_channel(session), "rayo_call_private", call);
4222 switch_channel_set_variable(channel, "hangup_after_bridge", "false");
4223 switch_channel_set_variable(channel, "transfer_after_bridge", "");
4224 switch_channel_set_variable(channel, "park_after_bridge", "true");
4225 switch_channel_set_variable(channel, "hold_hangup_xfer_exten", "park:inline:");
4226 switch_channel_set_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE, "-1"); /* required so that output mixing works */
4227 switch_core_event_hook_add_read_frame(session, rayo_call_on_read_frame);
4228
4229 if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
4230 /* At this point, this outbound call might already be under control of a rayo client that is waiting for answer before sending
4231 commands. The answered event might have been sent before we are ready to execute commands, so we delayed sending
4232 those events if the rayo APP hadn't started yet. This delay would have only been a few milliseconds.
4233 */
4234 switch_mutex_lock(RAYO_ACTOR(call)->mutex);
4235 call->rayo_app_started = 1;
4236 if (call->answer_event) {
4237 struct rayo_client *rclient = RAYO_CLIENT(RAYO_LOCATE(rayo_call_get_dcp_jid(call)));
4238 if (rclient) {
4239 on_call_answer_event(rclient, call->answer_event);
4240 switch_event_destroy(&call->answer_event);
4241 RAYO_RELEASE(rclient);
4242 }
4243 }
4244 switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
4245
4246 /* Outbound calls might have a nested join to another call or conference - do that now */
4247 if (!zstr(app)) {
4248 switch_core_session_execute_application(session, app, app_args);
4249 }
4250 }
4251
4252 /* Ready for remote control */
4253 switch_ivr_park(session, NULL);
4254 }
4255 }
4256
4257 /**
4258 * Stream locates client
4259 */
xmpp_stream_client_locate(struct xmpp_stream * stream,const char * jid)4260 static struct rayo_actor *xmpp_stream_client_locate(struct xmpp_stream *stream, const char *jid)
4261 {
4262 struct rayo_actor *actor = NULL;
4263 if (xmpp_stream_is_s2s(stream)) {
4264 actor = RAYO_LOCATE(jid);
4265 if (!actor) {
4266 /* previously unknown client - add it */
4267 struct rayo_peer_server *rserver = RAYO_PEER_SERVER(xmpp_stream_get_private(stream));
4268 actor = RAYO_ACTOR(rayo_client_create(jid, xmpp_stream_get_jid(stream), PS_UNKNOWN, rayo_client_send, rserver));
4269 RAYO_RETAIN(actor);
4270 } else if (strcmp(RAT_CLIENT, actor->type)) {
4271 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, not a client: %s\n", xmpp_stream_get_jid(stream), jid);
4272 RAYO_RELEASE(actor);
4273 actor = NULL;
4274 }
4275 } else {
4276 actor = RAYO_ACTOR(xmpp_stream_get_private(stream));
4277 RAYO_RETAIN(actor);
4278 }
4279 return actor;
4280 }
4281
4282 /**
4283 * Handle stream resource binding
4284 * @param stream the new stream
4285 */
on_xmpp_stream_bind(struct xmpp_stream * stream)4286 static int on_xmpp_stream_bind(struct xmpp_stream *stream)
4287 {
4288 if (!xmpp_stream_is_s2s(stream)) {
4289 /* client belongs to stream */
4290 struct rayo_client *client = rayo_client_create(xmpp_stream_get_jid(stream), xmpp_stream_get_jid(stream), PS_OFFLINE, rayo_client_send, NULL);
4291 if (client) {
4292 xmpp_stream_set_private(stream, client);
4293 } else {
4294 /* this went really bad... */
4295 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create client entity!\n");
4296 return 0;
4297 }
4298 }
4299 return 1;
4300 }
4301
4302 /**
4303 * Handle new stream creation
4304 * @param stream the new stream
4305 */
on_xmpp_stream_ready(struct xmpp_stream * stream)4306 static int on_xmpp_stream_ready(struct xmpp_stream *stream)
4307 {
4308 if (xmpp_stream_is_s2s(stream)) {
4309 if (xmpp_stream_is_incoming(stream)) {
4310 /* peer server belongs to a s2s inbound stream */
4311 struct rayo_peer_server *peer = rayo_peer_server_create(xmpp_stream_get_jid(stream));
4312 if (peer) {
4313 xmpp_stream_set_private(stream, peer);
4314 } else {
4315 /* this went really bad... */
4316 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "failed to create peer server entity!\n");
4317 return 0;
4318 }
4319 } else {
4320 /* send directed presence to domain */
4321 iks *presence = iks_new("presence");
4322 iks *x;
4323 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "sending server presence\n");
4324
4325 iks_insert_attrib(presence, "from", RAYO_JID(globals.server));
4326 iks_insert_attrib(presence, "to", xmpp_stream_get_jid(stream));
4327 x = iks_insert(presence, "show");
4328 iks_insert_cdata(x, "chat", 4);
4329 RAYO_SEND_MESSAGE(globals.server, xmpp_stream_get_jid(stream), presence);
4330 }
4331 }
4332 return 1;
4333 }
4334
4335 /**
4336 * Checks client availability. If unknown, client presence is probed.
4337 * @param rclient to check
4338 */
rayo_client_presence_check(struct rayo_client * rclient)4339 static void rayo_client_presence_check(struct rayo_client *rclient)
4340 {
4341 if (rclient->availability == PS_UNKNOWN) {
4342 /* for now, set online */
4343 rclient->availability = PS_ONLINE;
4344 }
4345 }
4346
4347 /**
4348 * Handle stream stanza
4349 * @param stream the stream
4350 * @param stanza the stanza to process
4351 */
on_xmpp_stream_recv(struct xmpp_stream * stream,iks * stanza)4352 static void on_xmpp_stream_recv(struct xmpp_stream *stream, iks *stanza)
4353 {
4354 const char *name = iks_name(stanza);
4355 if (!strcmp("iq", name)) {
4356 const char *from = iks_find_attrib_soft(stanza, "from");
4357 struct rayo_actor *actor = xmpp_stream_client_locate(stream, from);
4358 if (actor) {
4359 rayo_client_presence_check(RAYO_CLIENT(actor));
4360 rayo_client_command_recv(RAYO_CLIENT(actor), stanza);
4361 RAYO_RELEASE(actor);
4362 }
4363 } else if (!strcmp("presence", name)) {
4364 const char *from = iks_find_attrib_soft(stanza, "from");
4365 struct rayo_actor *actor = xmpp_stream_client_locate(stream, from);
4366 if (actor) {
4367 on_client_presence(RAYO_CLIENT(actor), stanza);
4368 RAYO_RELEASE(actor);
4369 }
4370 } else if (!strcmp("message", name)) {
4371 const char *from = iks_find_attrib_soft(stanza, "from");
4372 struct rayo_actor *actor = xmpp_stream_client_locate(stream, from);
4373 if (actor) {
4374 rayo_client_presence_check(RAYO_CLIENT(actor));
4375 on_client_message(RAYO_CLIENT(actor), stanza);
4376 RAYO_RELEASE(actor);
4377 }
4378 }
4379 }
4380
4381 /**
4382 * Handle stream destruction
4383 */
on_xmpp_stream_destroy(struct xmpp_stream * stream)4384 static void on_xmpp_stream_destroy(struct xmpp_stream *stream)
4385 {
4386 /* destroy peer server / client associated with this stream */
4387 void *actor = xmpp_stream_get_private(stream);
4388 if (actor) {
4389 RAYO_RELEASE(actor);
4390 RAYO_DESTROY(actor);
4391 }
4392 }
4393
4394 /**
4395 * A command alias
4396 */
4397 struct rayo_cmd_alias {
4398 /** number of additional arguments for alias */
4399 int args;
4400 /** the alias template */
4401 const char *cmd;
4402 };
4403
4404 /**
4405 * Add an alias to an API command
4406 * @param alias_name
4407 * @param alias_target
4408 * @param alias_cmd
4409 * @param alias_args
4410 */
rayo_add_cmd_alias(const char * alias_name,const char * alias_target,const char * alias_cmd,const char * alias_args)4411 static void rayo_add_cmd_alias(const char *alias_name, const char *alias_target, const char *alias_cmd, const char *alias_args)
4412 {
4413 struct rayo_cmd_alias *alias = switch_core_alloc(globals.pool, sizeof(*alias));
4414 alias->args = 0;
4415 if (switch_is_number(alias_args)) {
4416 alias->args = atoi(alias_args);
4417 if (alias->args < 0) {
4418 alias->args = 0;
4419 }
4420 }
4421 alias->cmd = alias_cmd;
4422 switch_core_hash_insert(globals.cmd_aliases, alias_name, alias);
4423
4424 /* set up autocomplete of alias */
4425 if (zstr(alias_target)) {
4426 alias_target = "all";
4427 }
4428 switch_console_set_complete(switch_core_sprintf(globals.pool, "add rayo %s ::rayo::list_%s", alias_name, alias_target));
4429 }
4430
4431 /**
4432 * Process module XML configuration
4433 * @param pool memory pool to allocate from
4434 * @param config_file to use
4435 * @return SWITCH_STATUS_SUCCESS on successful configuration
4436 */
do_config(switch_memory_pool_t * pool,const char * config_file)4437 static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_file)
4438 {
4439 switch_xml_t cfg, xml;
4440 switch_status_t status = SWITCH_STATUS_SUCCESS;
4441
4442 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Configuring module\n");
4443 if (!(xml = switch_xml_open_cfg(config_file, &cfg, NULL))) {
4444 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", config_file);
4445 return SWITCH_STATUS_TERM;
4446 }
4447
4448 /* set defaults */
4449 globals.max_idle_ms = 30000;
4450 globals.mixer_conf_profile = "sla";
4451 globals.num_message_threads = 8;
4452 globals.offer_uri = 1;
4453 globals.pause_when_offline = 0;
4454 globals.add_variables_to_offer = 0;
4455 globals.add_variables_to_events = 0;
4456 globals.offer_timeout_us = 5000000;
4457 globals.offer_algorithm = OFFER_ALL;
4458
4459 /* get params */
4460 {
4461 switch_xml_t settings = switch_xml_child(cfg, "settings");
4462 if (settings) {
4463 switch_xml_t param;
4464 for (param = switch_xml_child(settings, "param"); param; param = param->next) {
4465 const char *var = switch_xml_attr_soft(param, "name");
4466 const char *val = switch_xml_attr_soft(param, "value");
4467 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "param: %s = %s\n", var, val);
4468 if (!strcasecmp(var, "max-idle-sec")) {
4469 if (switch_is_number(val)) {
4470 int max_idle_sec = atoi(val);
4471 if (max_idle_sec > 0) {
4472 globals.max_idle_ms = max_idle_sec * 1000;
4473 }
4474 }
4475 } else if (!strcasecmp(var, "mixer-conf-profile")) {
4476 if (!zstr(val)) {
4477 globals.mixer_conf_profile = switch_core_strdup(pool, val);
4478 }
4479 } else if (!strcasecmp(var, "message-threads")) {
4480 if (switch_is_number(val)) {
4481 int num_message_threads = atoi(val);
4482 if (num_message_threads > 0) {
4483 globals.num_message_threads = num_message_threads;
4484 }
4485 }
4486 } else if (!strcasecmp(var, "offer-uri")) {
4487 if (switch_false(val)) {
4488 globals.offer_uri = 0;
4489 }
4490 } else if (!strcasecmp(var, "pause-when-offline")) {
4491 if (switch_true(val)) {
4492 globals.pause_when_offline = 1;
4493 }
4494 } else if (!strcasecmp(var, "add-variables-to-offer")) {
4495 if (switch_true(val)) {
4496 globals.add_variables_to_offer = 1;
4497 }
4498 } else if (!strcasecmp(var, "add-variables-to-events")) {
4499 if (switch_true(val)) {
4500 globals.add_variables_to_offer = 1;
4501 globals.add_variables_to_events = 1;
4502 }
4503 } else if (!strcasecmp(var, "offer-timeout-ms")) {
4504 int offer_timeout_ms = 0;
4505 if (switch_is_number(val) && (offer_timeout_ms = atoi(val)) >= 0 && offer_timeout_ms < 120000) {
4506 globals.offer_timeout_us = offer_timeout_ms * 1000;
4507 } else {
4508 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid value for offer-timeout-ms \"%s\"\n", val);
4509 }
4510 } else if (!strcasecmp(var, "offer-algorithm")) {
4511 if (zstr(val)) {
4512 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No value for offer-algorithm\n");
4513 } else if (!strcasecmp(val, "all")) {
4514 globals.offer_algorithm = OFFER_ALL;
4515 } else if (!strcasecmp(val, "first")) {
4516 globals.offer_algorithm = OFFER_FIRST;
4517 } else if (!strcasecmp(val, "random")) {
4518 globals.offer_algorithm = OFFER_RANDOM;
4519 } else {
4520 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid value for offer-algorithm \"%s\"\n", val);
4521 }
4522 } else {
4523 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
4524 }
4525 }
4526 }
4527 }
4528
4529 /* configure dial gateways */
4530 {
4531 switch_xml_t dial_gateways = switch_xml_child(cfg, "dial-gateways");
4532
4533 /* set defaults */
4534 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting default dial-gateways\n");
4535 dial_gateway_add("default", "sofia/gateway/outbound/", 0);
4536 dial_gateway_add("tel:", "sofia/gateway/outbound/", 4);
4537 dial_gateway_add("user", "", 0);
4538 dial_gateway_add("sofia", "", 0);
4539
4540 if (dial_gateways) {
4541 switch_xml_t dg;
4542 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting configured dial-gateways\n");
4543 for (dg = switch_xml_child(dial_gateways, "dial-gateway"); dg; dg = dg->next) {
4544 const char *uri_prefix = switch_xml_attr_soft(dg, "uriprefix");
4545 const char *dial_prefix = switch_xml_attr_soft(dg, "dialprefix");
4546 const char *strip_str = switch_xml_attr_soft(dg, "strip");
4547 int strip = 0;
4548
4549 if (!zstr(strip_str) && switch_is_number(strip_str)) {
4550 strip = atoi(strip_str);
4551 if (strip < 0) {
4552 strip = 0;
4553 }
4554 }
4555 if (!zstr(uri_prefix)) {
4556 dial_gateway_add(uri_prefix, dial_prefix, strip);
4557 }
4558 }
4559 }
4560 }
4561
4562 /* configure domain */
4563 {
4564 switch_xml_t domain = switch_xml_child(cfg, "domain");
4565 if (domain) {
4566 switch_xml_t l;
4567 const char *shared_secret = switch_xml_attr_soft(domain, "shared-secret");
4568 const char *name = switch_xml_attr_soft(domain, "name");
4569 const char *cert = switch_xml_attr_soft(domain, "cert");
4570 const char *key = switch_xml_attr_soft(domain, "key");
4571 if (zstr(name)) {
4572 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing <domain name=\"... failed to configure rayo server\n");
4573 status = SWITCH_STATUS_FALSE;
4574 goto done;
4575 }
4576 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Rayo domain set to %s\n", name);
4577
4578 if (zstr(shared_secret)) {
4579 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing shared secret for %s domain. Server dialback will not work\n", name);
4580 }
4581
4582 globals.xmpp_context = xmpp_stream_context_create(name, shared_secret, on_xmpp_stream_bind, on_xmpp_stream_ready, on_xmpp_stream_recv, on_xmpp_stream_destroy);
4583 globals.server = rayo_server_create(name);
4584
4585 /* set up TLS */
4586 if (!zstr(cert)) {
4587 xmpp_stream_context_add_cert(globals.xmpp_context, cert);
4588 }
4589 if (!zstr(key)) {
4590 xmpp_stream_context_add_key(globals.xmpp_context, key);
4591 }
4592
4593 /* configure authorized users for this domain */
4594 l = switch_xml_child(domain, "users");
4595 if (l) {
4596 switch_xml_t u;
4597 for (u = switch_xml_child(l, "user"); u; u = u->next) {
4598 const char *user = switch_xml_attr_soft(u, "name");
4599 const char *password = switch_xml_attr_soft(u, "password");
4600 xmpp_stream_context_add_user(globals.xmpp_context, user, password);
4601 }
4602 }
4603
4604 /* get listeners for this domain */
4605 for (l = switch_xml_child(domain, "listen"); l; l = l->next) {
4606 const char *address = switch_xml_attr_soft(l, "address");
4607 const char *port = switch_xml_attr_soft(l, "port");
4608 const char *type = switch_xml_attr_soft(l, "type");
4609 const char *acl = switch_xml_attr_soft(l, "acl");
4610 int is_s2s = 0;
4611 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s listener: %s:%s\n", type, address, port);
4612 is_s2s = !strcmp("s2s", type);
4613 if (!is_s2s && strcmp("c2s", type)) {
4614 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Type must be \"c2s\" or \"s2s\"!\n");
4615 status = SWITCH_STATUS_FALSE;
4616 goto done;
4617 }
4618 if (zstr(address)) {
4619 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing address!\n");
4620 status = SWITCH_STATUS_FALSE;
4621 goto done;
4622 }
4623 if (!zstr(port) && !switch_is_number(port)) {
4624 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Port must be an integer!\n");
4625 status = SWITCH_STATUS_FALSE;
4626 goto done;
4627 }
4628 if (xmpp_stream_context_listen(globals.xmpp_context, address, atoi(port), is_s2s, acl) != SWITCH_STATUS_SUCCESS) {
4629 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to create %s listener: %s:%s\n", type, address, port);
4630 }
4631 }
4632
4633 /* get outbound server connections */
4634 for (l = switch_xml_child(domain, "connect"); l; l = l->next) {
4635 const char *domain = switch_xml_attr_soft(l, "domain");
4636 const char *address = switch_xml_attr_soft(l, "address");
4637 const char *port = switch_xml_attr_soft(l, "port");
4638 if (!zstr(port) && !switch_is_number(port)) {
4639 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Outbound server port must be an integer!\n");
4640 status = SWITCH_STATUS_FALSE;
4641 goto done;
4642 }
4643 if (zstr(address) && zstr(domain)) {
4644 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing outbound server address!\n");
4645 status = SWITCH_STATUS_FALSE;
4646 goto done;
4647 }
4648 xmpp_stream_context_connect(globals.xmpp_context, domain, address, atoi(port));
4649 }
4650 }
4651 }
4652
4653 /* get aliases */
4654 {
4655 switch_xml_t aliases = switch_xml_child(cfg, "aliases");
4656 if (aliases) {
4657 switch_xml_t alias;
4658 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting configured aliases\n");
4659 for (alias = switch_xml_child(aliases, "alias"); alias; alias = alias->next) {
4660 const char *alias_name = switch_xml_attr_soft(alias, "name");
4661 const char *alias_target = switch_xml_attr_soft(alias, "target");
4662 const char *alias_args = switch_xml_attr_soft(alias, "args");
4663 if (!zstr(alias_name) && !zstr(alias->txt)) {
4664 rayo_add_cmd_alias(alias_name, switch_core_strdup(pool, alias_target), switch_core_strdup(pool, alias->txt), switch_core_strdup(pool, alias_args));
4665 }
4666 }
4667 }
4668 }
4669
4670 done:
4671 switch_xml_free(xml);
4672
4673 return status;
4674 }
4675
4676 /**
4677 * Dump rayo actor stats
4678 */
rayo_actor_dump(struct rayo_actor * actor,switch_stream_handle_t * stream)4679 static void rayo_actor_dump(struct rayo_actor *actor, switch_stream_handle_t *stream)
4680 {
4681 if (!strcmp(RAT_CLIENT, actor->type)) {
4682 stream->write_function(stream, "TYPE='%s',SUBTYPE='%s',ID='%s',JID='%s',DOMAIN='%s',REFS=%i,STATUS='%s'", actor->type, actor->subtype, actor->id, RAYO_JID(actor), RAYO_DOMAIN(actor), actor->ref_count, presence_status_to_string(RAYO_CLIENT(actor)->availability));
4683 } else {
4684 stream->write_function(stream, "TYPE='%s',SUBTYPE='%s',ID='%s',JID='%s',DOMAIN='%s',REFS=%i", actor->type, actor->subtype, actor->id, RAYO_JID(actor), RAYO_DOMAIN(actor), actor->ref_count);
4685 }
4686 }
4687
4688 /**
4689 * Dump rayo actors
4690 */
dump_api(const char * cmd,switch_stream_handle_t * stream)4691 static int dump_api(const char *cmd, switch_stream_handle_t *stream)
4692 {
4693 switch_hash_index_t *hi;
4694 if (!zstr(cmd)) {
4695 return 0;
4696 }
4697
4698 stream->write_function(stream, "\nENTITIES\n");
4699 switch_mutex_lock(globals.actors_mutex);
4700 for (hi = switch_core_hash_first(globals.actors); hi; hi = switch_core_hash_next(&hi)) {
4701 struct rayo_actor *actor = NULL;
4702 const void *key;
4703 void *val;
4704 switch_core_hash_this(hi, &key, NULL, &val);
4705 actor = (struct rayo_actor *)val;
4706 switch_assert(actor);
4707 stream->write_function(stream, " ");
4708 rayo_actor_dump(actor, stream);
4709 stream->write_function(stream, "\n");
4710 }
4711
4712 for (hi = switch_core_hash_first(globals.destroy_actors); hi; hi = switch_core_hash_next(&hi)) {
4713 struct rayo_actor *actor = NULL;
4714 const void *key;
4715 void *val;
4716 switch_core_hash_this(hi, &key, NULL, &val);
4717 actor = (struct rayo_actor *)val;
4718 switch_assert(actor);
4719 stream->write_function(stream, "(DEAD) ");
4720 rayo_actor_dump(actor, stream);
4721 stream->write_function(stream, "\n");
4722 }
4723 switch_mutex_unlock(globals.actors_mutex);
4724
4725 xmpp_stream_context_dump(globals.xmpp_context, stream);
4726
4727 return 1;
4728 }
4729
4730 /**
4731 * Process response to console command_api
4732 */
rayo_console_client_send(struct rayo_actor * actor,struct rayo_message * msg)4733 void rayo_console_client_send(struct rayo_actor *actor, struct rayo_message *msg)
4734 {
4735 iks *response = msg->payload;
4736
4737 if (response) {
4738 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\nRECV: from %s, %s\n", msg->from_jid, iks_string(iks_stack(response), response));
4739 } else {
4740 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\nRECV: (null) from %s\n", msg->from_jid);
4741 }
4742 }
4743
4744 /**
4745 * Create a new Rayo console client
4746 * @return the new client or NULL
4747 */
rayo_console_client_create(void)4748 static struct rayo_client *rayo_console_client_create(void)
4749 {
4750 struct rayo_client *client = NULL;
4751 char *jid = NULL;
4752 char id[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
4753 switch_uuid_str(id, sizeof(id));
4754 jid = switch_mprintf("%s@%s/console", id, RAYO_JID(globals.server));
4755 client = rayo_client_create(jid, NULL, PS_OFFLINE, rayo_console_client_send, NULL);
4756 free(jid);
4757 return client;
4758 }
4759
4760 /**
4761 * Send command from console
4762 */
send_console_command(struct rayo_client * client,const char * to,const char * command_str)4763 static void send_console_command(struct rayo_client *client, const char *to, const char *command_str)
4764 {
4765 iks *command = NULL;
4766 iksparser *p = iks_dom_new(&command);
4767
4768 if (iks_parse(p, command_str, 0, 1) == IKS_OK && command) {
4769 char *str;
4770 iks *iq = NULL;
4771
4772 /* is command already wrapped in IQ? */
4773 if (!strcmp(iks_name(command), "iq")) {
4774 /* command already IQ */
4775 iq = command;
4776 } else {
4777 /* create IQ to wrap command */
4778 iq = iks_new_within("iq", iks_stack(command));
4779 iks_insert_node(iq, command);
4780 }
4781
4782 /* fill in command attribs */
4783 iks_insert_attrib(iq, "to", to);
4784 if (!iks_find_attrib(iq, "type")) {
4785 iks_insert_attrib(iq, "type", "set");
4786 }
4787 if (!iks_find_attrib(iq, "id")) {
4788 iks_insert_attrib_printf(iq, "id", "console-%i", RAYO_SEQ_NEXT(client));
4789 }
4790 iks_insert_attrib(iq, "from", RAYO_JID(client));
4791
4792 /* send command */
4793 str = iks_string(iks_stack(iq), iq);
4794 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\nSEND: to %s, %s\n", to, str);
4795 rayo_client_command_recv(client, iq);
4796 iks_delete(command);
4797 } else {
4798 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "bad request xml\n");
4799 }
4800 iks_parser_delete(p);
4801 }
4802
4803 /**
4804 * Send command to rayo actor
4805 */
command_api(char * cmd,switch_stream_handle_t * stream)4806 static int command_api(char *cmd, switch_stream_handle_t *stream)
4807 {
4808 char *argv[2] = { 0 };
4809 if (!zstr(cmd)) {
4810 int argc = switch_separate_string(cmd, ' ', argv, sizeof(argv) / sizeof(argv[0]));
4811 if (argc != 2) {
4812 return 0;
4813 }
4814 } else {
4815 return 0;
4816 }
4817
4818 /* send command */
4819 send_console_command(globals.console, argv[0], argv[1]);
4820 stream->write_function(stream, "+OK\n");
4821
4822 return 1;
4823 }
4824
4825 /**
4826 * Send command to rayo actor
4827 */
alias_api(struct rayo_cmd_alias * alias,char * args,switch_stream_handle_t * stream)4828 static int alias_api(struct rayo_cmd_alias *alias, char *args, switch_stream_handle_t *stream)
4829 {
4830 char *argv[10] = { 0 };
4831 int argc, i;
4832 char *cmd;
4833 char *jid;
4834
4835 if (zstr(alias->cmd)) {
4836 stream->write_function(stream, "-ERR missing alias template. Check configuration.\n");
4837 }
4838
4839 if (zstr(args)) {
4840 stream->write_function(stream, "-ERR no args\n");
4841 return 1;
4842 }
4843
4844 /* check args */
4845 argc = switch_separate_string(args, ' ', argv, sizeof(argv) / sizeof(argv[0]));
4846 if (argc != alias->args + 1) {
4847 stream->write_function(stream, "-ERR wrong number of args (%i/%i)\n", argc, alias->args + 1);
4848 return 1;
4849 }
4850
4851 jid = argv[0];
4852
4853 /* build command from args */
4854 cmd = strdup(alias->cmd);
4855 for (i = 1; i < argc; i++) {
4856 char *cmd_new;
4857 char to_replace[12] = { 0 };
4858 sprintf(to_replace, "$%i", i);
4859 cmd_new = switch_string_replace(cmd, to_replace, argv[i]);
4860 free(cmd);
4861 cmd = cmd_new;
4862 }
4863
4864 /* send command */
4865 send_console_command(globals.console, jid, cmd);
4866 stream->write_function(stream, "+OK\n");
4867 free(cmd);
4868
4869 return 1;
4870 }
4871
4872 /**
4873 * Send message from console
4874 */
send_console_message(struct rayo_client * client,const char * to,const char * type,const char * message_str)4875 static void send_console_message(struct rayo_client *client, const char *to, const char *type, const char *message_str)
4876 {
4877 iks *message = NULL, *x;
4878 message = iks_new("message");
4879 iks_insert_attrib(message, "to", to);
4880 iks_insert_attrib(message, "from", RAYO_JID(client));
4881 iks_insert_attrib_printf(message, "id", "console-%i", RAYO_SEQ_NEXT(client));
4882 iks_insert_attrib(message, "type", type);
4883 x = iks_insert(message, "body");
4884 iks_insert_cdata(x, message_str, strlen(message_str));
4885 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\nSEND: to %s, %s\n", to, iks_string(iks_stack(message), message));
4886 RAYO_SEND_MESSAGE(client, to, message);
4887 }
4888
4889 /**
4890 * Send message to rayo actor
4891 */
message_api(char * cmd,switch_stream_handle_t * stream)4892 static int message_api(char *cmd, switch_stream_handle_t *stream)
4893 {
4894 char *argv[3] = { 0 };
4895 if (!zstr(cmd)) {
4896 int argc = switch_separate_string(cmd, ' ', argv, sizeof(argv) / sizeof(argv[0]));
4897 if (argc != 3) {
4898 return 0;
4899 }
4900 } else {
4901 return 0;
4902 }
4903
4904 /* send message */
4905 send_console_message(globals.console, argv[0], argv[1], argv[2]);
4906 stream->write_function(stream, "+OK\n");
4907
4908 return 1;
4909 }
4910
4911 /**
4912 * Send presence from console
4913 */
send_console_presence(struct rayo_client * client,const char * to,int is_online)4914 static void send_console_presence(struct rayo_client *client, const char *to, int is_online)
4915 {
4916 iks *presence = NULL, *x;
4917 presence = iks_new("presence");
4918 iks_insert_attrib(presence, "to", to);
4919 iks_insert_attrib(presence, "from", RAYO_JID(client));
4920 iks_insert_attrib_printf(presence, "id", "console-%i", RAYO_SEQ_NEXT(client));
4921 if (!is_online) {
4922 iks_insert_attrib(presence, "type", "unavailable");
4923 }
4924 x = iks_insert(presence, "show");
4925 iks_insert_cdata(x, is_online ? "chat" : "dnd", 0);
4926 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\nSEND: to %s, %s\n", to, iks_string(iks_stack(presence), presence));
4927 RAYO_SEND_MESSAGE(client, to, presence);
4928 }
4929
4930 /**
4931 * Send console presence
4932 */
presence_api(char * cmd,switch_stream_handle_t * stream)4933 static int presence_api(char *cmd, switch_stream_handle_t *stream)
4934 {
4935 int is_online = 0;
4936 char *argv[2] = { 0 };
4937 if (!zstr(cmd)) {
4938 int argc = switch_separate_string(cmd, ' ', argv, sizeof(argv) / sizeof(argv[0]));
4939 if (argc != 2) {
4940 return 0;
4941 }
4942 } else {
4943 return 0;
4944 }
4945
4946 if (!strcmp("online", argv[1])) {
4947 is_online = 1;
4948 } else if (strcmp("offline", argv[1])) {
4949 return 0;
4950 }
4951
4952 /* send presence */
4953 send_console_presence(globals.console, argv[0], is_online);
4954 stream->write_function(stream, "+OK\n");
4955 return 1;
4956 }
4957
4958 #define RAYO_API_SYNTAX "status | (<alias> <jid>) | (cmd <jid> <command>) | (msg <jid> <message text>) | (presence <jid> <online|offline>)"
SWITCH_STANDARD_API(rayo_api)4959 SWITCH_STANDARD_API(rayo_api)
4960 {
4961 struct rayo_cmd_alias *alias;
4962 char *cmd_dup = NULL;
4963 char *argv[2] = { 0 };
4964 int success = 0;
4965
4966 if (zstr(cmd) ) {
4967 goto done;
4968 }
4969
4970 cmd_dup = strdup(cmd);
4971 switch_separate_string(cmd_dup, ' ', argv, sizeof(argv) / sizeof(argv[0]));
4972
4973 /* check if a command alias */
4974 alias = switch_core_hash_find(globals.cmd_aliases, argv[0]);
4975
4976 if (alias) {
4977 success = alias_api(alias, argv[1], stream);
4978 } else if (!strcmp("cmd", argv[0])) {
4979 success = command_api(argv[1], stream);
4980 } else if (!strcmp("status", argv[0])) {
4981 success = dump_api(argv[1], stream);
4982 } else if (!strcmp("msg", argv[0])) {
4983 success = message_api(argv[1], stream);
4984 } else if (!strcmp("presence", argv[0])) {
4985 success = presence_api(argv[1], stream);
4986 }
4987
4988 done:
4989 if (!success) {
4990 stream->write_function(stream, "-ERR: USAGE %s\n", RAYO_API_SYNTAX);
4991 }
4992
4993 switch_safe_free(cmd_dup);
4994
4995 return SWITCH_STATUS_SUCCESS;
4996 }
4997
4998 /**
4999 * Console auto-completion for actors given validation function
5000 */
list_actors(const char * line,const char * cursor,switch_console_callback_match_t ** matches,rayo_actor_match_fn match)5001 static switch_status_t list_actors(const char *line, const char *cursor, switch_console_callback_match_t **matches, rayo_actor_match_fn match)
5002 {
5003 switch_hash_index_t *hi;
5004 void *val;
5005 const void *vvar;
5006 switch_console_callback_match_t *my_matches = NULL;
5007 switch_status_t status = SWITCH_STATUS_FALSE;
5008 struct rayo_actor *actor;
5009
5010 switch_mutex_lock(globals.actors_mutex);
5011 for (hi = switch_core_hash_first(globals.actors); hi; hi = switch_core_hash_next(&hi)) {
5012 switch_core_hash_this(hi, &vvar, NULL, &val);
5013
5014 actor = (struct rayo_actor *) val;
5015 if (match(actor)) {
5016 switch_console_push_match(&my_matches, (const char *) vvar);
5017 }
5018 }
5019 switch_mutex_unlock(globals.actors_mutex);
5020
5021 if (my_matches) {
5022 *matches = my_matches;
5023 status = SWITCH_STATUS_SUCCESS;
5024 }
5025
5026 return status;
5027 }
5028
5029 /**
5030 * @return true if internal actor
5031 */
is_internal_actor(struct rayo_actor * actor)5032 static switch_bool_t is_internal_actor(struct rayo_actor *actor)
5033 {
5034 return strcmp(RAT_CLIENT, actor->type) && strcmp(RAT_PEER_SERVER, actor->type);
5035 }
5036
5037 /**
5038 * Console auto-completion for all internal actors
5039 */
list_internal(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5040 static switch_status_t list_internal(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5041 {
5042 return list_actors(line, cursor, matches, is_internal_actor);
5043 }
5044
5045 /**
5046 * @return true if external actor
5047 */
is_external_actor(struct rayo_actor * actor)5048 static switch_bool_t is_external_actor(struct rayo_actor *actor)
5049 {
5050 return !strcmp(RAT_CLIENT, actor->type) || !strcmp(RAT_PEER_SERVER, actor->type);
5051 }
5052
5053 /**
5054 * Console auto-completion for all external actors
5055 */
list_external(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5056 static switch_status_t list_external(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5057 {
5058 return list_actors(line, cursor, matches, is_external_actor);
5059 }
5060
5061 /**
5062 * @return true
5063 */
is_any_actor(struct rayo_actor * actor)5064 static switch_bool_t is_any_actor(struct rayo_actor *actor)
5065 {
5066 return SWITCH_TRUE;
5067 }
5068
5069 /**
5070 * Console auto-completion for all actors
5071 */
list_all(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5072 static switch_status_t list_all(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5073 {
5074 return list_actors(line, cursor, matches, is_any_actor);
5075 }
5076
5077 /**
5078 * @return true if a server
5079 */
is_server_actor(struct rayo_actor * actor)5080 static switch_bool_t is_server_actor(struct rayo_actor *actor)
5081 {
5082 return !strcmp(RAT_SERVER, actor->type);
5083 }
5084
5085 /**
5086 * Console auto-completion for all servers
5087 */
list_server(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5088 static switch_status_t list_server(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5089 {
5090 return list_actors(line, cursor, matches, is_server_actor);
5091 }
5092
5093 /**
5094 * @return true if a call
5095 */
is_call_actor(struct rayo_actor * actor)5096 static switch_bool_t is_call_actor(struct rayo_actor *actor)
5097 {
5098 return !strcmp(RAT_CALL, actor->type);
5099 }
5100
5101 /**
5102 * Console auto-completion for all calls
5103 */
list_call(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5104 static switch_status_t list_call(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5105 {
5106 return list_actors(line, cursor, matches, is_call_actor);
5107 }
5108
5109 /**
5110 * @return true if a component
5111 */
is_component_actor(struct rayo_actor * actor)5112 switch_bool_t is_component_actor(struct rayo_actor *actor)
5113 {
5114 return !strncmp(RAT_COMPONENT, actor->type, strlen(RAT_COMPONENT));
5115 }
5116
5117 /**
5118 * Console auto-completion for all components
5119 */
list_component(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5120 static switch_status_t list_component(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5121 {
5122 return list_actors(line, cursor, matches, is_component_actor);
5123 }
5124
5125 /**
5126 * @return true if a record component
5127 */
is_record_actor(struct rayo_actor * actor)5128 static switch_bool_t is_record_actor(struct rayo_actor *actor)
5129 {
5130 return is_component_actor(actor) && !strcmp(actor->subtype, "record");
5131 }
5132
5133 /**
5134 * Console auto-completion for all components
5135 */
list_record(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5136 static switch_status_t list_record(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5137 {
5138 return list_actors(line, cursor, matches, is_record_actor);
5139 }
5140
5141 /**
5142 * @return true if an output component
5143 */
is_output_actor(struct rayo_actor * actor)5144 static switch_bool_t is_output_actor(struct rayo_actor *actor)
5145 {
5146 return is_component_actor(actor) && !strcmp(actor->subtype, "output");
5147 }
5148
5149 /**
5150 * Console auto-completion for all components
5151 */
list_output(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5152 static switch_status_t list_output(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5153 {
5154 return list_actors(line, cursor, matches, is_output_actor);
5155 }
5156
5157 /**
5158 * @return true if an input component
5159 */
is_input_actor(struct rayo_actor * actor)5160 static switch_bool_t is_input_actor(struct rayo_actor *actor)
5161 {
5162 return is_component_actor(actor) && !strcmp(actor->subtype, "input");
5163 }
5164
5165 /**
5166 * Console auto-completion for all components
5167 */
list_input(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5168 static switch_status_t list_input(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5169 {
5170 return list_actors(line, cursor, matches, is_input_actor);
5171 }
5172
5173 /**
5174 * Shutdown module on load failure or shutdown from FreeSWITCH core
5175 */
do_shutdown(void)5176 static switch_status_t do_shutdown(void)
5177 {
5178 switch_console_del_complete_func("::rayo::list_all");
5179 switch_console_del_complete_func("::rayo::list_internal");
5180 switch_console_del_complete_func("::rayo::list_external");
5181 switch_console_del_complete_func("::rayo::list_server");
5182 switch_console_del_complete_func("::rayo::list_call");
5183 switch_console_del_complete_func("::rayo::list_component");
5184 switch_console_del_complete_func("::rayo::list_record");
5185 switch_console_del_complete_func("::rayo::list_output");
5186 switch_console_del_complete_func("::rayo::list_input");
5187 switch_console_set_complete("del rayo");
5188
5189 /* stop XMPP streams */
5190 if (globals.xmpp_context) {
5191 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for XMPP threads to stop\n");
5192 xmpp_stream_context_destroy(globals.xmpp_context);
5193 }
5194
5195 /* stop threads */
5196 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message and offer timeout threads to stop\n");
5197 stop_all_threads();
5198
5199 if (globals.console) {
5200 RAYO_RELEASE(globals.console);
5201 RAYO_DESTROY(globals.console);
5202 globals.console = NULL;
5203 }
5204
5205 if (globals.server) {
5206 RAYO_RELEASE(globals.server);
5207 RAYO_DESTROY(globals.server);
5208 globals.server = NULL;
5209 }
5210
5211 rayo_components_shutdown();
5212
5213 switch_event_unbind_callback(route_call_event);
5214 switch_event_unbind_callback(on_call_end_event);
5215 switch_event_unbind_callback(route_mixer_event);
5216
5217 if (globals.command_handlers) {
5218 switch_core_hash_destroy(&globals.command_handlers);
5219 }
5220 if (globals.event_handlers) {
5221 switch_core_hash_destroy(&globals.event_handlers);
5222 }
5223 if (globals.clients_roster) {
5224 switch_core_hash_destroy(&globals.clients_roster);
5225 }
5226 if (globals.actors) {
5227 switch_core_hash_destroy(&globals.actors);
5228 }
5229 if (globals.destroy_actors) {
5230 switch_core_hash_destroy(&globals.destroy_actors);
5231 }
5232 if (globals.actors_by_id) {
5233 switch_core_hash_destroy(&globals.actors_by_id);
5234 }
5235 if (globals.dial_gateways) {
5236 switch_core_hash_destroy(&globals.dial_gateways);
5237 }
5238 if (globals.cmd_aliases) {
5239 switch_core_hash_destroy(&globals.cmd_aliases);
5240 }
5241
5242
5243 return SWITCH_STATUS_SUCCESS;
5244 }
5245
5246 /**
5247 * Load module
5248 */
SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)5249 SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
5250 {
5251 switch_api_interface_t *api_interface;
5252 switch_application_interface_t *app_interface;
5253
5254
5255 if (switch_event_reserve_subclass("rayo::cpa") != SWITCH_STATUS_SUCCESS) {
5256 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", "rayo::cpa");
5257 return SWITCH_STATUS_TERM;
5258 }
5259
5260
5261 *module_interface = switch_loadable_module_create_module_interface(pool, modname);
5262
5263 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Loading module\n");
5264
5265 memset(&globals, 0, sizeof(globals));
5266 globals.pool = pool;
5267 switch_core_hash_init(&globals.command_handlers);
5268 switch_core_hash_init(&globals.event_handlers);
5269 switch_core_hash_init(&globals.clients_roster);
5270 switch_mutex_init(&globals.clients_mutex, SWITCH_MUTEX_NESTED, pool);
5271 switch_core_hash_init(&globals.actors);
5272 switch_core_hash_init(&globals.destroy_actors);
5273 switch_core_hash_init(&globals.actors_by_id);
5274 switch_mutex_init(&globals.actors_mutex, SWITCH_MUTEX_NESTED, pool);
5275 switch_core_hash_init(&globals.dial_gateways);
5276 switch_mutex_init(&globals.dial_gateways_mutex, SWITCH_MUTEX_NESTED, pool);
5277 switch_core_hash_init(&globals.cmd_aliases);
5278 switch_thread_rwlock_create(&globals.shutdown_rwlock, pool);
5279 switch_queue_create(&globals.msg_queue, 25000, pool);
5280 switch_queue_create(&globals.offer_queue, 25000, pool);
5281 globals.offline_logged = 1;
5282
5283 /* server commands */
5284 rayo_actor_command_handler_add(RAT_SERVER, "", "get:"IKS_NS_XMPP_PING":ping", on_iq_xmpp_ping);
5285 rayo_actor_command_handler_add(RAT_SERVER, "", "get:"IKS_NS_XMPP_DISCO":query", on_iq_get_xmpp_disco);
5286 rayo_actor_command_handler_add(RAT_SERVER, "", "set:"RAYO_NS":dial", on_rayo_dial);
5287 rayo_actor_command_handler_add(RAT_SERVER, "", "set:"RAYO_NS":exec", on_rayo_exec);
5288
5289 /* Rayo call commands */
5290 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":accept", on_rayo_accept);
5291 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":answer", on_rayo_answer);
5292 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":redirect", on_rayo_redirect);
5293 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":reject", on_rayo_hangup); /* handles both reject and hangup */
5294 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":hangup", on_rayo_hangup); /* handles both reject and hangup */
5295 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":join", on_rayo_join);
5296 rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_NS":unjoin", on_rayo_unjoin);
5297
5298 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_ORIGINATE, NULL, route_call_event, NULL);
5299 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA, NULL, route_call_event, NULL);
5300 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_PROGRESS, NULL, route_call_event, NULL);
5301 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_ANSWER, NULL, route_call_event, NULL);
5302 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_BRIDGE, NULL, route_call_event, NULL);
5303 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_PARK, NULL, route_call_event, NULL);
5304 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_EXECUTE, NULL, route_call_event, NULL);
5305 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE, NULL, route_call_event, NULL);
5306
5307 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_DESTROY, NULL, on_call_end_event, NULL);
5308
5309 switch_event_bind(modname, SWITCH_EVENT_CUSTOM, "conference::maintenance", route_mixer_event, NULL);
5310
5311 SWITCH_ADD_APP(app_interface, "rayo", "Offer call control to Rayo client(s)", "", rayo_app, RAYO_USAGE, SAF_SUPPORT_NOMEDIA);
5312 SWITCH_ADD_API(api_interface, "rayo", "Query rayo status", rayo_api, RAYO_API_SYNTAX);
5313
5314 /* set up rayo components */
5315 if (rayo_components_load(module_interface, pool, RAYO_CONFIG_FILE) != SWITCH_STATUS_SUCCESS) {
5316 goto error;
5317 }
5318
5319 /* configure / open sockets */
5320 if(do_config(globals.pool, RAYO_CONFIG_FILE) != SWITCH_STATUS_SUCCESS) {
5321 goto error;
5322 }
5323
5324 /* create admin client */
5325 globals.console = rayo_console_client_create();
5326 if (!globals.console) {
5327 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to create console client entity!\n");
5328 goto error;
5329 }
5330
5331 /* start up message threads */
5332 {
5333 int i;
5334 for (i = 0; i < globals.num_message_threads; i++) {
5335 start_deliver_message_thread(pool);
5336 }
5337 }
5338 start_offer_timeout_thread(pool);
5339
5340 switch_console_set_complete("add rayo status");
5341 switch_console_set_complete("add rayo msg ::rayo::list_all");
5342 switch_console_set_complete("add rayo msg ::rayo::list_all chat");
5343 switch_console_set_complete("add rayo msg ::rayo::list_all groupchat");
5344 switch_console_set_complete("add rayo msg ::rayo::list_all headline");
5345 switch_console_set_complete("add rayo msg ::rayo::list_all normal");
5346 switch_console_set_complete("add rayo presence ::rayo::list_server online");
5347 switch_console_set_complete("add rayo presence ::rayo::list_server offline");
5348 switch_console_add_complete_func("::rayo::list_all", list_all);
5349 switch_console_add_complete_func("::rayo::list_internal", list_internal);
5350 switch_console_add_complete_func("::rayo::list_external", list_external);
5351 switch_console_add_complete_func("::rayo::list_server", list_server);
5352 switch_console_add_complete_func("::rayo::list_call", list_call);
5353 switch_console_add_complete_func("::rayo::list_component", list_component);
5354 switch_console_add_complete_func("::rayo::list_record", list_record);
5355 switch_console_add_complete_func("::rayo::list_output", list_output);
5356 switch_console_add_complete_func("::rayo::list_input", list_input);
5357
5358 return SWITCH_STATUS_SUCCESS;
5359
5360 error:
5361 switch_event_free_subclass("rayo::cpa");
5362 do_shutdown();
5363 return SWITCH_STATUS_TERM;
5364
5365 }
5366
5367 /**
5368 * Shutdown module. Notifies threads to stop.
5369 */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown)5370 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown)
5371 {
5372 switch_status_t result;
5373
5374 switch_event_free_subclass("rayo::cpa");
5375 result = do_shutdown();
5376 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Module shutdown\n");
5377 return result;
5378 }
5379
5380 /**
5381 * Checks status of connected clients
5382 */
SWITCH_MODULE_RUNTIME_FUNCTION(mod_rayo_runtime)5383 SWITCH_MODULE_RUNTIME_FUNCTION(mod_rayo_runtime)
5384 {
5385 if (globals.pause_when_offline) {
5386 switch_thread_rwlock_rdlock(globals.shutdown_rwlock);
5387 while (!globals.shutdown) {
5388 switch_sleep(1000 * 1000); /* 1 second */
5389 pause_when_offline();
5390 }
5391 switch_thread_rwlock_unlock(globals.shutdown_rwlock);
5392 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Runtime thread is done\n");
5393 }
5394 return SWITCH_STATUS_TERM;
5395 }
5396
5397 /* For Emacs:
5398 * Local Variables:
5399 * mode:c
5400 * indent-tabs-mode:t
5401 * tab-width:4
5402 * c-basic-offset:4
5403 * End:
5404 * For VIM:
5405 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
5406 */
5407