📄 chan_gtalk.c
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 1999 - 2005, Digium, Inc. * * Matt O'Gorman <mogorman@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. *//*! \file * * \author Matt O'Gorman <mogorman@digium.com> * * \brief Gtalk Channel Driver, until google/libjingle works with jingle spec * * \ingroup channel_drivers *//*** MODULEINFO <depend>iksemel</depend> <depend>res_jabber</depend> <use>gnutls</use> ***/#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 139283 $")#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <errno.h>#include <stdlib.h>#include <fcntl.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/signal.h>#include <iksemel.h>#include <pthread.h>#ifdef HAVE_GNUTLS#include <gcrypt.h>GCRY_THREAD_OPTION_PTHREAD_IMPL;#endif /* HAVE_GNUTLS */#include "asterisk/lock.h"#include "asterisk/channel.h"#include "asterisk/config.h"#include "asterisk/logger.h"#include "asterisk/module.h"#include "asterisk/pbx.h"#include "asterisk/options.h"#include "asterisk/lock.h"#include "asterisk/sched.h"#include "asterisk/io.h"#include "asterisk/rtp.h"#include "asterisk/acl.h"#include "asterisk/callerid.h"#include "asterisk/file.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/musiconhold.h"#include "asterisk/manager.h"#include "asterisk/stringfields.h"#include "asterisk/utils.h"#include "asterisk/causes.h"#include "asterisk/astobj.h"#include "asterisk/abstract_jb.h"#include "asterisk/jabber.h"#define GOOGLE_CONFIG "gtalk.conf"#define GOOGLE_NS "http://www.google.com/session"/*! Global jitterbuffer configuration - by default, jb is disabled */static struct ast_jb_conf default_jbconf ={ .flags = 0, .max_size = -1, .resync_threshold = -1, .impl = ""};static struct ast_jb_conf global_jbconf;enum gtalk_protocol { AJI_PROTOCOL_UDP = 1, AJI_PROTOCOL_SSLTCP = 2,};enum gtalk_connect_type { AJI_CONNECT_STUN = 1, AJI_CONNECT_LOCAL = 2, AJI_CONNECT_RELAY = 3,};struct gtalk_pvt { ast_mutex_t lock; /*!< Channel private lock */ time_t laststun; struct gtalk *parent; /*!< Parent client */ char sid[100]; char us[AJI_MAX_JIDLEN]; char them[AJI_MAX_JIDLEN]; char ring[10]; /*!< Message ID of ring */ iksrule *ringrule; /*!< Rule for matching RING request */ int initiator; /*!< If we're the initiator */ int alreadygone; int capability; struct ast_codec_pref prefs; struct gtalk_candidate *theircandidates; struct gtalk_candidate *ourcandidates; char cid_num[80]; /*!< Caller ID num */ char cid_name[80]; /*!< Caller ID name */ char exten[80]; /*!< Called extension */ struct ast_channel *owner; /*!< Master Channel */ struct ast_rtp *rtp; /*!< RTP audio session */ struct ast_rtp *vrtp; /*!< RTP video session */ int jointcapability; /*!< Supported capability at both ends (codecs ) */ int peercapability; struct gtalk_pvt *next; /* Next entity */};struct gtalk_candidate { char name[100]; enum gtalk_protocol protocol; double preference; char username[100]; char password[100]; enum gtalk_connect_type type; char network[6]; int generation; char ip[16]; int port; int receipt; struct gtalk_candidate *next;};struct gtalk { ASTOBJ_COMPONENTS(struct gtalk); struct aji_client *connection; struct aji_buddy *buddy; struct gtalk_pvt *p; struct ast_codec_pref prefs; int amaflags; /*!< AMA Flags */ char user[AJI_MAX_JIDLEN]; char context[AST_MAX_CONTEXT]; char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */ int capability; ast_group_t callgroup; /*!< Call group */ ast_group_t pickupgroup; /*!< Pickup group */ int callingpres; /*!< Calling presentation */ int allowguest; char language[MAX_LANGUAGE]; /*!< Default language for prompts */ char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */};struct gtalk_container { ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);};static const char desc[] = "Gtalk Channel";static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;AST_MUTEX_DEFINE_STATIC(gtalklock); /*!< Protect the interface list (of gtalk_pvt's) *//* Forward declarations */static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);static int gtalk_digit_begin(struct ast_channel *ast, char digit);static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);static int gtalk_hangup(struct ast_channel *ast);static int gtalk_answer(struct ast_channel *ast);static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action);static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p);static int gtalk_newcall(struct gtalk *client, ikspak *pak);static struct ast_frame *gtalk_read(struct ast_channel *ast);static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);static int gtalk_do_reload(int fd, int argc, char **argv);static int gtalk_show_channels(int fd, int argc, char **argv);/*----- RTP interface functions */static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);static int gtalk_get_codec(struct ast_channel *chan);/*! \brief PBX interface structure for channel registration */static const struct ast_channel_tech gtalk_tech = { .type = "Gtalk", .description = "Gtalk Channel Driver", .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), .requester = gtalk_request, .send_digit_begin = gtalk_digit_begin, .send_digit_end = gtalk_digit_end, .bridge = ast_rtp_bridge, .call = gtalk_call, .hangup = gtalk_hangup, .answer = gtalk_answer, .read = gtalk_read, .write = gtalk_write, .exception = gtalk_read, .indicate = gtalk_indicate, .fixup = gtalk_fixup, .send_html = gtalk_sendhtml, .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER};static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */static struct sched_context *sched; /*!< The scheduling context */static struct io_context *io; /*!< The IO context */static struct in_addr __ourip;/*! \brief RTP driver interface */static struct ast_rtp_protocol gtalk_rtp = { type: "Gtalk", get_rtp_info: gtalk_get_rtp_peer, set_rtp_peer: gtalk_set_rtp_peer, get_codec: gtalk_get_codec,};static char show_channels_usage[] = "Usage: gtalk show channels\n" " Shows current state of the Gtalk channels.\n";static char reload_usage[] = "Usage: gtalk reload\n" " Reload gtalk channel driver.\n";static struct ast_cli_entry gtalk_cli[] = { {{ "gtalk", "reload", NULL}, gtalk_do_reload, "Reload GoogleTalk configuration", reload_usage }, {{ "gtalk", "show", "channels", NULL}, gtalk_show_channels, "Show GoogleTalk channels", show_channels_usage }, };static char externip[16];static struct gtalk_container gtalk_list;static void gtalk_member_destroy(struct gtalk *obj){ free(obj);}static struct gtalk *find_gtalk(char *name, char *connection){ struct gtalk *gtalk = NULL; char *domain = NULL , *s = NULL; if(strchr(connection, '@')) { s = ast_strdupa(connection); domain = strsep(&s, "@"); ast_verbose("OOOOH domain = %s\n", domain); } gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name); if (!gtalk && strchr(name, '@')) gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp); if (!gtalk) { /* guest call */ ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { ASTOBJ_RDLOCK(iterator); if (!strcasecmp(iterator->name, "guest")) { gtalk = iterator; } ASTOBJ_UNLOCK(iterator); if (gtalk) break; }); } return gtalk;}static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs){ int res = 0; char *format = ast_getformatname(codec); if (!strcasecmp("ulaw", format)) { iks *payload_eg711u, *payload_pcmu; payload_pcmu = iks_new("payload-type"); payload_eg711u = iks_new("payload-type"); if(!payload_eg711u || !payload_pcmu) { if(payload_pcmu) iks_delete(payload_pcmu); if(payload_eg711u) iks_delete(payload_eg711u); ast_log(LOG_WARNING,"Failed to allocate iks node"); return -1; } iks_insert_attrib(payload_pcmu, "id", "0"); iks_insert_attrib(payload_pcmu, "name", "PCMU"); iks_insert_attrib(payload_pcmu, "clockrate","8000"); iks_insert_attrib(payload_pcmu, "bitrate","64000"); iks_insert_attrib(payload_eg711u, "id", "100"); iks_insert_attrib(payload_eg711u, "name", "EG711U"); iks_insert_attrib(payload_eg711u, "clockrate","8000"); iks_insert_attrib(payload_eg711u, "bitrate","64000"); iks_insert_node(dcodecs, payload_pcmu); iks_insert_node(dcodecs, payload_eg711u); res ++; } if (!strcasecmp("alaw", format)) { iks *payload_eg711a, *payload_pcma; payload_pcma = iks_new("payload-type"); payload_eg711a = iks_new("payload-type"); if(!payload_eg711a || !payload_pcma) { if(payload_eg711a) iks_delete(payload_eg711a); if(payload_pcma) iks_delete(payload_pcma); ast_log(LOG_WARNING,"Failed to allocate iks node"); return -1; } iks_insert_attrib(payload_pcma, "id", "8"); iks_insert_attrib(payload_pcma, "name", "PCMA"); iks_insert_attrib(payload_pcma, "clockrate","8000"); iks_insert_attrib(payload_pcma, "bitrate","64000"); payload_eg711a = iks_new("payload-type"); iks_insert_attrib(payload_eg711a, "id", "101"); iks_insert_attrib(payload_eg711a, "name", "EG711A"); iks_insert_attrib(payload_eg711a, "clockrate","8000"); iks_insert_attrib(payload_eg711a, "bitrate","64000"); iks_insert_node(dcodecs, payload_pcma); iks_insert_node(dcodecs, payload_eg711a); res ++; } if (!strcasecmp("ilbc", format)) { iks *payload_ilbc = iks_new("payload-type"); if(!payload_ilbc) { ast_log(LOG_WARNING,"Failed to allocate iks node"); return -1; } iks_insert_attrib(payload_ilbc, "id", "97"); iks_insert_attrib(payload_ilbc, "name", "iLBC"); iks_insert_attrib(payload_ilbc, "clockrate","8000"); iks_insert_attrib(payload_ilbc, "bitrate","13300"); iks_insert_node(dcodecs, payload_ilbc); res ++; } if (!strcasecmp("g723", format)) { iks *payload_g723 = iks_new("payload-type"); if(!payload_g723) { ast_log(LOG_WARNING,"Failed to allocate iks node"); return -1; } iks_insert_attrib(payload_g723, "id", "4"); iks_insert_attrib(payload_g723, "name", "G723"); iks_insert_attrib(payload_g723, "clockrate","8000"); iks_insert_attrib(payload_g723, "bitrate","6300"); iks_insert_node(dcodecs, payload_g723); res ++; } if (!strcasecmp("speex", format)) { iks *payload_speex = iks_new("payload-type"); if(!payload_speex) { ast_log(LOG_WARNING,"Failed to allocate iks node"); return -1; } iks_insert_attrib(payload_speex, "id", "110"); iks_insert_attrib(payload_speex, "name", "speex"); iks_insert_attrib(payload_speex, "clockrate","8000"); iks_insert_attrib(payload_speex, "bitrate","11000"); iks_insert_node(dcodecs, payload_speex); res++; } if (!strcasecmp("gsm", format)) { iks *payload_gsm = iks_new("payload-type"); if(!payload_gsm) { ast_log(LOG_WARNING,"Failed to allocate iks node"); return -1; } iks_insert_attrib(payload_gsm, "id", "103"); iks_insert_attrib(payload_gsm, "name", "gsm"); iks_insert_node(dcodecs, payload_gsm); res++; } ast_rtp_lookup_code(p->rtp, 1, codec); return res;}static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator){ struct gtalk *client = p->parent; iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport; int x; int pref_codec = 0; int alreadysent = 0; int codecs_num = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -