Wed Jan 8 2020 09:49:43

Asterisk developer's documentation


chan_gtalk.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Matt O'Gorman <mogorman@digium.com>
7  * Philippe Sultan <philippe.sultan@gmail.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*! \file
21  *
22  * \author Matt O'Gorman <mogorman@digium.com>
23  * \author Philippe Sultan <philippe.sultan@gmail.com>
24  *
25  * \brief Gtalk Channel Driver, until google/libjingle works with jingle spec
26  *
27  * \ingroup channel_drivers
28  *
29  * ********** General TODO:s
30  * \todo Support config reloading.
31  * \todo Fix native bridging.
32  */
33 
34 /*** MODULEINFO
35  <depend>iksemel</depend>
36  <depend>res_jabber</depend>
37  <use>openssl</use>
38  <support_level>extended</support_level>
39  ***/
40 
41 
42 #include "asterisk.h"
43 
44 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
45 
46 #include <sys/socket.h>
47 #include <fcntl.h>
48 #include <netdb.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <sys/signal.h>
52 #include <iksemel.h>
53 #include <pthread.h>
54 #include <ctype.h>
55 
56 #include "asterisk/lock.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/config.h"
59 #include "asterisk/module.h"
60 #include "asterisk/pbx.h"
61 #include "asterisk/sched.h"
62 #include "asterisk/io.h"
63 #include "asterisk/rtp_engine.h"
64 #include "asterisk/stun.h"
65 #include "asterisk/acl.h"
66 #include "asterisk/callerid.h"
67 #include "asterisk/file.h"
68 #include "asterisk/cli.h"
69 #include "asterisk/app.h"
70 #include "asterisk/musiconhold.h"
71 #include "asterisk/manager.h"
72 #include "asterisk/stringfields.h"
73 #include "asterisk/utils.h"
74 #include "asterisk/causes.h"
75 #include "asterisk/astobj.h"
76 #include "asterisk/abstract_jb.h"
77 #include "asterisk/jabber.h"
78 #include "asterisk/jingle.h"
79 
80 #define GOOGLE_CONFIG "gtalk.conf"
81 
82 /*! Global jitterbuffer configuration - by default, jb is disabled */
83 static struct ast_jb_conf default_jbconf =
84 {
85  .flags = 0,
86  .max_size = -1,
87  .resync_threshold = -1,
88  .impl = "",
89  .target_extra = -1,
90 };
91 static struct ast_jb_conf global_jbconf;
92 
96 };
97 
102 };
103 
104 struct gtalk_pvt {
105  ast_mutex_t lock; /*!< Channel private lock */
106  time_t laststun;
107  struct gtalk *parent; /*!< Parent client */
108  char sid[100];
111  char ring[10]; /*!< Message ID of ring */
112  iksrule *ringrule; /*!< Rule for matching RING request */
113  int initiator; /*!< If we're the initiator */
119  char cid_num[80]; /*!< Caller ID num */
120  char cid_name[80]; /*!< Caller ID name */
121  char exten[80]; /*!< Called extension */
122  struct ast_channel *owner; /*!< Master Channel */
123  struct ast_rtp_instance *rtp; /*!< RTP audio session */
124  struct ast_rtp_instance *vrtp; /*!< RTP video session */
125  format_t jointcapability; /*!< Supported capability at both ends (codecs ) */
127  struct gtalk_pvt *next; /* Next entity */
128 };
129 
131  char name[100];
133  double preference;
134  char username[100];
135  char password[100];
137  char network[6];
139  char ip[16];
140  int port;
141  int receipt;
143 };
144 
145 struct gtalk {
148  struct aji_buddy *buddy;
149  struct gtalk_pvt *p;
151  int amaflags; /*!< AMA Flags */
154  char parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */
155  char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
157  ast_group_t callgroup; /*!< Call group */
158  ast_group_t pickupgroup; /*!< Pickup group */
159  int callingpres; /*!< Calling presentation */
161  char language[MAX_LANGUAGE]; /*!< Default language for prompts */
162  char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */
163 };
164 
167 };
168 
169 static const char desc[] = "Gtalk Channel";
170 
172 
173 AST_MUTEX_DEFINE_STATIC(gtalklock); /*!< Protect the interface list (of gtalk_pvt's) */
174 
175 /* Forward declarations */
176 static struct ast_channel *gtalk_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
177 /*static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);*/
178 static int gtalk_sendtext(struct ast_channel *ast, const char *text);
179 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
180 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
181 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
182 static int gtalk_hangup(struct ast_channel *ast);
183 static int gtalk_answer(struct ast_channel *ast);
184 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action);
185 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p);
186 static int gtalk_newcall(struct gtalk *client, ikspak *pak);
187 static struct ast_frame *gtalk_read(struct ast_channel *ast);
188 static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
189 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
190 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
191 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
192 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
193 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p);
194 /* static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); */
195 static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
196 static int gtalk_update_externip(void);
197 static int gtalk_parser(void *data, ikspak *pak);
198 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to);
199 
200 /*! \brief PBX interface structure for channel registration */
201 static const struct ast_channel_tech gtalk_tech = {
202  .type = "Gtalk",
203  .description = "Gtalk Channel Driver",
204  .capabilities = AST_FORMAT_AUDIO_MASK,
205  .requester = gtalk_request,
206  .send_text = gtalk_sendtext,
207  .send_digit_begin = gtalk_digit_begin,
208  .send_digit_end = gtalk_digit_end,
209  /* XXX TODO native bridging is causing odd problems with DTMF pass-through with
210  * the gtalk servers. Enable native bridging once the source of this problem has
211  * been identified.
212  .bridge = ast_rtp_instance_bridge, */
213  .call = gtalk_call,
214  .hangup = gtalk_hangup,
215  .answer = gtalk_answer,
216  .read = gtalk_read,
217  .write = gtalk_write,
218  .exception = gtalk_read,
219  .indicate = gtalk_indicate,
220  .fixup = gtalk_fixup,
221  .send_html = gtalk_sendhtml,
223 };
224 
225 static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */
226 
227 static struct sched_context *sched; /*!< The scheduling context */
228 static struct io_context *io; /*!< The IO context */
229 static struct in_addr __ourip;
230 
231 static struct ast_cli_entry gtalk_cli[] = {
232 /* AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"), XXX TODO reloads are not possible yet. */
233  AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
234 };
235 
236 static char externip[16];
237 static struct sockaddr_in stunaddr; /*!< the stun server we get the externip from */
238 
240 
241 static void gtalk_member_destroy(struct gtalk *obj)
242 {
243  ast_free(obj);
244 }
245 
246 static struct gtalk *find_gtalk(char *name, char *connection)
247 {
248  struct gtalk *gtalk = NULL;
249  char *domain = NULL , *s = NULL;
250 
251  if (strchr(connection, '@')) {
252  s = ast_strdupa(connection);
253  domain = strsep(&s, "@");
254  ast_verbose("OOOOH domain = %s\n", domain);
255  }
256  gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
257  if (!gtalk && strchr(name, '@'))
258  gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);
259 
260  if (!gtalk) {
261  /* guest call */
263  ASTOBJ_RDLOCK(iterator);
264  if (!strcasecmp(iterator->name, "guest")) {
265  gtalk = iterator;
266  }
267  ASTOBJ_UNLOCK(iterator);
268 
269  if (gtalk)
270  break;
271  });
272 
273  }
274  return gtalk;
275 }
276 
277 
278 static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs)
279 {
280  int res = 0;
281  char *format = ast_getformatname(codec);
282 
283  if (!strcasecmp("ulaw", format)) {
284  iks *payload_eg711u, *payload_pcmu;
285  payload_pcmu = iks_new("payload-type");
286  payload_eg711u = iks_new("payload-type");
287 
288  if(!payload_eg711u || !payload_pcmu) {
289  iks_delete(payload_pcmu);
290  iks_delete(payload_eg711u);
291  ast_log(LOG_WARNING,"Failed to allocate iks node\n");
292  return -1;
293  }
294  iks_insert_attrib(payload_pcmu, "id", "0");
295  iks_insert_attrib(payload_pcmu, "name", "PCMU");
296  iks_insert_attrib(payload_pcmu, "clockrate","8000");
297  iks_insert_attrib(payload_pcmu, "bitrate","64000");
298  iks_insert_attrib(payload_eg711u, "id", "100");
299  iks_insert_attrib(payload_eg711u, "name", "EG711U");
300  iks_insert_attrib(payload_eg711u, "clockrate","8000");
301  iks_insert_attrib(payload_eg711u, "bitrate","64000");
302  iks_insert_node(dcodecs, payload_pcmu);
303  iks_insert_node(dcodecs, payload_eg711u);
304  res ++;
305  }
306  if (!strcasecmp("alaw", format)) {
307  iks *payload_eg711a, *payload_pcma;
308  payload_pcma = iks_new("payload-type");
309  payload_eg711a = iks_new("payload-type");
310  if(!payload_eg711a || !payload_pcma) {
311  iks_delete(payload_eg711a);
312  iks_delete(payload_pcma);
313  ast_log(LOG_WARNING,"Failed to allocate iks node\n");
314  return -1;
315  }
316  iks_insert_attrib(payload_pcma, "id", "8");
317  iks_insert_attrib(payload_pcma, "name", "PCMA");
318  iks_insert_attrib(payload_pcma, "clockrate","8000");
319  iks_insert_attrib(payload_pcma, "bitrate","64000");
320  payload_eg711a = iks_new("payload-type");
321  iks_insert_attrib(payload_eg711a, "id", "101");
322  iks_insert_attrib(payload_eg711a, "name", "EG711A");
323  iks_insert_attrib(payload_eg711a, "clockrate","8000");
324  iks_insert_attrib(payload_eg711a, "bitrate","64000");
325  iks_insert_node(dcodecs, payload_pcma);
326  iks_insert_node(dcodecs, payload_eg711a);
327  res ++;
328  }
329  if (!strcasecmp("ilbc", format)) {
330  iks *payload_ilbc = iks_new("payload-type");
331  if(!payload_ilbc) {
332  ast_log(LOG_WARNING,"Failed to allocate iks node\n");
333  return -1;
334  }
335  iks_insert_attrib(payload_ilbc, "id", "97");
336  iks_insert_attrib(payload_ilbc, "name", "iLBC");
337  iks_insert_attrib(payload_ilbc, "clockrate","8000");
338  iks_insert_attrib(payload_ilbc, "bitrate","13300");
339  iks_insert_node(dcodecs, payload_ilbc);
340  res ++;
341  }
342  if (!strcasecmp("g723", format)) {
343  iks *payload_g723 = iks_new("payload-type");
344  if(!payload_g723) {
345  ast_log(LOG_WARNING,"Failed to allocate iks node\n");
346  return -1;
347  }
348  iks_insert_attrib(payload_g723, "id", "4");
349  iks_insert_attrib(payload_g723, "name", "G723");
350  iks_insert_attrib(payload_g723, "clockrate","8000");
351  iks_insert_attrib(payload_g723, "bitrate","6300");
352  iks_insert_node(dcodecs, payload_g723);
353  res ++;
354  }
355  if (!strcasecmp("speex", format)) {
356  iks *payload_speex = iks_new("payload-type");
357  if(!payload_speex) {
358  ast_log(LOG_WARNING,"Failed to allocate iks node\n");
359  return -1;
360  }
361  iks_insert_attrib(payload_speex, "id", "110");
362  iks_insert_attrib(payload_speex, "name", "speex");
363  iks_insert_attrib(payload_speex, "clockrate","8000");
364  iks_insert_attrib(payload_speex, "bitrate","11000");
365  iks_insert_node(dcodecs, payload_speex);
366  res++;
367  }
368  if (!strcasecmp("gsm", format)) {
369  iks *payload_gsm = iks_new("payload-type");
370  if(!payload_gsm) {
371  ast_log(LOG_WARNING,"Failed to allocate iks node\n");
372  return -1;
373  }
374  iks_insert_attrib(payload_gsm, "id", "103");
375  iks_insert_attrib(payload_gsm, "name", "gsm");
376  iks_insert_node(dcodecs, payload_gsm);
377  res++;
378  }
379 
380  return res;
381 }
382 
383 static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
384 {
385  struct gtalk *client = p->parent;
386  iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
387  int x;
388  int pref_codec = 0;
389  int alreadysent = 0;
390  int codecs_num = 0;
391  char *lowerto = NULL;
392 
393  iq = iks_new("iq");
394  gtalk = iks_new("session");
395  dcodecs = iks_new("description");
396  transport = iks_new("transport");
397  payload_telephone = iks_new("payload-type");
398  if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
399  iks_delete(iq);
400  iks_delete(gtalk);
401  iks_delete(dcodecs);
402  iks_delete(transport);
403  iks_delete(payload_telephone);
404 
405  ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
406  return 0;
407  }
408  iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
409  iks_insert_attrib(dcodecs, "xml:lang", "en");
410 
411  for (x = 0; x < 64; x++) {
412  if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
413  break;
414  if (!(client->capability & pref_codec))
415  continue;
416  if (alreadysent & pref_codec)
417  continue;
418  codecs_num = add_codec_to_answer(p, pref_codec, dcodecs);
419  alreadysent |= pref_codec;
420  }
421 
422  if (codecs_num) {
423  /* only propose DTMF within an audio session */
424  iks_insert_attrib(payload_telephone, "id", "101");
425  iks_insert_attrib(payload_telephone, "name", "telephone-event");
426  iks_insert_attrib(payload_telephone, "clockrate", "8000");
427  }
428  iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
429 
430  iks_insert_attrib(iq, "type", "set");
431  iks_insert_attrib(iq, "to", to);
432  iks_insert_attrib(iq, "from", from);
433  iks_insert_attrib(iq, "id", client->connection->mid);
435 
436  iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
437  iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
438  /* put the initiator attribute to lower case if we receive the call
439  * otherwise GoogleTalk won't establish the session */
440  if (!initiator) {
441  char c;
442  char *t = lowerto = ast_strdupa(to);
443  while (((c = *t) != '/') && (*t++ = tolower(c)));
444  }
445  iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
446  iks_insert_attrib(gtalk, "id", sid);
447  iks_insert_node(iq, gtalk);
448  iks_insert_node(gtalk, dcodecs);
449  iks_insert_node(dcodecs, payload_telephone);
450 
451  ast_aji_send(client->connection, iq);
452 
453  iks_delete(payload_telephone);
454  iks_delete(transport);
455  iks_delete(dcodecs);
456  iks_delete(gtalk);
457  iks_delete(iq);
458  return 1;
459 }
460 
461 static int gtalk_ringing_ack(void *data, ikspak *pak)
462 {
463  struct gtalk_pvt *p = data;
464  struct ast_channel *owner;
465 
466  ast_mutex_lock(&p->lock);
467 
468  if (p->ringrule) {
469  iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
470  }
471  p->ringrule = NULL;
472 
473  /* this may be a redirect */
474  if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
475  char *name = NULL;
476  char *redirect = NULL;
477  iks *traversenodes = NULL;
478  traversenodes = pak->query;
479  while (traversenodes) {
480  if (!(name = iks_name(traversenodes))) {
481  break;
482  }
483  if (!strcasecmp(name, "error") &&
484  ((redirect = iks_find_cdata(traversenodes, "redirect")) ||
485  (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
486  (redirect = strstr(redirect, "xmpp:"))) {
487  redirect += 5;
488  ast_log(LOG_DEBUG, "redirect %s\n", redirect);
489  ast_copy_string(p->them, redirect, sizeof(p->them));
490 
491  gtalk_invite(p, p->them, p->us, p->sid, 1);
492  break;
493  }
494  traversenodes = iks_next_tag(traversenodes);
495  }
496  }
497  gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
498  owner = p->owner;
499  ast_mutex_unlock(&p->lock);
500 
501  if (owner) {
503  }
504 
505  return IKS_FILTER_EAT;
506 }
507 
508 static int gtalk_answer(struct ast_channel *ast)
509 {
510  struct gtalk_pvt *p = ast->tech_pvt;
511  int res = 0;
512 
513  ast_debug(1, "Answer!\n");
514  ast_mutex_lock(&p->lock);
515  gtalk_invite(p, p->them, p->us,p->sid, 0);
516  manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
517  ast->name, "GTALK", p->sid);
518  ast_mutex_unlock(&p->lock);
519  return res;
520 }
521 
522 static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
523 {
524  struct gtalk_pvt *p = chan->tech_pvt;
526 
527  if (!p)
528  return res;
529 
530  ast_mutex_lock(&p->lock);
531  if (p->rtp){
532  ao2_ref(p->rtp, +1);
533  *instance = p->rtp;
535  }
536  ast_mutex_unlock(&p->lock);
537 
538  return res;
539 }
540 
542 {
543  struct gtalk_pvt *p = chan->tech_pvt;
544  return p->peercapability;
545 }
546 
547 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, format_t codecs, int nat_active)
548 {
549  struct gtalk_pvt *p;
550 
551  p = chan->tech_pvt;
552  if (!p)
553  return -1;
554  ast_mutex_lock(&p->lock);
555 
556 /* if (rtp)
557  ast_rtp_get_peer(rtp, &p->redirip);
558  else
559  memset(&p->redirip, 0, sizeof(p->redirip));
560  p->redircodecs = codecs; */
561 
562  /* Reset lastrtprx timer */
563  ast_mutex_unlock(&p->lock);
564  return 0;
565 }
566 
567 static struct ast_rtp_glue gtalk_rtp_glue = {
568  .type = "Gtalk",
569  .get_rtp_info = gtalk_get_rtp_peer,
570  .get_codec = gtalk_get_codec,
571  .update_peer = gtalk_set_rtp_peer,
572 };
573 
574 static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
575 {
576  iks *response = NULL, *error = NULL, *reason = NULL;
577  int res = -1;
578 
579  response = iks_new("iq");
580  if (response) {
581  iks_insert_attrib(response, "type", "result");
582  iks_insert_attrib(response, "from", from);
583  iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
584  iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
585  if (reasonstr) {
586  error = iks_new("error");
587  if (error) {
588  iks_insert_attrib(error, "type", "cancel");
589  reason = iks_new(reasonstr);
590  if (reason)
591  iks_insert_node(error, reason);
592  iks_insert_node(response, error);
593  }
594  }
595  ast_aji_send(client->connection, response);
596  res = 0;
597  }
598 
599  iks_delete(reason);
600  iks_delete(error);
601  iks_delete(response);
602 
603  return res;
604 }
605 
606 static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
607 {
608  struct gtalk_pvt *tmp = NULL;
609  char *from;
610  iks *codec;
611  char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
612  int peernoncodeccapability;
613 
614  ast_log(LOG_DEBUG, "The client is %s\n", client->name);
615 
616  /* Make sure our new call does exist */
617  for (tmp = client->p; tmp; tmp = tmp->next) {
618  if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
619  break;
620  } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
621  break;
622  }
623  }
624 
625  if (!tmp) {
626  ast_log(LOG_WARNING, "Could not find session in iq\n");
627  return -1;
628  }
629 
630  /* codec points to the first <payload-type/> tag */
631  codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
632  while (codec) {
633  char *codec_id = iks_find_attrib(codec, "id");
634  char *codec_name = iks_find_attrib(codec, "name");
635  if (!codec_id || !codec_name) {
636  codec = iks_next_tag(codec);
637  continue;
638  }
639 
642  tmp->rtp,
643  atoi(codec_id));
646  tmp->rtp,
647  atoi(codec_id),
648  "audio",
649  codec_name,
650  0);
651  codec = iks_next_tag(codec);
652  }
653 
654  /* Now gather all of the codecs that we are asked for */
655  ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), &tmp->peercapability, &peernoncodeccapability);
656 
657  /* at this point, we received an awser from the remote Gtalk client,
658  which allows us to compare capabilities */
659  tmp->jointcapability = tmp->capability & tmp->peercapability;
660  if (!tmp->jointcapability) {
661  ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
662  ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
663  ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
664  /* close session if capabilities don't match */
665  ast_queue_hangup(tmp->owner);
666 
667  return -1;
668 
669  }
670 
671  from = iks_find_attrib(pak->x, "to");
672  if (!from) {
673  from = client->connection->jid->full;
674  }
675 
676  if (tmp->owner) {
678  }
679  gtalk_update_stun(tmp->parent, tmp);
680  gtalk_response(client, from, pak, NULL, NULL);
681  return 1;
682 }
683 
684 static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
685 {
686  struct gtalk_pvt *tmp;
687  char *from;
688 
689  ast_log(LOG_DEBUG, "The client is %s\n", client->name);
690  /* find corresponding call */
691  for (tmp = client->p; tmp; tmp = tmp->next) {
692  if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
693  break;
694  }
695  }
696 
697  from = iks_find_attrib(pak->x, "to");
698  if (!from) {
699  from = client->connection->jid->full;
700  }
701 
702  if (tmp) {
703  gtalk_update_stun(tmp->parent, tmp);
704  } else {
705  ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
706  }
707 
708  /* answer 'iq' packet to let the remote peer know that we're alive */
709  gtalk_response(client, from, pak, NULL, NULL);
710  return 1;
711 }
712 
713 static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
714 {
715  struct gtalk_pvt *tmp;
716  iks *dtmfnode = NULL, *dtmfchild = NULL;
717  char *dtmf;
718  char *from;
719  /* Make sure our new call doesn't exist yet */
720  for (tmp = client->p; tmp; tmp = tmp->next) {
721  if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
722  break;
723  }
724  from = iks_find_attrib(pak->x, "to");
725  if (!from) {
726  from = client->connection->jid->full;
727  }
728 
729  if (tmp) {
730  if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
731  gtalk_response(client, from, pak,
732  "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
733  "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
734  return -1;
735  }
736  if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
737  if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
738  if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
739  struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
740  f.subclass.integer = dtmf[0];
741  ast_queue_frame(tmp->owner, &f);
742  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
743  } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
744  struct ast_frame f = {AST_FRAME_DTMF_END, };
745  f.subclass.integer = dtmf[0];
746  ast_queue_frame(tmp->owner, &f);
747  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
748  } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
749  struct ast_frame f = {AST_FRAME_DTMF, };
750  f.subclass.integer = dtmf[0];
751  ast_queue_frame(tmp->owner, &f);
752  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
753  }
754  }
755  } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
756  if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
757  if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
758  if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
759  struct ast_frame f = {AST_FRAME_DTMF_END, };
760  f.subclass.integer = dtmf[0];
761  ast_queue_frame(tmp->owner, &f);
762  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
763  } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
764  struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
765  f.subclass.integer = dtmf[0];
766  ast_queue_frame(tmp->owner, &f);
767  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
768  }
769  }
770  }
771  }
772  gtalk_response(client, from, pak, NULL, NULL);
773  return 1;
774  } else {
775  ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
776  }
777 
778  gtalk_response(client, from, pak, NULL, NULL);
779  return 1;
780 }
781 
782 static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
783 {
784  struct gtalk_pvt *tmp;
785  char *from;
786 
787  ast_debug(1, "The client is %s\n", client->name);
788  /* Make sure our new call doesn't exist yet */
789  for (tmp = client->p; tmp; tmp = tmp->next) {
790  if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
791  (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
792  break;
793  }
794  }
795  from = iks_find_attrib(pak->x, "to");
796  if (!from) {
797  from = client->connection->jid->full;
798  }
799 
800  if (tmp) {
801  tmp->alreadygone = 1;
802  if (tmp->owner) {
803  ast_queue_hangup(tmp->owner);
804  }
805  } else {
806  ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
807  }
808  gtalk_response(client, from, pak, NULL, NULL);
809  return 1;
810 }
811 
812 static int gtalk_get_local_ip(struct ast_sockaddr *ourip)
813 {
814  struct ast_sockaddr root;
815  struct ast_sockaddr bindaddr_tmp;
816  struct ast_sockaddr *addrs;
817  int addrs_cnt;
818 
819  /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
820  ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
821  if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
822  ast_sockaddr_copy(ourip, &bindaddr_tmp);
823  return 0;
824  }
825 
826  /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
827  * If you can't resolve google.com from your network, then this module is useless for you anyway. */
828  if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) {
829  ast_sockaddr_copy(&root, &addrs[0]);
830  ast_free(addrs);
831  if (!ast_ouraddrfor(&root, ourip)) {
832  return 0;
833  }
834  }
835 
836  /* As a last resort, use this function to find our local address. */
837  return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
838 }
839 
840 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
841 {
842  struct gtalk_candidate *tmp;
843  struct aji_client *c = client->connection;
844  struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
845  struct sockaddr_in sin = { 0, };
846  struct ast_sockaddr sin_tmp;
847  struct ast_sockaddr us;
848  iks *iq, *gtalk, *candidate, *transport;
849  char user[17], pass[17], preference[5], port[7];
850  char *lowerfrom = NULL;
851 
852  iq = iks_new("iq");
853  gtalk = iks_new("session");
854  candidate = iks_new("candidate");
855  transport = iks_new("transport");
856  if (!iq || !gtalk || !candidate || !transport) {
857  ast_log(LOG_ERROR, "Memory allocation error\n");
858  goto safeout;
859  }
860  ours1 = ast_calloc(1, sizeof(*ours1));
861  ours2 = ast_calloc(1, sizeof(*ours2));
862  if (!ours1 || !ours2)
863  goto safeout;
864 
865  iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
866  iks_insert_node(iq, gtalk);
867  iks_insert_node(gtalk,candidate);
868  iks_insert_node(gtalk,transport);
869 
870  for (; p; p = p->next) {
871  if (!strcasecmp(p->sid, sid))
872  break;
873  }
874 
875  if (!p) {
876  ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
877  goto safeout;
878  }
879 
881  ast_sockaddr_to_sin(&sin_tmp, &sin);
882 
883  gtalk_get_local_ip(&us);
884 
885  if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
886  ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.\n");
887  }
888 
889  /* Setup our gtalk candidates */
890  ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
891  ours1->port = ntohs(sin.sin_port);
892  ours1->preference = 1;
893  snprintf(user, sizeof(user), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
894  snprintf(pass, sizeof(pass), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
895  ast_copy_string(ours1->username, user, sizeof(ours1->username));
896  ast_copy_string(ours1->password, pass, sizeof(ours1->password));
898  sizeof(ours1->ip));
899  ours1->protocol = AJI_PROTOCOL_UDP;
900  ours1->type = AJI_CONNECT_LOCAL;
901  ours1->generation = 0;
902  p->ourcandidates = ours1;
903 
904  /* XXX this is a blocking action. We send a STUN request to the server
905  * and wait for the response. If blocking here is a problem the STUN requests/responses
906  * for the externip may need to be done differently. */
908  if (!ast_strlen_zero(externip)) {
909  ast_copy_string(ours2->username, user, sizeof(ours2->username));
910  ast_copy_string(ours2->password, pass, sizeof(ours2->password));
911  ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
912  ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
913  ours2->port = ntohs(sin.sin_port);
914  ours2->preference = 0.9;
915  ours2->protocol = AJI_PROTOCOL_UDP;
916  ours2->type = AJI_CONNECT_STUN;
917  ours2->generation = 0;
918  ours1->next = ours2;
919  ours2 = NULL;
920  }
921  ours1 = NULL;
922 
923  for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
924  snprintf(port, sizeof(port), "%d", tmp->port);
925  snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
926  iks_insert_attrib(iq, "from", to);
927  iks_insert_attrib(iq, "to", from);
928  iks_insert_attrib(iq, "type", "set");
929  iks_insert_attrib(iq, "id", c->mid);
931  iks_insert_attrib(gtalk, "type", "candidates");
932  iks_insert_attrib(gtalk, "id", sid);
933  /* put the initiator attribute to lower case if we receive the call
934  * otherwise GoogleTalk won't establish the session */
935  if (!p->initiator) {
936  char c;
937  char *t = lowerfrom = ast_strdupa(from);
938  while (((c = *t) != '/') && (*t++ = tolower(c)));
939  }
940  iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
941  iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
942  iks_insert_attrib(candidate, "name", tmp->name);
943  iks_insert_attrib(candidate, "address", tmp->ip);
944  iks_insert_attrib(candidate, "port", port);
945  iks_insert_attrib(candidate, "username", tmp->username);
946  iks_insert_attrib(candidate, "password", tmp->password);
947  iks_insert_attrib(candidate, "preference", preference);
948  if (tmp->protocol == AJI_PROTOCOL_UDP)
949  iks_insert_attrib(candidate, "protocol", "udp");
950  if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
951  iks_insert_attrib(candidate, "protocol", "ssltcp");
952  if (tmp->type == AJI_CONNECT_STUN)
953  iks_insert_attrib(candidate, "type", "stun");
954  if (tmp->type == AJI_CONNECT_LOCAL)
955  iks_insert_attrib(candidate, "type", "local");
956  if (tmp->type == AJI_CONNECT_RELAY)
957  iks_insert_attrib(candidate, "type", "relay");
958  iks_insert_attrib(candidate, "network", "0");
959  iks_insert_attrib(candidate, "generation", "0");
960  ast_aji_send(c, iq);
961  }
962  p->laststun = 0;
963 
964 safeout:
965  if (ours1)
966  ast_free(ours1);
967  if (ours2)
968  ast_free(ours2);
969  iks_delete(iq);
970  iks_delete(gtalk);
971  iks_delete(candidate);
972  iks_delete(transport);
973 
974  return 1;
975 }
976 
977 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
978 {
979  struct gtalk_pvt *tmp = NULL;
980  struct aji_resource *resources = NULL;
981  struct aji_buddy *buddy = NULL;
982  char idroster[200] = "";
983  char *data, *exten = NULL;
984  struct ast_sockaddr bindaddr_tmp;
985 
986  ast_debug(1, "The client is %s for alloc\n", client->name);
987  if (!sid && !strchr(them, '/')) { /* I started call! */
988  if (!strcasecmp(client->name, "guest")) {
989  buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
990  if (buddy) {
991  resources = buddy->resources;
992  }
993  } else if (client->buddy) {
994  resources = client->buddy->resources;
995  }
996 
997  while (resources) {
998  if (resources->cap->jingle) {
999  break;
1000  }
1001  resources = resources->next;
1002  }
1003  if (resources) {
1004  snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
1005  } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
1006  snprintf(idroster, sizeof(idroster), "%s", them);
1007  } else {
1008  ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
1009  if (buddy) {
1011  }
1012  return NULL;
1013  }
1014  if (buddy) {
1016  }
1017  }
1018  if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
1019  return NULL;
1020  }
1021 
1022  memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
1023 
1024  if (sid) {
1025  ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
1026  ast_copy_string(tmp->them, them, sizeof(tmp->them));
1027  ast_copy_string(tmp->us, us, sizeof(tmp->us));
1028  } else {
1029  snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", (long unsigned)ast_random(), (long unsigned)ast_random());
1030  ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
1031  ast_copy_string(tmp->us, us, sizeof(tmp->us));
1032  tmp->initiator = 1;
1033  }
1034  /* clear codecs */
1035  bindaddr.sin_family = AF_INET;
1036  ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
1037  if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
1038  ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
1039  ast_free(tmp);
1040  return NULL;
1041  }
1047 
1048  /* add user configured codec capabilites */
1049  if (client->capability) {
1050  tmp->capability = client->capability;
1051  } else if (global_capability) {
1053  }
1054 
1055  tmp->parent = client;
1056  if (!tmp->rtp) {
1057  ast_log(LOG_WARNING, "Out of RTP sessions?\n");
1058  ast_free(tmp);
1059  return NULL;
1060  }
1061 
1062  /* Set CALLERID(name) to the full JID of the remote peer */
1063  ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
1064 
1065  if(strchr(tmp->us, '/')) {
1066  data = ast_strdupa(tmp->us);
1067  exten = strsep(&data, "/");
1068  } else {
1069  exten = tmp->us;
1070  }
1071  ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
1072  ast_mutex_init(&tmp->lock);
1074  tmp->next = client->p;
1075  client->p = tmp;
1077  return tmp;
1078 }
1079 
1080 /*! \brief Start new gtalk channel */
1081 static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const char *linkedid)
1082 {
1083  struct ast_channel *tmp;
1084  int fmt;
1085  int what;
1086  const char *n2;
1087 
1088  if (title)
1089  n2 = title;
1090  else
1091  n2 = i->us;
1092  tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid,
1093  client->accountcode, i->exten, client->context, client->amaflags,
1094  "Gtalk/%s-%04lx", n2, (long unsigned)(ast_random() & 0xffff));
1095  if (!tmp) {
1096  ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
1097  return NULL;
1098  }
1099  tmp->tech = &gtalk_tech;
1100 
1101  /* Select our native format based on codec preference until we receive
1102  something from another device to the contrary. */
1103  if (i->jointcapability)
1104  what = i->jointcapability;
1105  else if (i->capability)
1106  what = i->capability;
1107  else
1108  what = global_capability;
1109 
1110  /* Set Frame packetization */
1111  if (i->rtp) {
1113  }
1114 
1116  fmt = ast_best_codec(tmp->nativeformats);
1117 
1118  if (i->rtp) {
1119  ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
1120  ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
1121  }
1122  if (i->vrtp) {
1125  }
1126  if (state == AST_STATE_RING)
1127  tmp->rings = 1;
1129  tmp->writeformat = fmt;
1130  tmp->rawwriteformat = fmt;
1131  tmp->readformat = fmt;
1132  tmp->rawreadformat = fmt;
1133  tmp->tech_pvt = i;
1134 
1135  tmp->callgroup = client->callgroup;
1136  tmp->pickupgroup = client->pickupgroup;
1137  tmp->caller.id.name.presentation = client->callingpres;
1138  tmp->caller.id.number.presentation = client->callingpres;
1139  if (!ast_strlen_zero(client->accountcode))
1141  if (client->amaflags)
1142  tmp->amaflags = client->amaflags;
1143  if (!ast_strlen_zero(client->language))
1144  ast_string_field_set(tmp, language, client->language);
1145  if (!ast_strlen_zero(client->musicclass))
1147  if (!ast_strlen_zero(client->parkinglot))
1149  i->owner = tmp;
1151  ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
1152  ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
1153 
1154  if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
1155  tmp->dialed.number.str = ast_strdup(i->exten);
1156  }
1157  tmp->priority = 1;
1158  if (i->rtp)
1160  if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
1161  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
1163  ast_hangup(tmp);
1164  tmp = NULL;
1165  } else {
1166  manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
1167  "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
1168  i->owner ? i->owner->name : "", "Gtalk", i->sid);
1169  }
1170  return tmp;
1171 }
1172 
1173 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
1174 {
1175  iks *request, *session = NULL;
1176  int res = -1;
1177  char *lowerthem = NULL;
1178 
1179  request = iks_new("iq");
1180  if (request) {
1181  iks_insert_attrib(request, "type", "set");
1182  iks_insert_attrib(request, "from", p->us);
1183  iks_insert_attrib(request, "to", p->them);
1184  iks_insert_attrib(request, "id", client->connection->mid);
1186  session = iks_new("session");
1187  if (session) {
1188  iks_insert_attrib(session, "type", action);
1189  iks_insert_attrib(session, "id", p->sid);
1190  /* put the initiator attribute to lower case if we receive the call
1191  * otherwise GoogleTalk won't establish the session */
1192  if (!p->initiator) {
1193  char c;
1194  char *t = lowerthem = ast_strdupa(p->them);
1195  while (((c = *t) != '/') && (*t++ = tolower(c)));
1196  }
1197  iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
1198  iks_insert_attrib(session, "xmlns", GOOGLE_NS);
1199  iks_insert_node(request, session);
1200  ast_aji_send(client->connection, request);
1201  res = 0;
1202  }
1203  }
1204 
1205  iks_delete(session);
1206  iks_delete(request);
1207 
1208  return res;
1209 }
1210 
1211 static void gtalk_free_candidates(struct gtalk_candidate *candidate)
1212 {
1213  struct gtalk_candidate *last;
1214  while (candidate) {
1215  last = candidate;
1216  candidate = candidate->next;
1217  ast_free(last);
1218  }
1219 }
1220 
1221 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
1222 {
1223  struct gtalk_pvt *cur, *prev = NULL;
1224  cur = client->p;
1225  while (cur) {
1226  if (cur == p) {
1227  if (prev)
1228  prev->next = p->next;
1229  else
1230  client->p = p->next;
1231  break;
1232  }
1233  prev = cur;
1234  cur = cur->next;
1235  }
1236  if (p->ringrule)
1237  iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
1238  if (p->owner)
1239  ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
1240  if (p->rtp)
1242  if (p->vrtp)
1245  ast_free(p);
1246 }
1247 
1248 
1249 static int gtalk_newcall(struct gtalk *client, ikspak *pak)
1250 {
1251  struct gtalk_pvt *p, *tmp = client->p;
1252  struct ast_channel *chan;
1253  int res;
1254  iks *codec;
1255  char *from = NULL;
1256  char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
1257  int peernoncodeccapability;
1258  char *sid;
1259 
1260  /* Make sure our new call doesn't exist yet */
1261  from = iks_find_attrib(pak->x,"to");
1262  if (!from) {
1263  from = client->connection->jid->full;
1264  }
1265 
1266  while (tmp) {
1267  if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
1268  (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
1269  ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
1270  gtalk_response(client, from, pak, "out-of-order", NULL);
1271  return -1;
1272  }
1273  tmp = tmp->next;
1274  }
1275 
1276  if (!strcasecmp(client->name, "guest")){
1277  /* the guest account is not tied to any configured XMPP client,
1278  let's set it now */
1279  if (client->connection) {
1281  }
1282  client->connection = ast_aji_get_client(from);
1283  if (!client->connection) {
1284  ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
1285  return -1;
1286  }
1287  }
1288 
1289  if (!(sid = iks_find_attrib(pak->query, "id"))) {
1290  ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
1291  return -1;
1292  }
1293 
1294  p = gtalk_alloc(client, from, pak->from->full, sid);
1295  if (!p) {
1296  ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
1297  return -1;
1298  }
1299 
1300  chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
1301  if (!chan) {
1302  gtalk_free_pvt(client, p);
1303  return -1;
1304  }
1305 
1306  ast_mutex_lock(&p->lock);
1307  ast_copy_string(p->them, pak->from->full, sizeof(p->them));
1308  ast_copy_string(p->sid, sid, sizeof(p->sid));
1309 
1310  /* codec points to the first <payload-type/> tag */
1311  codec = iks_first_tag(iks_first_tag(pak->query));
1312 
1313  while (codec) {
1314  char *codec_id = iks_find_attrib(codec, "id");
1315  char *codec_name = iks_find_attrib(codec, "name");
1316  if (!codec_id || !codec_name) {
1317  codec = iks_next_tag(codec);
1318  continue;
1319  }
1320  if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
1323  p->vrtp,
1324  atoi(codec_id));
1327  p->vrtp,
1328  atoi(codec_id),
1329  "video",
1330  codec_name,
1331  0);
1332  } else {
1335  p->rtp,
1336  atoi(codec_id));
1339  p->rtp,
1340  atoi(codec_id),
1341  "audio",
1342  codec_name,
1343  0);
1344  }
1345  codec = iks_next_tag(codec);
1346  }
1347 
1348  /* Now gather all of the codecs that we are asked for */
1351  ast_mutex_unlock(&p->lock);
1352 
1354  if (!p->jointcapability) {
1355  ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
1358  /* close session if capabilities don't match */
1359  gtalk_action(client, p, "reject");
1360  p->alreadygone = 1;
1361  gtalk_hangup(chan);
1362  ast_channel_release(chan);
1363  return -1;
1364  }
1365 
1366  res = ast_pbx_start(chan);
1367 
1368  switch (res) {
1369  case AST_PBX_FAILED:
1370  ast_log(LOG_WARNING, "Failed to start PBX :(\n");
1371  gtalk_response(client, from, pak, "service-unavailable", NULL);
1372  break;
1373  case AST_PBX_CALL_LIMIT:
1374  ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
1375  gtalk_response(client, from, pak, "service-unavailable", NULL);
1376  break;
1377  case AST_PBX_SUCCESS:
1378  gtalk_response(client, from, pak, NULL, NULL);
1379  gtalk_create_candidates(client, p, p->sid, p->them, p->us);
1380  /* nothing to do */
1381  break;
1382  }
1383 
1384  return 1;
1385 }
1386 
1387 static int gtalk_update_externip(void)
1388 {
1389  int sock;
1390  char *newaddr;
1391  struct sockaddr_in answer = { 0, };
1392  struct sockaddr_in *dst;
1393  struct ast_sockaddr tmp_dst;
1394 
1395  if (!stunaddr.sin_addr.s_addr) {
1396  return -1;
1397  }
1398  dst = &stunaddr;
1399 
1400  sock = socket(AF_INET, SOCK_DGRAM, 0);
1401  if (sock < 0) {
1402  ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
1403  return -1;
1404  }
1405 
1406  ast_sockaddr_from_sin(&tmp_dst, dst);
1407  if (ast_connect(sock, &tmp_dst) != 0) {
1408  ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
1409  close(sock);
1410  return -1;
1411  }
1412 
1413  if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
1414  close(sock);
1415  return -1;
1416  }
1417 
1418  newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
1419  memcpy(externip, newaddr, sizeof(externip));
1420 
1421  close(sock);
1422  return 0;
1423 
1424 }
1425 
1426 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
1427 {
1428  struct gtalk_candidate *tmp;
1429  struct hostent *hp;
1430  struct ast_hostent ahp;
1431  struct sockaddr_in sin = { 0, };
1432  struct sockaddr_in aux = { 0, };
1433  struct ast_sockaddr sin_tmp;
1434  struct ast_sockaddr aux_tmp;
1435 
1436  if (time(NULL) == p->laststun)
1437  return 0;
1438 
1439  tmp = p->theircandidates;
1440  p->laststun = time(NULL);
1441  while (tmp) {
1442  char username[256];
1443 
1444  /* Find the IP address of the host */
1445  if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
1446  ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
1447  tmp = tmp->next;
1448  continue;
1449  }
1450  sin.sin_family = AF_INET;
1451  memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
1452  sin.sin_port = htons(tmp->port);
1453  snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
1454 
1455  /* Find out the result of the STUN */
1457  ast_sockaddr_to_sin(&aux_tmp, &aux);
1458 
1459  /* If the STUN result is different from the IP of the hostname,
1460  * lock on the stun IP of the hostname advertised by the
1461  * remote client */
1462  if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
1463  ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
1464  } else {
1465  ast_sockaddr_from_sin(&sin_tmp, &sin);
1466  ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
1467  }
1468  if (aux.sin_addr.s_addr) {
1469  ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
1470  ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
1471  }
1472 
1473  tmp = tmp->next;
1474  }
1475  return 1;
1476 }
1477 
1478 static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
1479 {
1480  struct gtalk_pvt *p = NULL, *tmp = NULL;
1481  struct aji_client *c = client->connection;
1482  struct gtalk_candidate *newcandidate = NULL;
1483  iks *traversenodes = NULL, *receipt = NULL;
1484  char *from;
1485 
1486  from = iks_find_attrib(pak->x,"to");
1487  if (!from) {
1488  from = c->jid->full;
1489  }
1490 
1491  for (tmp = client->p; tmp; tmp = tmp->next) {
1492  if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
1493  (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
1494  p = tmp;
1495  break;
1496  }
1497  }
1498 
1499  if (!p) {
1500  return -1;
1501  }
1502  traversenodes = pak->query;
1503  while(traversenodes) {
1504  if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
1505  traversenodes = iks_first_tag(traversenodes);
1506  continue;
1507  }
1508  if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
1509  traversenodes = iks_child(traversenodes);
1510  continue;
1511  }
1512  if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
1513  newcandidate = ast_calloc(1, sizeof(*newcandidate));
1514  if (!newcandidate)
1515  return 0;
1516  ast_copy_string(newcandidate->name,
1517  S_OR(iks_find_attrib(traversenodes, "name"), ""),
1518  sizeof(newcandidate->name));
1519  ast_copy_string(newcandidate->ip,
1520  S_OR(iks_find_attrib(traversenodes, "address"), ""),
1521  sizeof(newcandidate->ip));
1522  newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
1523  ast_copy_string(newcandidate->username,
1524  S_OR(iks_find_attrib(traversenodes, "username"), ""),
1525  sizeof(newcandidate->username));
1526  ast_copy_string(newcandidate->password,
1527  S_OR(iks_find_attrib(traversenodes, "password"), ""),
1528  sizeof(newcandidate->password));
1529  newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
1530  if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
1531  newcandidate->protocol = AJI_PROTOCOL_UDP;
1532  if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
1533  newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
1534 
1535  if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
1536  newcandidate->type = AJI_CONNECT_STUN;
1537  if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
1538  newcandidate->type = AJI_CONNECT_LOCAL;
1539  if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
1540  newcandidate->type = AJI_CONNECT_RELAY;
1541  ast_copy_string(newcandidate->network,
1542  S_OR(iks_find_attrib(traversenodes, "network"), ""),
1543  sizeof(newcandidate->network));
1544  newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
1545  newcandidate->next = NULL;
1546 
1547  newcandidate->next = p->theircandidates;
1548  p->theircandidates = newcandidate;
1549  p->laststun = 0;
1550  gtalk_update_stun(p->parent, p);
1551  newcandidate = NULL;
1552  }
1553  traversenodes = iks_next_tag(traversenodes);
1554  }
1555 
1556  receipt = iks_new("iq");
1557  iks_insert_attrib(receipt, "type", "result");
1558  iks_insert_attrib(receipt, "from", from);
1559  iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
1560  iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
1561  ast_aji_send(c, receipt);
1562 
1563  iks_delete(receipt);
1564 
1565  return 1;
1566 }
1567 
1568 static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
1569 {
1570  struct ast_frame *f;
1571 
1572  if (!p->rtp) {
1573  return &ast_null_frame;
1574  }
1575  f = ast_rtp_instance_read(p->rtp, 0);
1576  gtalk_update_stun(p->parent, p);
1577  if (p->owner) {
1578  /* We already hold the channel lock */
1579  if (f->frametype == AST_FRAME_VOICE) {
1581  ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec));
1582  p->owner->nativeformats =
1586  }
1587  /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
1588  f = ast_dsp_process(p->owner, p->vad, f);
1589  if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
1590  ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
1591  } */
1592  }
1593  }
1594  return f;
1595 }
1596 
1597 static struct ast_frame *gtalk_read(struct ast_channel *ast)
1598 {
1599  struct ast_frame *fr;
1600  struct gtalk_pvt *p = ast->tech_pvt;
1601 
1602  ast_mutex_lock(&p->lock);
1603  fr = gtalk_rtp_read(ast, p);
1604  ast_mutex_unlock(&p->lock);
1605  return fr;
1606 }
1607 
1608 /*! \brief Send frame to media channel (rtp) */
1609 static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
1610 {
1611  struct gtalk_pvt *p = ast->tech_pvt;
1612  int res = 0;
1613  char buf[256];
1614 
1615  switch (frame->frametype) {
1616  case AST_FRAME_VOICE:
1617  if (!(frame->subclass.codec & ast->nativeformats)) {
1619  "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1621  ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
1624  return 0;
1625  }
1626  if (p) {
1627  ast_mutex_lock(&p->lock);
1628  if (p->rtp) {
1629  res = ast_rtp_instance_write(p->rtp, frame);
1630  }
1631  ast_mutex_unlock(&p->lock);
1632  }
1633  break;
1634  case AST_FRAME_VIDEO:
1635  if (p) {
1636  ast_mutex_lock(&p->lock);
1637  if (p->vrtp) {
1638  res = ast_rtp_instance_write(p->vrtp, frame);
1639  }
1640  ast_mutex_unlock(&p->lock);
1641  }
1642  break;
1643  case AST_FRAME_IMAGE:
1644  return 0;
1645  break;
1646  default:
1647  ast_log(LOG_WARNING, "Can't send %u type frames with Gtalk write\n",
1648  frame->frametype);
1649  return 0;
1650  }
1651 
1652  return res;
1653 }
1654 
1655 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1656 {
1657  struct gtalk_pvt *p = newchan->tech_pvt;
1658  ast_mutex_lock(&p->lock);
1659 
1660  if ((p->owner != oldchan)) {
1661  ast_mutex_unlock(&p->lock);
1662  return -1;
1663  }
1664  if (p->owner == oldchan)
1665  p->owner = newchan;
1666  ast_mutex_unlock(&p->lock);
1667  return 0;
1668 }
1669 
1670 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1671 {
1672  int res = 0;
1673 
1674  switch (condition) {
1675  case AST_CONTROL_HOLD:
1676  ast_moh_start(ast, data, NULL);
1677  break;
1678  case AST_CONTROL_UNHOLD:
1679  ast_moh_stop(ast);
1680  break;
1681  default:
1682  ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
1683  res = -1;
1684  }
1685 
1686  return res;
1687 }
1688 
1689 static int gtalk_sendtext(struct ast_channel *chan, const char *text)
1690 {
1691  int res = 0;
1692  struct aji_client *client = NULL;
1693  struct gtalk_pvt *p = chan->tech_pvt;
1694 
1695  if (!p->parent) {
1696  ast_log(LOG_ERROR, "Parent channel not found\n");
1697  return -1;
1698  }
1699  if (!p->parent->connection) {
1700  ast_log(LOG_ERROR, "XMPP client not found\n");
1701  return -1;
1702  }
1703  client = p->parent->connection;
1704  res = ast_aji_send_chat(client, p->them, text);
1705  return res;
1706 }
1707 
1708 static int gtalk_digit_begin(struct ast_channel *chan, char digit)
1709 {
1710  struct gtalk_pvt *p = chan->tech_pvt;
1711  int res = 0;
1712 
1713  ast_mutex_lock(&p->lock);
1714  if (p->rtp) {
1715  ast_rtp_instance_dtmf_begin(p->rtp, digit);
1716  } else {
1717  res = -1;
1718  }
1719  ast_mutex_unlock(&p->lock);
1720 
1721  return res;
1722 }
1723 
1724 static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
1725 {
1726  struct gtalk_pvt *p = chan->tech_pvt;
1727  int res = 0;
1728 
1729  ast_mutex_lock(&p->lock);
1730  if (p->rtp) {
1731  ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
1732  } else {
1733  res = -1;
1734  }
1735  ast_mutex_unlock(&p->lock);
1736 
1737  return res;
1738 }
1739 
1740 /* This function is of not in use at the moment, but I am choosing to leave this
1741  * within the code base as a reference to how DTMF is possible through
1742  * jingle signaling. However, google currently does DTMF through the RTP. */
1743 #if 0
1744 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
1745 {
1746  struct gtalk_pvt *p = ast->tech_pvt;
1747  struct gtalk *client = p->parent;
1748  iks *iq, *gtalk, *dtmf;
1749  char buffer[2] = {digit, '\0'};
1750  char *lowerthem = NULL;
1751  iq = iks_new("iq");
1752  gtalk = iks_new("gtalk");
1753  dtmf = iks_new("dtmf");
1754  if(!iq || !gtalk || !dtmf) {
1755  iks_delete(iq);
1756  iks_delete(gtalk);
1757  iks_delete(dtmf);
1758  ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
1759  return -1;
1760  }
1761 
1762  iks_insert_attrib(iq, "type", "set");
1763  iks_insert_attrib(iq, "to", p->them);
1764  iks_insert_attrib(iq, "from", p->us);
1765  iks_insert_attrib(iq, "id", client->connection->mid);
1767  iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
1768  iks_insert_attrib(gtalk, "action", "session-info");
1769  // put the initiator attribute to lower case if we receive the call
1770  // otherwise GoogleTalk won't establish the session
1771  if (!p->initiator) {
1772  char c;
1773  char *t = lowerthem = ast_strdupa(p->them);
1774  while (((c = *t) != '/') && (*t++ = tolower(c)));
1775  }
1776  iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
1777  iks_insert_attrib(gtalk, "sid", p->sid);
1778  iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
1779  iks_insert_attrib(dtmf, "code", buffer);
1780  iks_insert_node(iq, gtalk);
1781  iks_insert_node(gtalk, dtmf);
1782 
1783  ast_mutex_lock(&p->lock);
1784  if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
1785  iks_insert_attrib(dtmf, "action", "button-down");
1786  } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
1787  iks_insert_attrib(dtmf, "action", "button-up");
1788  }
1789  ast_aji_send(client->connection, iq);
1790 
1791  iks_delete(iq);
1792  iks_delete(gtalk);
1793  iks_delete(dtmf);
1794  ast_mutex_unlock(&p->lock);
1795  return 0;
1796 }
1797 #endif
1798 
1799 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
1800 {
1801  ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
1802 
1803  return -1;
1804 }
1805 
1806 /*!\brief Initiate new call, part of PBX interface
1807  * dest is the dial string */
1808 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
1809 {
1810  struct gtalk_pvt *p = ast->tech_pvt;
1811 
1812  if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
1813  ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
1814  return -1;
1815  }
1816 
1818  if (!p->ringrule) {
1819  ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
1820  p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
1821  IKS_RULE_ID, p->ring, IKS_RULE_DONE);
1822  } else {
1823  ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
1824  }
1825 
1826  gtalk_invite(p, p->them, p->us, p->sid, 1);
1827 
1828  return 0;
1829 }
1830 
1831 /*! \brief Hangup a call through the gtalk proxy channel */
1832 static int gtalk_hangup(struct ast_channel *ast)
1833 {
1834  struct gtalk_pvt *p = ast->tech_pvt;
1835  struct gtalk *client;
1836 
1837  ast_mutex_lock(&p->lock);
1838  client = p->parent;
1839  p->owner = NULL;
1840  ast->tech_pvt = NULL;
1841  if (!p->alreadygone) {
1842  gtalk_action(client, p, "terminate");
1843  }
1844  ast_mutex_unlock(&p->lock);
1845 
1846  gtalk_free_pvt(client, p);
1848 
1849  return 0;
1850 }
1851 
1852 /*!\brief Part of PBX interface */
1853 static struct ast_channel *gtalk_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
1854 {
1855  struct gtalk_pvt *p = NULL;
1856  struct gtalk *client = NULL;
1857  char *sender = NULL, *to = NULL, *s = NULL;
1858  struct ast_channel *chan = NULL;
1859 
1860  if (data) {
1861  s = ast_strdupa(data);
1862  sender = strsep(&s, "/");
1863  if (sender && (sender[0] != '\0')) {
1864  to = strsep(&s, "/");
1865  }
1866  if (!to) {
1867  ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
1868  return NULL;
1869  }
1870  }
1871 
1872  client = find_gtalk(to, sender);
1873  if (!client) {
1874  ast_log(LOG_WARNING, "Could not find recipient.\n");
1875  return NULL;
1876  }
1877  if (!strcasecmp(client->name, "guest")){
1878  /* the guest account is not tied to any configured XMPP client,
1879  let's set it now */
1880  if (client->connection) {
1882  }
1883  client->connection = ast_aji_get_client(sender);
1884  if (!client->connection) {
1885  ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
1887  return NULL;
1888  }
1889  }
1890 
1891  ASTOBJ_WRLOCK(client);
1892  p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
1893  if (p) {
1894  chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? requestor->linkedid : NULL);
1895  }
1896  ASTOBJ_UNLOCK(client);
1897  return chan;
1898 }
1899 
1900 /*! \brief CLI command "gtalk show channels" */
1901 static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1902 {
1903 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
1904  struct gtalk_pvt *p;
1905  struct ast_channel *chan;
1906  int numchans = 0;
1907  char them[AJI_MAX_JIDLEN];
1908  char *jid = NULL;
1909  char *resource = NULL;
1910 
1911  switch (cmd) {
1912  case CLI_INIT:
1913  e->command = "gtalk show channels";
1914  e->usage =
1915  "Usage: gtalk show channels\n"
1916  " Shows current state of the Gtalk channels.\n";
1917  return NULL;
1918  case CLI_GENERATE:
1919  return NULL;
1920  }
1921 
1922  if (a->argc != 3)
1923  return CLI_SHOWUSAGE;
1924 
1926  ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
1928  ASTOBJ_WRLOCK(iterator);
1929  p = iterator->p;
1930  while(p) {
1931  chan = p->owner;
1932  ast_copy_string(them, p->them, sizeof(them));
1933  jid = them;
1934  resource = strchr(them, '/');
1935  if (!resource)
1936  resource = "None";
1937  else {
1938  *resource = '\0';
1939  resource ++;
1940  }
1941  if (chan)
1942  ast_cli(a->fd, FORMAT,
1943  chan->name,
1944  jid,
1945  resource,
1948  );
1949  else
1950  ast_log(LOG_WARNING, "No available channel\n");
1951  numchans ++;
1952  p = p->next;
1953  }
1954  ASTOBJ_UNLOCK(iterator);
1955  });
1956 
1958 
1959  ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
1960  return CLI_SUCCESS;
1961 #undef FORMAT
1962 }
1963 
1964 /*! \brief CLI command "gtalk reload"
1965  * \todo XXX TODO make this work. */
1966 #if 0
1967 static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1968 {
1969  switch (cmd) {
1970  case CLI_INIT:
1971  e->command = "gtalk reload";
1972  e->usage =
1973  "Usage: gtalk reload\n"
1974  " Reload gtalk channel driver.\n";
1975  return NULL;
1976  case CLI_GENERATE:
1977  return NULL;
1978  }
1979 
1980  ast_verbose("IT DOES WORK!\n");
1981  return CLI_SUCCESS;
1982 }
1983 #endif
1984 
1985 static int gtalk_parser(void *data, ikspak *pak)
1986 {
1987  struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
1988  int res;
1989  iks *tmp;
1990 
1991  if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
1992  ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
1993  pak->query = tmp;
1994  }
1995 
1996  if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
1997  ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
1998  }
1999 
2000  if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
2001  ast_log(LOG_NOTICE, "No attribute \"type\" found. Ignoring message.\n");
2002  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
2003  /* New call */
2004  gtalk_newcall(client, pak);
2005  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
2006  ast_debug(3, "About to add candidate!\n");
2007  res = gtalk_add_candidate(client, pak);
2008  if (!res) {
2009  ast_log(LOG_WARNING, "Could not add any candidate\n");
2010  } else {
2011  ast_debug(3, "Candidate Added!\n");
2012  }
2013  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
2014  gtalk_is_answered(client, pak);
2015  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
2016  gtalk_is_accepted(client, pak);
2017  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
2018  gtalk_handle_dtmf(client, pak);
2019  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
2020  gtalk_hangup_farend(client, pak);
2021  } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
2022  gtalk_hangup_farend(client, pak);
2023  }
2025  return IKS_FILTER_EAT;
2026 }
2027 
2028 static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
2029  struct ast_codec_pref prefs, char *context,
2030  struct gtalk *member)
2031 {
2032  struct aji_client *client;
2033 
2034  if (!member)
2035  ast_log(LOG_WARNING, "Out of memory.\n");
2036 
2037  ast_copy_string(member->name, label, sizeof(member->name));
2038  ast_copy_string(member->user, label, sizeof(member->user));
2039  ast_copy_string(member->context, context, sizeof(member->context));
2040  member->allowguest = allowguest;
2041  member->prefs = prefs;
2042  while (var) {
2043  if (!strcasecmp(var->name, "username"))
2044  ast_copy_string(member->user, var->value, sizeof(member->user));
2045  else if (!strcasecmp(var->name, "disallow"))
2046  ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
2047  else if (!strcasecmp(var->name, "allow"))
2048  ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
2049  else if (!strcasecmp(var->name, "context"))
2050  ast_copy_string(member->context, var->value, sizeof(member->context));
2051  else if (!strcasecmp(var->name, "parkinglot"))
2052  ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
2053  else if (!strcasecmp(var->name, "connection")) {
2054  if ((client = ast_aji_get_client(var->value))) {
2055  member->connection = client;
2056  iks_filter_add_rule(client->f, gtalk_parser, member,
2057  IKS_RULE_TYPE, IKS_PAK_IQ,
2058  IKS_RULE_FROM_PARTIAL, member->user,
2059  IKS_RULE_NS, GOOGLE_NS,
2060  IKS_RULE_DONE);
2061  } else {
2062  ast_log(LOG_ERROR, "connection referenced not found!\n");
2063  return 0;
2064  }
2065  }
2066  var = var->next;
2067  }
2068  if (member->connection && member->user)
2069  member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
2070  else {
2071  ast_log(LOG_ERROR, "No Connection or Username!\n");
2072  }
2073  return 1;
2074 }
2075 
2076 static int gtalk_load_config(void)
2077 {
2078  char *cat = NULL;
2079  struct ast_config *cfg = NULL;
2080  char context[AST_MAX_CONTEXT] = "";
2081  char parkinglot[AST_MAX_CONTEXT] = "";
2082  int allowguest = 1;
2083  struct ast_variable *var;
2084  struct gtalk *member;
2085  struct ast_codec_pref prefs = { "", };
2086  struct aji_client_container *clients;
2087  struct gtalk_candidate *global_candidates = NULL;
2088  struct hostent *hp;
2089  struct ast_hostent ahp;
2090  struct ast_flags config_flags = { 0 };
2091 
2092  cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
2093  if (!cfg) {
2094  return 0;
2095  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2096  ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG);
2097  return 0;
2098  }
2099 
2100  /* Copy the default jb config over global_jbconf */
2101  memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
2102 
2103  /* set defaults */
2104  memset(&stunaddr, 0, sizeof(stunaddr));
2105 
2106  cat = ast_category_browse(cfg, NULL);
2107  for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2108  /* handle jb conf */
2109  if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
2110  continue;
2111 
2112  if (!strcasecmp(var->name, "allowguest")) {
2113  allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
2114  } else if (!strcasecmp(var->name, "disallow")) {
2115  ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
2116  } else if (!strcasecmp(var->name, "allow")) {
2117  ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
2118  } else if (!strcasecmp(var->name, "context")) {
2119  ast_copy_string(context, var->value, sizeof(context));
2120  } else if (!strcasecmp(var->name, "externip")) {
2121  ast_copy_string(externip, var->value, sizeof(externip));
2122  } else if (!strcasecmp(var->name, "parkinglot")) {
2123  ast_copy_string(parkinglot, var->value, sizeof(parkinglot));
2124  } else if (!strcasecmp(var->name, "bindaddr")) {
2125  if (!(hp = ast_gethostbyname(var->value, &ahp))) {
2126  ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
2127  } else {
2128  memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
2129  }
2130  } else if (!strcasecmp(var->name, "stunaddr")) {
2131  stunaddr.sin_port = htons(STANDARD_STUN_PORT);
2132  if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
2133  ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
2134  }
2135  }
2136  }
2137  while (cat) {
2138  if (strcasecmp(cat, "general")) {
2139  var = ast_variable_browse(cfg, cat);
2140  member = ast_calloc(1, sizeof(*member));
2141  ASTOBJ_INIT(member);
2142  ASTOBJ_WRLOCK(member);
2143  if (!strcasecmp(cat, "guest")) {
2144  ast_copy_string(member->name, "guest", sizeof(member->name));
2145  ast_copy_string(member->user, "guest", sizeof(member->user));
2146  ast_copy_string(member->context, context, sizeof(member->context));
2147  ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot));
2148  member->allowguest = allowguest;
2149  member->prefs = prefs;
2150  while (var) {
2151  if (!strcasecmp(var->name, "disallow")) {
2152  ast_parse_allow_disallow(&member->prefs, &member->capability,
2153  var->value, 0);
2154  } else if (!strcasecmp(var->name, "allow")) {
2155  ast_parse_allow_disallow(&member->prefs, &member->capability,
2156  var->value, 1);
2157  } else if (!strcasecmp(var->name, "context")) {
2158  ast_copy_string(member->context, var->value,
2159  sizeof(member->context));
2160  } else if (!strcasecmp(var->name, "parkinglot")) {
2161  ast_copy_string(member->parkinglot, var->value,
2162  sizeof(member->parkinglot));
2163  }
2164  var = var->next;
2165  }
2166  ASTOBJ_UNLOCK(member);
2167  clients = ast_aji_get_clients();
2168  if (clients) {
2169  ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
2170  ASTOBJ_WRLOCK(iterator);
2171  ASTOBJ_WRLOCK(member);
2172  if (member->connection) {
2174  }
2175  member->connection = NULL;
2176  iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
2177  iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
2178  iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE);
2179  ASTOBJ_UNLOCK(member);
2180  ASTOBJ_UNLOCK(iterator);
2181  });
2184  } else {
2185  ASTOBJ_UNLOCK(member);
2187  }
2188  } else {
2189  ASTOBJ_UNLOCK(member);
2190  if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
2193  }
2194  }
2195  cat = ast_category_browse(cfg, cat);
2196  }
2197 
2198  ast_config_destroy(cfg);
2200  gtalk_free_candidates(global_candidates);
2201  return 1;
2202 }
2203 
2204 /*! \brief Load module into PBX, register channel */
2205 static int load_module(void)
2206 {
2207  struct ast_sockaddr bindaddr_tmp;
2208  struct ast_sockaddr ourip_tmp;
2209 
2210  char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
2211  free(jabber_loaded);
2212  if (!jabber_loaded) {
2213  /* If embedded, check for a different module name */
2214  jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
2215  free(jabber_loaded);
2216  if (!jabber_loaded) {
2217  ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
2218  return AST_MODULE_LOAD_DECLINE;
2219  }
2220  }
2221 
2223  if (!gtalk_load_config()) {
2224  ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
2225  return 0;
2226  }
2227 
2228  sched = sched_context_create();
2229  if (!sched) {
2230  ast_log(LOG_WARNING, "Unable to create schedule context\n");
2231  }
2232 
2233  io = io_context_create();
2234  if (!io) {
2235  ast_log(LOG_WARNING, "Unable to create I/O context\n");
2236  }
2237 
2238  ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
2239  if (gtalk_get_local_ip(&ourip_tmp)) {
2240  ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
2241  return 0;
2242  }
2243  __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
2244 
2245  ast_rtp_glue_register(&gtalk_rtp_glue);
2246  ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
2247 
2248  /* Make sure we can register our channel type */
2249  if (ast_channel_register(&gtalk_tech)) {
2250  ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
2251  return -1;
2252  }
2253  return 0;
2254 }
2255 
2256 /*! \brief Reload module
2257  * \todo XXX TODO make this work. */
2258 #if 0
2259 static int reload(void)
2260 {
2261  return 0;
2262 }
2263 #endif
2264 /*! \brief Unload the gtalk channel from Asterisk */
2265 static int unload_module(void)
2266 {
2267  struct gtalk_pvt *privates = NULL;
2268  ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
2269  /* First, take us out of the channel loop */
2270  ast_channel_unregister(&gtalk_tech);
2271  ast_rtp_glue_unregister(&gtalk_rtp_glue);
2272 
2273  if (!ast_mutex_lock(&gtalklock)) {
2274  /* Hangup all interfaces if they have an owner */
2276  ASTOBJ_WRLOCK(iterator);
2277  privates = iterator->p;
2278  while(privates) {
2279  if (privates->owner)
2281  privates = privates->next;
2282  }
2283  iterator->p = NULL;
2284  ASTOBJ_UNLOCK(iterator);
2285  });
2287  } else {
2288  ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2289  return -1;
2290  }
2293  return 0;
2294 }
2295 
2297  .load = load_module,
2298  .unload = unload_module,
2299  /* .reload = reload, */
2300  .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2301  );
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:240
Jingle definitions for chan_jingle.
void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs)
Set codec packetization preferences.
Definition: rtp_engine.c:727
static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
Definition: chan_gtalk.c:522
static char musicclass[MAX_MUSICCLASS]
Definition: chan_mgcp.c:155
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1569
unsigned long long ast_group_t
Definition: channel.h:175
static char pass[512]
union ast_frame_subclass subclass
Definition: frame.h:146
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:383
int presentation
Q.931 encoded presentation-indicator encoded field.
Definition: channel.h:227
static int gtalk_hangup(struct ast_channel *ast)
Hangup a call through the gtalk proxy channel.
Definition: chan_gtalk.c:1832
static format_t global_capability
Definition: chan_gtalk.c:171
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
struct aji_client * connection
Definition: chan_gtalk.c:147
Music on hold handling.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static int gtalk_ringing_ack(void *data, ikspak *pak)
Definition: chan_gtalk.c:461
const char *const type
Definition: channel.h:508
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int rings
Definition: channel.h:840
static struct ast_channel * gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const char *linkedid)
Start new gtalk channel.
Definition: chan_gtalk.c:1081
struct ast_rtp_instance * rtp
Definition: chan_gtalk.c:123
void ast_aji_buddy_destroy(struct aji_buddy *obj)
Definition: res_jabber.c:432
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char * str
Subscriber phone number (Malloced)
Definition: channel.h:336
void ast_module_unref(struct ast_module *)
Definition: loader.c:1312
static char parkinglot[AST_MAX_CONTEXT]
Definition: chan_mgcp.c:156
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame with payload.
Definition: channel.c:1601
struct ast_frame ast_null_frame
Definition: frame.c:131
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
char * strsep(char **str, const char *delims)
static char * gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command &quot;gtalk show channels&quot;.
Definition: chan_gtalk.c:1901
int amaflags
Definition: chan_gtalk.c:151
double preference
Definition: chan_gtalk.c:133
int priority
Definition: channel.h:841
static void gtalk_free_candidates(struct gtalk_candidate *candidate)
Definition: chan_gtalk.c:1211
static struct ast_frame * gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
Definition: chan_gtalk.c:1568
int presentation
Q.931 presentation-indicator and screening-indicator encoded fields.
Definition: channel.h:245
int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode)
Set the DTMF mode that should be used.
Definition: rtp_engine.c:750
char them[AJI_MAX_JIDLEN]
Definition: chan_gtalk.c:110
#define ast_strdup(a)
Definition: astmm.h:109
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
format_t writeformat
Definition: channel.h:854
static int gtalk_load_config(void)
Definition: chan_gtalk.c:2076
static struct ast_jb_conf default_jbconf
Definition: chan_gtalk.c:83
static struct io_context * io
Definition: chan_gtalk.c:228
int ast_aji_send(struct aji_client *client, iks *x)
Wraps raw sending.
Definition: res_jabber.c:1439
int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindaddr, int family)
Find our IP address.
Definition: acl.c:744
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define AST_CAUSE_SWITCH_CONGESTION
Definition: causes.h:122
ast_group_t callgroup
Definition: chan_gtalk.c:157
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:121
#define MAX_MUSICCLASS
Definition: channel.h:139
struct ast_party_name name
Subscriber name.
Definition: channel.h:290
static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
Definition: chan_gtalk.c:1799
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:938
void * tech_pvt
Definition: channel.h:744
struct ast_rtp_instance * vrtp
Definition: chan_gtalk.c:124
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1921
static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
Definition: chan_gtalk.c:1426
struct ast_rtp_codecs * ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
Get the codecs structure of an RTP instance.
Definition: rtp_engine.c:483
static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
Definition: chan_gtalk.c:782
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
static int gtalk_sendtext(struct ast_channel *ast, const char *text)
Definition: chan_gtalk.c:1689
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:5879
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
Definition: abstract_jb.c:577
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
gtalk_connect_type
Definition: chan_gtalk.c:98
char cid_num[80]
Definition: chan_gtalk.c:119
#define AST_FRAME_DTMF
Definition: frame.h:128
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_gtalk.c:155
char username[100]
Definition: chan_gtalk.c:134
static struct gtalk_container gtalk_list
Definition: chan_gtalk.c:239
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
enum gtalk_connect_type type
Definition: chan_gtalk.c:136
#define AST_MAX_ACCOUNT_CODE
Definition: cdr.h:73
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Send a frame out over RTP.
Definition: rtp_engine.c:374
format_t rawwriteformat
Definition: channel.h:856
#define ast_rtp_glue_register(glue)
Definition: rtp_engine.h:476
format_t ast_codec_pref_index(struct ast_codec_pref *pref, int index)
Codec located at a particular place in the preference index.
Definition: frame.c:1061
static struct ast_cli_entry gtalk_cli[]
Definition: chan_gtalk.c:231
Definition: cli.h:146
Configuration File Parser.
#define FORMAT
static int gtalk_write(struct ast_channel *ast, struct ast_frame *f)
Send frame to media channel (rtp)
Definition: chan_gtalk.c:1609
uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
Get an IPv4 address of an ast_sockaddr.
Definition: netsock2.c:394
static struct in_addr __ourip
Definition: chan_gtalk.c:229
#define GOOGLE_TRANSPORT_NS
Definition: jingle.h:50
format_t ast_best_codec(format_t fmts)
Pick the best audio codec.
Definition: channel.c:1062
struct gtalk_pvt * p
Definition: chan_gtalk.c:149
#define ASTOBJ_WRLOCK(object)
Lock an ASTOBJ for writing.
Definition: astobj.h:104
iksrule * ringrule
Definition: chan_gtalk.c:112
#define ast_mutex_lock(a)
Definition: lock.h:155
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:907
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
char * text
Definition: app_queue.c:1091
format_t nativeformats
Definition: channel.h:852
static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, format_t codecs, int nat_active)
Definition: chan_gtalk.c:547
static int gtalk_parser(void *data, ikspak *pak)
CLI command &quot;gtalk reload&quot;.
Definition: chan_gtalk.c:1985
time_t laststun
Definition: chan_gtalk.c:106
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
format_t codec
Definition: frame.h:137
static void gtalk_member_destroy(struct gtalk *obj)
Definition: chan_gtalk.c:241
const char * data
Definition: channel.h:755
I/O Management (derived from Cheops-NG)
Common implementation-independent jitterbuffer stuff.
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
struct aji_buddy * buddy
Definition: chan_gtalk.c:148
const ast_string_field linkedid
Definition: channel.h:787
AJI - The Asterisk Jabber Interface.
#define LOG_DEBUG
Definition: logger.h:122
format_t peercapability
Definition: chan_gtalk.c:126
static struct gtalk_pvt * gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
Definition: chan_gtalk.c:977
enum ast_channel_adsicpe adsicpe
Definition: channel.h:844
format_t rawreadformat
Definition: channel.h:855
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
Socket address structure.
Definition: netsock2.h:63
ast_group_t pickupgroup
Definition: channel.h:819
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
const char * type
Definition: rtp_engine.h:395
ast_group_t callgroup
Definition: channel.h:818
struct ast_channel * ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const char *linkedid, const int amaflag, const char *name_fmt,...)
Definition: channel.c:9825
int capability
Definition: chan_gtalk.c:115
static int gtalk_update_externip(void)
Definition: chan_gtalk.c:1387
struct ast_frame dtmff
Definition: channel.h:816
#define MAX_LANGUAGE
Definition: channel.h:138
int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
sends messages.
Definition: res_jabber.c:2582
String fields in structures.
Utility functions.
static int unload_module(void)
Reload module.
Definition: chan_gtalk.c:2265
char network[6]
Definition: chan_gtalk.c:137
static char externip[16]
Definition: chan_gtalk.c:236
#define ASTOBJ_COMPONENTS(type)
Add ASTOBJ components to a struct (with locking support).
Definition: astobj.h:173
void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username)
Request that the underlying RTP engine send a STUN BIND request.
Definition: rtp_engine.c:1749
struct gtalk_pvt * next
Definition: chan_gtalk.c:127
#define ASTOBJ_CONTAINER_INIT(container)
Initialize a container.
Definition: astobj.h:752
char context[AST_MAX_CONTEXT]
Definition: chan_gtalk.c:153
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
char resource[AJI_MAX_RESJIDLEN]
Definition: jabber.h:119
char sid[100]
Definition: chan_gtalk.c:108
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
char ring[10]
Definition: chan_gtalk.c:111
int ast_set_read_format(struct ast_channel *chan, format_t format)
Sets read format on channel chan Set read format for channel to whichever component of &quot;format&quot; is be...
Definition: channel.c:5301
int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us)
Get our local IP address when contacting a remote host.
Definition: acl.c:705
static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest, struct ast_codec_pref prefs, char *context, struct gtalk *member)
Definition: chan_gtalk.c:2028
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
Determine if the address type is unspecified, or &quot;any&quot; address.
Definition: netsock2.c:424
const char * value
Definition: config.h:79
static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
Definition: chan_gtalk.c:713
struct ast_module * self
Definition: module.h:227
General Asterisk PBX channel definitions.
static const int STANDARD_STUN_PORT
Definition: stun.h:35
struct gtalk * parent
Definition: chan_gtalk.c:107
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: config.c:2805
struct ast_party_dialed::@155 number
Dialed/Called number.
struct gtalk_candidate * ourcandidates
Definition: chan_gtalk.c:118
struct aji_buddy_container buddies
Definition: jabber.h:184
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
Definition: netsock2.h:642
static struct ast_jb_conf global_jbconf
Definition: chan_gtalk.c:91
const int fd
Definition: cli.h:153
#define AST_FORMAT_ALAW
Definition: frame.h:248
char musicclass[MAX_MUSICCLASS]
Definition: chan_gtalk.c:162
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
Generic STUN request.
Definition: stun.c:373
char * ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
Match modules names for the Asterisk cli.
Definition: loader.c:626
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
Access Control of various sorts.
Global IO variables are now in a struct in order to be made threadsafe.
Definition: io.c:66
format_t capability
Definition: chan_gtalk.c:156
format_t jointcapability
Definition: chan_gtalk.c:125
int datalen
Definition: frame.h:148
Scheduler Routines (derived from cheops)
char name[80]
Definition: chan_gtalk.c:146
char parkinglot[AST_MAX_CONTEXT]
Definition: chan_gtalk.c:154
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define ao2_ref(o, delta)
Definition: astobj2.h:472
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2746
long int ast_random(void)
Definition: utils.c:1640
struct ast_codec_pref prefs
Definition: chan_gtalk.c:150
#define ASTOBJ_INIT(object)
Initialize an object.
Definition: astobj.h:264
int initiator
Definition: chan_gtalk.c:113
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:108
const char * name
Definition: config.h:77
char user[AJI_MAX_JIDLEN]
Definition: chan_gtalk.c:152
STUN support.
static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
Definition: chan_gtalk.c:840
#define AST_FORMAT_H263
Definition: frame.h:283
int alreadygone
Definition: chan_gtalk.c:114
static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs)
Definition: chan_gtalk.c:278
char password[100]
Definition: chan_gtalk.c:135
struct aji_resource * next
Definition: jabber.h:123
ast_rtp_glue_result
Definition: rtp_engine.h:125
int callingpres
Definition: chan_gtalk.c:159
int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options)
Record payload information that was seen in an a=rtpmap: SDP line.
Definition: rtp_engine.c:597
Structure to describe a channel &quot;technology&quot;, ie a channel driver See for examples: ...
Definition: channel.h:507
Core PBX routines and definitions.
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1558
static struct sched_context * sched
Definition: chan_gtalk.c:227
#define ASTOBJ_UNREF(object, destructor)
Decrement the reference count on an object.
Definition: astobj.h:218
static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
Definition: chan_gtalk.c:1670
struct ast_party_dialed dialed
Dialed/Called information.
Definition: channel.h:797
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static int reload(void)
Definition: app_amd.c:497
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
ASTOBJ_CONTAINER_COMPONENTS(struct gtalk)
static int gtalk_is_accepted(struct gtalk *client, ikspak *pak)
Definition: chan_gtalk.c:684
char us[AJI_MAX_JIDLEN]
Definition: chan_gtalk.c:109
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define ASTOBJ_CONTAINER_DESTROY(container)
Destroy a container.
Definition: astobj.h:765
#define LOG_ERROR
Definition: logger.h:155
#define ASTOBJ_CONTAINER_DESTROYALL(container, destructor)
Empty a container.
Definition: astobj.h:453
A set of macros implementing objects and containers. Macros are used for maximum performance, to support multiple inheritance, and to be easily integrated into existing structures without additional malloc calls, etc.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
static struct sockaddr_in stunaddr
Definition: chan_gtalk.c:237
int64_t format_t
Definition: frame_defs.h:32
#define free(a)
Definition: astmm.h:94
#define ASTOBJ_CONTAINER_LINK(container, newobj)
Add an object to a container.
Definition: astobj.h:776
struct ast_channel * owner
Definition: chan_gtalk.c:122
#define CLI_SHOWUSAGE
Definition: cli.h:44
static struct ast_codec_pref prefs
Definition: chan_iax2.c:258
static const char desc[]
Definition: chan_gtalk.c:169
#define AST_FORMAT_ULAW
Definition: frame.h:246
iksid * jid
Definition: jabber.h:160
static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
Definition: chan_gtalk.c:383
static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_gtalk.c:1724
enum ast_channel_state _state
Definition: channel.h:839
int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit)
Begin sending a DTMF digit.
Definition: rtp_engine.c:736
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:210
const ast_string_field name
Definition: channel.h:787
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AJI_MAX_JIDLEN
Definition: jabber.h:73
format_t ast_codec_choose(struct ast_codec_pref *pref, format_t formats, int find_best)
Select the best audio format according to preference list from supplied options. If &quot;find_best&quot; is no...
Definition: frame.c:1249
#define ASTOBJ_CONTAINER_TRAVERSE(container, continue, eval)
Iterate through the objects in a container.
Definition: astobj.h:376
#define LOG_NOTICE
Definition: logger.h:133
ast_group_t pickupgroup
Definition: chan_gtalk.c:158
struct aji_client * ast_aji_get_client(const char *name)
grab a aji_client structure by label name or JID. Bumps the refcount. (without the resource string) ...
Definition: res_jabber.c:4575
#define AST_FORMAT_VIDEO_MASK
Definition: frame.h:290
int errno
ast_mutex_t lock
Definition: chan_gtalk.c:105
static const char name[]
#define AST_MAX_CONTEXT
Definition: channel.h:136
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:564
#define ASTOBJ_UNLOCK(object)
Unlock a locked object.
Definition: astobj.h:109
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
#define ASTOBJ_CONTAINER_FIND(container, namestr)
Find an object in a container.
Definition: astobj.h:401
#define AST_FORMAT_AUDIO_MASK
Definition: frame.h:274
void ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.c:447
int allowguest
Definition: jabber.h:177
static struct ast_format f[]
Definition: format_g726.c:181
int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp)
Get the file descriptor for an RTP session (or RTCP)
Definition: rtp_engine.c:786
struct ast_rtp_instance * ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, const struct ast_sockaddr *sa, void *data)
Create a new RTP instance.
Definition: rtp_engine.c:308
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition: abstract_jb.h:58
static const char type[]
Definition: chan_nbs.c:57
structure to hold users read from users.conf
void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
Clear payload information from an RTP instance.
Definition: rtp_engine.c:488
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the local address that we are expecting RTP on.
Definition: rtp_engine.c:430
Structure used to handle boolean flags.
Definition: utils.h:200
static struct aji_client_container clients
Definition: res_jabber.c:392
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
Destroy an RTP instance.
Definition: rtp_engine.c:301
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2631
static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
Initiate new call, part of PBX interface dest is the dial string.
Definition: chan_gtalk.c:1808
#define GOOGLE_CONFIG
Definition: chan_gtalk.c:80
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
Definition: abstract_jb.c:616
const char * usage
Definition: cli.h:171
static struct ast_frame * gtalk_read(struct ast_channel *ast)
Definition: chan_gtalk.c:1597
static struct sockaddr_in bindaddr
Definition: chan_gtalk.c:225
char cid_name[80]
Definition: chan_gtalk.c:120
char name[100]
Definition: chan_gtalk.c:131
void ast_aji_client_destroy(struct aji_client *obj)
Definition: res_jabber.c:410
static int gtalk_newcall(struct gtalk *client, ikspak *pak)
Definition: chan_gtalk.c:1249
static struct gtalk * find_gtalk(char *name, char *connection)
Definition: chan_gtalk.c:246
struct aji_version * cap
Definition: jabber.h:121
#define CLI_SUCCESS
Definition: cli.h:43
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
Definition: utils.c:195
static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_gtalk.c:1655
#define GOOGLE_AUDIO_NS
Definition: jingle.h:48
struct sched_context * sched_context_create(void)
New schedule context.
Definition: sched.c:246
Channels have this property if they can create jitter; i.e. most VoIP channels.
Definition: channel.h:888
static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
Definition: chan_gtalk.c:606
Standard Command Line Interface.
#define ASTOBJ_RDLOCK(object)
Lock an ASTOBJ for reading.
Definition: astobj.h:100
format_t readformat
Definition: channel.h:853
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
int allowguest
Definition: chan_gtalk.c:160
char exten[80]
Definition: chan_gtalk.c:121
static struct ast_rtp_glue gtalk_rtp_glue
Definition: chan_gtalk.c:567
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7119
int ast_rtp_glue_unregister(struct ast_rtp_glue *glue)
Unregister RTP glue.
Definition: rtp_engine.c:266
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define GOOGLE_JINGLE_NS
Definition: jingle.h:47
char * ast_getformatname_multiple(char *buf, size_t size, format_t format)
Get the names of a set of formats.
Definition: frame.c:591
Data structure associated with a single frame of data.
Definition: frame.h:142
int hangupcause
Definition: channel.h:849
#define ASTOBJ_CONTAINER_FIND_FULL(container, data, field, hashfunc, hashoffset, comparefunc)
Find an object in a container.
Definition: astobj.h:428
Internal Asterisk hangup causes.
char language[MAX_LANGUAGE]
Definition: chan_gtalk.c:161
static int load_module(void)
Load module into PBX, register channel.
Definition: chan_gtalk.c:2205
Channels have this property if they can accept input with jitter; i.e. most VoIP channels.
Definition: channel.h:883
void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
Set the value of an RTP instance property.
Definition: rtp_engine.c:469
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
Definition: netsock2.h:629
enum ast_frame_type frametype
Definition: frame.h:144
struct ast_variable * next
Definition: config.h:82
static format_t gtalk_get_codec(struct ast_channel *chan)
Definition: chan_gtalk.c:541
#define ast_mutex_init(pmutex)
Definition: lock.h:152
#define GOOGLE_NS
Definition: jingle.h:46
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
int ast_rtp_instance_dtmf_end_with_duration(struct ast_rtp_instance *instance, char digit, unsigned int duration)
Definition: rtp_engine.c:745
static int gtalk_answer(struct ast_channel *ast)
Definition: chan_gtalk.c:508
static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
Definition: chan_gtalk.c:1173
gtalk_protocol
Definition: chan_gtalk.c:93
static ast_mutex_t gtalklock
Definition: chan_gtalk.c:173
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
Pluggable RTP Architecture.
#define ASTOBJ_REF(object)
Increment an object reference count.
Definition: astobj.h:201
Asterisk module definitions.
static struct hostent * hp
Definition: chan_skinny.c:1048
struct gtalk_candidate * next
Definition: chan_gtalk.c:142
enum gtalk_protocol protocol
Definition: chan_gtalk.c:132
static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
Definition: chan_gtalk.c:1221
int amaflags
Definition: channel.h:843
struct gtalk_candidate * theircandidates
Definition: chan_gtalk.c:117
static snd_pcm_format_t format
Definition: chan_alsa.c:93
union ast_frame::@172 data
struct ast_channel_tech * tech
Definition: channel.h:743
#define AST_FORMAT_GSM
Definition: frame.h:244
char mid[6]
Definition: jabber.h:159
struct aji_resource * resources
Definition: jabber.h:137
General jitterbuffer configuration.
Definition: abstract_jb.h:55
void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
Record payload information that was seen in an m= SDP line.
Definition: rtp_engine.c:532
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:526
iksfilter * f
Definition: jabber.h:162
int jingle
Definition: jabber.h:106
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:467
Structure for mutex and tracking information.
Definition: lock.h:121
static int gtalk_digit_begin(struct ast_channel *ast, char digit)
Definition: chan_gtalk.c:1708
void ast_aji_increment_mid(char *mid)
increments the mid field for messages and other events.
Definition: res_jabber.c:2790
int ast_parse_allow_disallow(struct ast_codec_pref *pref, format_t *mask, const char *list, int allowing)
Parse an &quot;allow&quot; or &quot;deny&quot; line in a channel or device configuration and update the capabilities mask...
Definition: frame.c:1272
void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, format_t *astformats, int *nonastformats)
Retrieve all formats that were found.
Definition: rtp_engine.c:636
static struct ast_channel * gtalk_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
Part of PBX interface.
Definition: chan_gtalk.c:1853
struct ast_frame * ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
Receive a frame over RTP.
Definition: rtp_engine.c:379
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
struct ast_codec_pref prefs
Definition: chan_gtalk.c:116
#define ast_mutex_unlock(a)
Definition: lock.h:156
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
Definition: netsock2.c:248
static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
Definition: chan_gtalk.c:1478
static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
Definition: chan_gtalk.c:574
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
static int gtalk_get_local_ip(struct ast_sockaddr *ourip)
Definition: chan_gtalk.c:812
static struct ast_channel_tech gtalk_tech
PBX interface structure for channel registration.
Definition: chan_gtalk.c:201
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292
struct aji_client_container * ast_aji_get_clients(void)
Definition: res_jabber.c:4597
struct io_context * io_context_create(void)
Creates a context Create a context for I/O operations Basically mallocs an IO structure and sets up s...
Definition: io.c:76