[asterisk-commits] jdixon: branch jdixon/chan_usbradio-1.4 r140411 - /team/jdixon/chan_usbradio-...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Aug 28 20:45:02 CDT 2008
Author: jdixon
Date: Thu Aug 28 20:45:01 2008
New Revision: 140411
URL: http://svn.digium.com/view/asterisk?view=rev&rev=140411
Log:
Added chan_echolink to main SVN
Added:
team/jdixon/chan_usbradio-1.4/channels/chan_echolink.c (with props)
Added: team/jdixon/chan_usbradio-1.4/channels/chan_echolink.c
URL: http://svn.digium.com/view/asterisk/team/jdixon/chan_usbradio-1.4/channels/chan_echolink.c?view=auto&rev=140411
==============================================================================
--- team/jdixon/chan_usbradio-1.4/channels/chan_echolink.c (added)
+++ team/jdixon/chan_usbradio-1.4/channels/chan_echolink.c Thu Aug 28 20:45:01 2008
@@ -1,0 +1,2404 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Copyright (C) 2008, Scott Lawson/KI4LKF
+ * ScottLawson/KI4LKF <ham44865 at yahoo.com>
+ * Jim Dixon, WB6NIL <jim at lambdatel.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
+ *
+ * \brief Echolink channel driver for Asterisk
+ *
+ * \author Scott Lawson/KI4LKF <ham44865 at yahoo.com>
+ * \author Jim Dixon, WB6NIL <jim at lambdatel.com>
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+ <depend>zlib</depend>
+ ***/
+
+/* Version 0.14, 08/27/2008
+Echolink channel driver for Asterisk/app_rpt.
+A lot more has to be added,
+Here is what comes to mind first:
+
+---> does not send its station info.
+---> does not process chat text.
+---> recognizes a few remote text commands.
+---> no busy, deaf or mute.
+---> no capacity limits.
+---> no banned or privare station list.
+---> no admin list, only local 127.0.0.1 access.
+---> no welcome text message.
+---> no login or connect timeouts.
+---> no max TX time limit.
+---> no activity reporting.
+---> no event notififications.
+---> no stats.
+---> no callsign prefix restrictions.
+---> no announcements on connects/disconnects.
+---> no loop detection.
+---> allows "doubles"
+
+Otherwise it works as an Echolink conference and it
+will accept multiple station connects.
+It also detects disconnect requests and
+removes dead stations on heartbeat timeouts.
+Default ports are 5198,5199.
+
+Remote text commands thru netcat:
+o.conip <IPaddress> (request a connect)
+o.dconip <IPaddress> (request a disconnect)
+o.rec (turn on/off recording)
+
+It is invoked as echolink/identifier (like el0 for example)
+Example:
+Under a node stanza in rpt.conf,
+rxchannel=echolink/el0
+
+The el0 or whatever you put there must match the stanza in the
+echolink.conf file.
+
+If the linux box is protected by a NAT router,
+leave the IP address as 0.0.0.0,
+do not use 127.0.0.1
+
+*/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <search.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+
+#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/utils.h"
+#include "asterisk/app.h"
+#include "asterisk/dsp.h"
+#include "asterisk/translate.h"
+#include "asterisk/astdb.h"
+
+#define MAX_RXKEY_TIME 4
+
+/* 50 * 10 * 20ms iax2 = 10,000ms = 10 seconds heartbeat */
+#define KEEPALIVE_TIME 50 * 10
+#define BLOCKING_FACTOR 4
+#define GSM_FRAME_SIZE 33
+#define QUEUE_OVERLOAD_THRESHOLD_AST 25
+#define QUEUE_OVERLOAD_THRESHOLD_EL 20
+
+#define EL_IP_SIZE 15
+#define EL_CALL_SIZE 15
+#define EL_NAME_SIZE 31
+#define EL_PWD_SIZE 15
+#define EL_EMAIL_SIZE 31
+#define EL_QTH_SIZE 31
+#define EL_MAX_SERVERS 3
+#define EL_SERVERNAME_SIZE 63
+#define EL_MAX_INSTANCES 100
+
+/*
+ If you want to compile/link this code
+ on "BIG-ENDIAN" platforms, then
+ use this: #define RTP_BIG_ENDIAN
+ Have only tested this code on "little-endian"
+ platforms running Linux.
+*/
+
+static const char tdesc[] = "Echolink channel driver by KI4LKF";
+static int prefformat = AST_FORMAT_GSM;
+static char type[] = "echolink";
+static char db_active = 'a';
+static char db_loading = 0;
+static char snapshot_id[50] = {'0',0};
+static int el_net_get_index = 0;
+static int el_net_get_nread = 0;
+
+
+/* Echolink audio packet heafer */
+struct gsmVoice_t {
+#ifdef RTP_BIG_ENDIAN
+ uint8_t version:2;
+ uint8_t pad:1;
+ uint8_t ext:1;
+ uint8_t csrc:4;
+ uint8_t marker:1;
+ uint8_t payt:7;
+#else
+ uint8_t csrc:4;
+ uint8_t ext:1;
+ uint8_t pad:1;
+ uint8_t version:2;
+ uint8_t payt:7;
+ uint8_t marker:1;
+#endif
+ uint16_t seqnum;
+ uint32_t time;
+ uint32_t ssrc;
+ unsigned char data[BLOCKING_FACTOR * GSM_FRAME_SIZE];
+};
+
+struct el_instance;
+struct el_pvt;
+
+/* Echolink node details */
+/* Also each node in binary tree in memory */
+struct el_node {
+ char ip[EL_IP_SIZE + 1];
+ char call[EL_CALL_SIZE + 1];
+ char name[EL_NAME_SIZE + 1];
+ unsigned int nodenum; /* not used yet */
+ short countdown;
+ uint16_t seqnum;
+ struct el_instance *instp;
+ struct el_pvt *p;
+ struct ast_channel *chan;
+};
+
+struct el_instance
+{
+ ast_mutex_t lock;
+ char name[EL_NAME_SIZE + 1];
+ char mycall[EL_CALL_SIZE + 1];
+ char myname[EL_NAME_SIZE + 1];
+ char mypwd[EL_PWD_SIZE + 1];
+ char myemail[EL_EMAIL_SIZE + 1];
+ char myqth[EL_QTH_SIZE + 1];
+ char elservers[EL_MAX_SERVERS][EL_SERVERNAME_SIZE + 1];
+ char ipaddr[EL_IP_SIZE + 1];
+ char port[EL_IP_SIZE + 1];
+ char astnode[EL_NAME_SIZE + 1];
+ char context[EL_NAME_SIZE + 1];
+ int maxstns;
+ /* missed 10 heartbeats, you're out */
+ short rtcptimeout;
+ unsigned int mynode;
+ char fdr_file[FILENAME_MAX];
+ int audio_sock;
+ int ctrl_sock;
+ uint16_t audio_port;
+ uint16_t ctrl_port;
+ int fdr;
+ unsigned long seqno;
+ int confmode;
+ struct el_pvt *confp;
+ struct gsmVoice_t audio_all_but_one;
+ struct gsmVoice_t audio_all;
+ struct el_node el_node_test;
+
+} ;
+
+struct el_rxqast {
+ struct el_rxqast *qe_forw;
+ struct el_rxqast *qe_back;
+ char buf[GSM_FRAME_SIZE];
+};
+
+struct el_rxqel {
+ struct el_rxqel *qe_forw;
+ struct el_rxqel *qe_back;
+ char buf[BLOCKING_FACTOR * GSM_FRAME_SIZE];
+ char fromip[EL_IP_SIZE + 1];
+};
+
+struct el_pvt {
+ struct ast_channel *owner;
+ struct el_instance *instp;
+ char app[16];
+ char stream[80];
+ char ip[EL_IP_SIZE + 1];
+ char txkey;
+ int rxkey;
+ int keepalive;
+ struct ast_frame fr;
+ int txindex;
+ struct el_rxqast rxqast;
+ struct el_rxqel rxqel;
+ char firstsent;
+ char firstheard;
+ struct ast_dsp *dsp;
+ struct ast_module_user *u;
+ struct ast_trans_pvt *xpath;
+ unsigned int nodenum;
+};
+
+struct rtcp_sdes_request_item {
+ unsigned char r_item;
+ char *r_text;
+};
+
+struct rtcp_sdes_request {
+ int nitems;
+ unsigned char ssrc[4];
+ struct rtcp_sdes_request_item item[10];
+};
+
+struct rtcp_common_t {
+#ifdef RTP_BIG_ENDIAN
+ uint8_t version:2;
+ uint8_t p:1;
+ uint8_t count:5;
+#else
+ uint8_t count:5;
+ uint8_t p:1;
+ uint8_t version:2;
+#endif
+ uint8_t pt:8;
+ uint16_t length;
+};
+
+struct rtcp_sdes_item_t {
+ uint8_t type;
+ uint8_t length;
+ char data[1];
+};
+
+struct rtcp_t {
+ struct rtcp_common_t common;
+ union {
+ struct {
+ uint32_t src[1];
+ } bye;
+
+ struct rtcp_sdes_t {
+ uint32_t src;
+ struct rtcp_sdes_item_t item[1];
+ } sdes;
+ } r;
+};
+
+int debug = 0;
+struct el_instance *instances[EL_MAX_INSTANCES];
+int ninstances = 0;
+
+/* binary search tree in memory, root node */
+static void *el_node_list = NULL;
+
+/* Echolink registration thread */
+static pthread_t el_register_thread;
+static pthread_t el_reader_thread;
+static pthread_t el_directory_thread;
+static int run_forever = 1;
+
+static char *config = "echolink.conf";
+
+#ifdef OLD_ASTERISK
+#define ast_free free
+#define ast_malloc malloc
+#endif
+
+static struct ast_channel *el_request(const char *type, int format, void *data, int *cause);
+static int el_call(struct ast_channel *ast, char *dest, int timeout);
+static int el_hangup(struct ast_channel *ast);
+static struct ast_frame *el_xread(struct ast_channel *ast);
+static int el_xwrite(struct ast_channel *ast, struct ast_frame *frame);
+static int el_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen);
+static int el_digit_begin(struct ast_channel *c, char digit);
+static int el_digit_end(struct ast_channel *c, char digit, unsigned int duratiion);
+static int el_text(struct ast_channel *c, const char *text);
+
+static int rtcp_make_sdes(unsigned char *pkt, int pktLen, char *call, char *name);
+static int rtcp_make_bye(unsigned char *p, char *reason);
+static void parse_sdes(unsigned char *packet, struct rtcp_sdes_request *r);
+static void copy_sdes_item(char *source, char *dest, int destlen);
+static int is_rtcp_bye(unsigned char *p, int len);
+static int is_rtcp_sdes(unsigned char *p, int len);
+ /* remove binary tree functions if Asterisk has similar functionality */
+static int compare_ip(const void *pa, const void *pb);
+static void send_audio_all_but_one(const void *nodep, const VISIT which, const int depth);
+static void send_audio_all(const void *nodep, const VISIT which, const int depth);
+static void send_heartbeat(const void *nodep, const VISIT which, const int depth);
+static void print_users(const void *nodep, const VISIT which, const int depth);
+static void free_node(void *nodep);
+static void process_cmd(char *buf,char *fromip,struct el_instance *instp);
+static int find_delete(struct el_node *key);
+static int sendcmd(char *server,struct el_instance *instp);
+static int do_new_call(struct el_instance *instp, struct el_pvt *p, char *call, char *name);
+
+/* remove writen if Asterisk has similar functionality */
+static int writen(int fd, char *ptr, int nbytes);
+
+static const struct ast_channel_tech el_tech = {
+ .type = type,
+ .description = tdesc,
+ .capabilities = AST_FORMAT_GSM,
+ .requester = el_request,
+ .call = el_call,
+ .hangup = el_hangup,
+ .read = el_xread,
+ .write = el_xwrite,
+ .indicate = el_indicate,
+ .send_text = el_text,
+ .send_digit_begin = el_digit_begin,
+ .send_digit_end = el_digit_end,
+};
+
+static int rtcp_make_sdes(unsigned char *pkt, int pktLen, char *call, char *name)
+{
+ unsigned char zp[1500];
+ unsigned char *p = zp;
+ struct rtcp_t *rp;
+ unsigned char *ap;
+ char line[EL_CALL_SIZE + EL_NAME_SIZE + 1];
+ int l, hl, pl;
+
+ hl = 0;
+ *p++ = 3 << 6;
+ *p++ = 201;
+ *p++ = 0;
+ *p++ = 1;
+ *((long *) p) = htonl(0);
+ p += 4;
+ hl = 8;
+
+ rp = (struct rtcp_t *) p;
+ *((short *) p) = htons((3 << 14) | 202 | (1 << 8));
+ rp->r.sdes.src = htonl(0);
+ ap = (unsigned char *) rp->r.sdes.item;
+
+ strncpy(line,"CALLSIGN",EL_CALL_SIZE + EL_NAME_SIZE);
+ *ap++ = 1;
+ *ap++ = l = strlen(line);
+ memcpy(ap,line,l);
+ ap += l;
+
+ snprintf(line,EL_CALL_SIZE + EL_NAME_SIZE,"%s %s",call,name);
+ *ap++ = 2;
+ *ap++ = l = strlen(line);
+ memcpy(ap,line,l);
+ ap += l;
+
+ /* enable DTMF keypad */
+ *ap++ = 8;
+ *ap++ = 3;
+ *ap++ = 1;
+ *ap++ = 'D';
+ *ap++ = '1';
+
+ *ap++ = 0;
+ *ap++ = 0;
+ l = ap - p;
+
+ rp->common.length = htons(((l + 3) / 4) - 1);
+ l = hl + ((ntohs(rp->common.length) + 1) * 4);
+
+ pl = (l & 4) ? l : l + 4;
+
+ if (pl > l) {
+ int pad = pl - l;
+ memset(zp + l, '\0', pad);
+ zp[pl - 1] = pad;
+ p[0] |= 0x20;
+ rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
+ l = pl;
+ }
+
+ if (l > pktLen)
+ return 0;
+ memcpy(pkt,zp,l);
+ return l;
+}
+
+static int rtcp_make_bye(unsigned char *p, char *reason)
+{
+ struct rtcp_t *rp;
+ unsigned char *ap, *zp;
+ int l, hl, pl;
+
+ zp = p;
+ hl = 0;
+
+ *p++ = 3 << 6;
+ *p++ = 201;
+ *p++ = 0;
+ *p++ = 1;
+ *((long *) p) = htonl(0);
+ p += 4;
+ hl = 8;
+
+ rp = (struct rtcp_t *)p;
+ *((short *) p) = htons((3 << 14) | 203 | (1 << 8));
+ rp->r.bye.src[0] = htonl(0);
+ ap = (unsigned char *) rp->r.sdes.item;
+ l = 0;
+ if (reason != NULL) {
+ l = strlen(reason);
+ if (l > 0) {
+ *ap++ = l;
+ memcpy(ap,reason,l);
+ ap += l;
+ }
+ }
+ while ((ap - p) & 3)
+ *ap++ = 0;
+ l = ap - p;
+ rp->common.length = htons((l / 4) - 1);
+ l = hl + ((ntohs(rp->common.length) + 1) * 4);
+
+ pl = (l & 4) ? l : l + 4;
+ if (pl > l) {
+ int pad = pl - l;
+ memset(zp + l, '\0', pad);
+ zp[pl - 1] = pad;
+ p[0] |= 0x20;
+ rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
+ l = pl;
+ }
+ return l;
+}
+
+static void parse_sdes(unsigned char *packet, struct rtcp_sdes_request *r)
+{
+ int i;
+ unsigned char *p = packet;
+
+ for (i = 0; i < r->nitems; i++)
+ r->item[i].r_text = NULL;
+
+ while ((p[0] >> 6 & 3) == 3 || (p[0] >> 6 & 3) == 1) {
+ if ((p[1] == 202) && ((p[0] & 0x1F) > 0)) {
+ unsigned char *cp = p + 8,
+ *lp = cp + (ntohs(*((short *) (p + 2))) + 1) * 4;
+ memcpy(r->ssrc, p + 4, 4);
+ while (cp < lp) {
+ unsigned char itype = *cp;
+ if (itype == 0)
+ break;
+
+ for (i = 0; i < r->nitems; i++) {
+ if (r->item[i].r_item == itype &&
+ r->item[i].r_text == NULL) {
+ r->item[i].r_text = (char *) cp;
+ break;
+ }
+ }
+ cp += cp[1] + 2;
+ }
+ break;
+ }
+ p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+ }
+ return;
+}
+
+static void copy_sdes_item(char *source, char *dest, int destlen)
+{
+ int len = source[1] & 0xFF;
+ if (len > destlen)
+ len = destlen;
+ memcpy(dest,source + 2, len);
+ dest[len] = 0;
+ return;
+}
+
+static int is_rtcp_bye(unsigned char *p, int len)
+{
+ unsigned char *end;
+ int sawbye = 0;
+
+
+ if ((((p[0] >> 6) & 3) != 3 && ((p[0] >> 6) & 3) != 1) ||
+ ((p[0] & 0x20) != 0) ||
+ ((p[1] != 200) && (p[1] != 201)))
+ return 0;
+
+ end = p + len;
+
+ do {
+ if (p[1] == 203)
+ sawbye = 1;
+
+ p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+ } while (p < end && (((p[0] >> 6) & 3) == 3));
+
+ return sawbye;
+}
+
+static int is_rtcp_sdes(unsigned char *p, int len)
+{
+ unsigned char *end;
+ int sawsdes = 0;
+
+ if ((((p[0] >> 6) & 3) != 3 && ((p[0] >> 6) & 3) != 1) ||
+ ((p[0] & 0x20) != 0) ||
+ ((p[1] != 200) && (p[1] != 201)))
+ return 0;
+
+ end = p + len;
+ do {
+ if (p[1] == 202)
+ sawsdes = 1;
+
+ p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+ } while (p < end && (((p[0] >> 6) & 3) == 3));
+
+ return sawsdes;
+}
+
+static int el_call(struct ast_channel *ast, char *dest, int timeout)
+{
+ struct el_pvt *p = ast->tech_pvt;
+ struct el_instance *instp = p->instp;
+ char buf[100];
+
+
+ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+ ast_log(LOG_WARNING, "el_call called on %s, neither down nor reserved\n", ast->name);
+ return -1;
+ }
+ /* When we call, it just works, really, there's no destination... Just
+ ring the phone and wait for someone to answer */
+// if (option_debug)
+ ast_log(LOG_NOTICE, "Calling %s on %s\n", dest, ast->name);
+ if (*dest) /* if number specified */
+ {
+ char *str,*cp;
+
+ str = strdup(dest);
+ cp = strchr(str,'/');
+ if (cp) *cp++ = 0; else cp = str;
+ snprintf(buf,sizeof(buf) - 1,"o.conip %s",cp);
+ free(str);
+ ast_mutex_lock(&instp->lock);
+ strcpy(instp->el_node_test.ip,cp);
+ do_new_call(instp,p,"OUTBOUND","OUTBOUND");
+ process_cmd(buf,"127.0.0.1",instp);
+ ast_mutex_unlock(&instp->lock);
+ }
+ ast_setstate(ast,AST_STATE_RINGING);
+ return 0;
+}
+
+static void el_destroy(struct el_pvt *p)
+{
+ if (p->dsp) ast_dsp_free(p->dsp);
+ if (p->xpath) ast_translator_free_path(p->xpath);
+ ast_module_user_remove(p->u);
+ ast_free(p);
+}
+
+static struct el_pvt *el_alloc(void *data)
+{
+ struct el_pvt *p;
+ int n;
+ /* int flags = 0; */
+ char stream[256];
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(idstr);
+ );
+
+ if (ast_strlen_zero(data)) return NULL;
+
+ AST_STANDARD_APP_ARGS(args,data);
+
+ for(n = 0; n < ninstances; n++)
+ {
+ if (!strcmp(instances[n]->name,args.idstr)) break;
+ }
+ if (n >= ninstances)
+ {
+ ast_log(LOG_NOTICE,"Cannot find echolink channel %s\n",args.idstr);
+ return NULL;
+ }
+
+ p = ast_malloc(sizeof(struct el_pvt));
+ if (p) {
+ memset(p, 0, sizeof(struct el_pvt));
+
+ sprintf(stream,"%s-%lu",args.idstr,instances[n]->seqno++);
+ strcpy(p->stream,stream);
+ p->rxqast.qe_forw = &p->rxqast;
+ p->rxqast.qe_back = &p->rxqast;
+
+ p->rxqel.qe_forw = &p->rxqel;
+ p->rxqel.qe_back = &p->rxqel;
+
+ p->keepalive = KEEPALIVE_TIME;
+ p->instp = instances[n];
+ p->instp->confp = p; /* save for conference mode */
+ if (!p->instp->confmode)
+ {
+ p->dsp = ast_dsp_new();
+ if (!p->dsp)
+ {
+ ast_log(LOG_ERROR,"Cannot get DSP!!\n");
+ return NULL;
+ }
+#ifdef NEW_ASTERISK
+ ast_dsp_set_features(p->dsp,DSP_FEATURE_DIGIT_DETECT);
+ ast_dsp_set_digitmode(p->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF);
+#else
+ ast_dsp_set_features(p->dsp,DSP_FEATURE_DTMF_DETECT);
+ ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_RELAXDTMF);
+#endif
+ p->xpath = ast_translator_build_path(AST_FORMAT_SLINEAR,AST_FORMAT_GSM);
+ if (!p->xpath)
+ {
+ ast_log(LOG_ERROR,"Cannot get translator!!\n");
+ return NULL;
+ }
+ }
+ }
+ return p;
+}
+
+static int el_hangup(struct ast_channel *ast)
+{
+ struct el_pvt *p = ast->tech_pvt;
+ struct el_instance *instp = p->instp;
+ int i,n;
+ unsigned char bye[50];
+ struct sockaddr_in sin;
+
+ if (!instp->confmode)
+ {
+ if (debug) ast_log(LOG_DEBUG,"Sent bye to IP address %s\n",p->ip);
+ ast_mutex_lock(&instp->lock);
+ strcpy(instp->el_node_test.ip,p->ip);
+ find_delete(&instp->el_node_test);
+ ast_mutex_unlock(&instp->lock);
+ n = rtcp_make_bye(bye,"disconnected");
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(p->ip);
+ sin.sin_port = htons(instp->ctrl_port);
+ for (i = 0; i < 20; i++)
+ {
+ sendto(instp->ctrl_sock, bye, n,
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+ }
+ if (option_debug)
+ ast_log(LOG_DEBUG, "el_hangup(%s)\n", ast->name);
+ if (!ast->tech_pvt) {
+ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
+ return 0;
+ }
+ el_destroy(p);
+ ast->tech_pvt = NULL;
+ ast_setstate(ast, AST_STATE_DOWN);
+ return 0;
+}
+
+static int el_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen)
+{
+ struct el_pvt *p = ast->tech_pvt;
+
+ switch (cond) {
+ case AST_CONTROL_RADIO_KEY:
+ p->txkey = 1;
+ break;
+ case AST_CONTROL_RADIO_UNKEY:
+ p->txkey = 0;
+ break;
+ case AST_CONTROL_HANGUP:
+ return -1;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int el_digit_begin(struct ast_channel *ast, char digit)
+{
+ return -1;
+}
+
+static int el_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+ return -1;
+}
+
+static int el_text(struct ast_channel *ast, const char *text)
+{
+ struct el_pvt *p = ast->tech_pvt;
+ char *cmd = NULL,*arg1 = NULL,*arg2 = NULL;
+ char *arg3 = NULL,delim = ' ',*saveptr;
+ char buf[200],*ptr,str[200],*arg4 = NULL;
+
+ strncpy(buf,text,sizeof(buf) - 1);
+ ptr = strchr(buf, (int)'\r');
+ if (ptr) *ptr = '\0';
+ ptr = strchr(buf, (int)'\n');
+ if (ptr) *ptr = '\0';
+ cmd = strtok_r(buf, &delim, &saveptr);
+ if (!cmd)
+ {
+ return 0;
+ }
+
+ arg1 = strtok_r(NULL, &delim, &saveptr);
+ arg2 = strtok_r(NULL, &delim, &saveptr);
+ arg3 = strtok_r(NULL, &delim, &saveptr);
+ arg4 = strtok_r(NULL, &delim, &saveptr);
+
+ if (!strcasecmp(cmd,"D"))
+ {
+ sprintf(str,"3%06u",p->nodenum);
+ /* if not for this one, we cant go any farther */
+ if (strcmp(arg1,str)) return 0;
+ ast_senddigit(ast,*arg4);
+ return 0;
+ }
+ return 0;
+}
+
+static int compare_ip(const void *pa, const void *pb)
+{
+ return strncmp(((struct el_node *)pa)->ip,((struct el_node *)pb)->ip,EL_IP_SIZE);
+}
+
+/* Echolink ---> Echolink */
+void send_audio_all_but_one(const void *nodep, const VISIT which, const int depth)
+{
+ struct sockaddr_in sin;
+ struct el_instance *instp = (*(struct el_node **)nodep)->instp;
+
+ if ((which == leaf) || (which == postorder)) {
+ if (strncmp((*(struct el_node **)nodep)->ip, instp->el_node_test.ip,EL_IP_SIZE) != 0) {
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(instp->audio_port);
+ sin.sin_addr.s_addr = inet_addr((*(struct el_node **)nodep)->ip);
+
+ instp->audio_all_but_one.version = 3;
+ instp->audio_all_but_one.pad = 0;
+ instp->audio_all_but_one.ext = 0;
+ instp->audio_all_but_one.csrc = 0;
+ instp->audio_all_but_one.marker = 0;
+ instp->audio_all_but_one.payt = 3;
+ instp->audio_all_but_one.seqnum = htons((*(struct el_node **)nodep)->seqnum++);
+ instp->audio_all_but_one.time = htonl(0);
+ instp->audio_all_but_one.ssrc = instp->mynode;
+
+ /*
+ ast_log(LOG_NOTICE, "sending to %s(%s)\n",
+ (*(struct el_node **)nodep)->call, (*(struct el_node **)nodep)->ip);
+ */
+
+ sendto(instp->audio_sock, (char *)&instp->audio_all_but_one, sizeof(instp->audio_all_but_one),
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+ }
+}
+
+static void send_audio_only_one(const void *nodep, const VISIT which, const int depth)
+{
+ struct sockaddr_in sin;
+ struct el_instance *instp = (*(struct el_node **)nodep)->instp;
+
+ if ((which == leaf) || (which == postorder)) {
+ if (strncmp((*(struct el_node **)nodep)->ip, instp->el_node_test.ip,EL_IP_SIZE) == 0) {
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(instp->audio_port);
+ sin.sin_addr.s_addr = inet_addr((*(struct el_node **)nodep)->ip);
+
+ instp->audio_all.version = 3;
+ instp->audio_all.pad = 0;
+ instp->audio_all.ext = 0;
+ instp->audio_all.csrc = 0;
+ instp->audio_all.marker = 0;
+ instp->audio_all.payt = 3;
+ instp->audio_all.seqnum = htons((*(struct el_node **)nodep)->seqnum++);
+ instp->audio_all.time = htonl(0);
+ instp->audio_all.ssrc = instp->mynode;
+
+ /*
+ ast_log(LOG_NOTICE, "sending to %s(%s)\n",
+ (*(struct el_node **)nodep)->call, (*(struct el_node **)nodep)->ip);
+ */
+ sendto(instp->audio_sock, (char *)&instp->audio_all, sizeof(instp->audio_all),
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+ }
+}
+
+/* Asterisk ---> Echolink */
+void send_audio_all(const void *nodep, const VISIT which, const int depth)
+{
+ struct sockaddr_in sin;
+ struct el_instance *instp = (*(struct el_node **)nodep)->instp;
+
+ if ((which == leaf) || (which == postorder)) {
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(instp->audio_port);
+ sin.sin_addr.s_addr = inet_addr((*(struct el_node **)nodep)->ip);
+
+ instp->audio_all.version = 3;
+ instp->audio_all.pad = 0;
+ instp->audio_all.ext = 0;
+ instp->audio_all.csrc = 0;
+ instp->audio_all.marker = 0;
+ instp->audio_all.payt = 3;
+ instp->audio_all.seqnum = htons((*(struct el_node **)nodep)->seqnum++);
+ instp->audio_all.time = htonl(0);
+ instp->audio_all.ssrc = instp->mynode;
+
+ /*
+ ast_log(LOG_NOTICE, "sending to %s(%s)\n",
+ (*(struct el_node **)nodep)->call, (*(struct el_node **)nodep)->ip);
+ */
+ sendto(instp->audio_sock, (char *)&instp->audio_all, sizeof(instp->audio_all),
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+}
+
+static void print_users(const void *nodep, const VISIT which, const int depth)
+{
+ if ((which == leaf) || (which == postorder)) {
+ ast_log(LOG_NOTICE,"call=%s,ip=%s,name=%s\n",
+ (*(struct el_node **)nodep)->call,
+ (*(struct el_node **)nodep)->ip,
+ (*(struct el_node **)nodep)->name);
+ }
+}
+
+static void send_heartbeat(const void *nodep, const VISIT which, const int depth)
+{
+ struct sockaddr_in sin;
+ unsigned char sdes_packet[256];
+ int sdes_length;
+ struct el_instance *instp = (*(struct el_node **)nodep)->instp;
+
+ if ((which == leaf) || (which == postorder)) {
+
+ if ((*(struct el_node **)nodep)->countdown >= 0)
+ (*(struct el_node **)nodep)->countdown --;
+
+ if ((*(struct el_node **)nodep)->countdown < 0) {
+ strncpy(instp->el_node_test.ip,(*(struct el_node **)nodep)->ip,EL_IP_SIZE);
+ strncpy(instp->el_node_test.call,(*(struct el_node **)nodep)->call,EL_CALL_SIZE);
+ ast_log(LOG_NOTICE,"countdown for %s(%s) negative\n",instp->el_node_test.call,instp->el_node_test.ip);
+ }
+ memset(sdes_packet,0,sizeof(sdes_packet));
+ sdes_length = rtcp_make_sdes(sdes_packet,sizeof(sdes_packet),
+ instp->mycall,instp->myname);
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(instp->ctrl_port);
+ sin.sin_addr.s_addr = inet_addr((*(struct el_node **)nodep)->ip);
+ sendto(instp->ctrl_sock, sdes_packet, sdes_length,
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+}
+
+static void free_node(void *nodep)
+{
+}
+
+static int find_delete(struct el_node *key)
+{
+ int found = 0;
+ struct el_node **found_key = NULL;
+
+ found_key = (struct el_node **)tfind(key, &el_node_list, compare_ip);
+ if (found_key) {
+ if (debug) ast_log(LOG_DEBUG,"...removing %s(%s)\n", (*found_key)->call, (*found_key)->ip);
+ found = 1;
+ if (!(*found_key)->instp->confmode)
+ ast_softhangup((*found_key)->chan,AST_SOFTHANGUP_DEV);
+ tdelete(key, &el_node_list, compare_ip);
+ }
+ return found;
+}
+
+static void process_cmd(char *buf, char *fromip,struct el_instance *instp)
+{
+ char *cmd = NULL;
+ char *arg1 = NULL;
+ char *arg2 = NULL;
+ char *arg3 = NULL;
+
+ char delim = ' ';
+ char *saveptr;
+ char *ptr;
+ struct sockaddr_in sin;
+ unsigned char pack[256];
+ int pack_length;
+ unsigned short i;
+ struct el_node key;
+
+ if (strncmp(fromip,"127.0.0.1",EL_IP_SIZE) != 0)
+ return;
+ ptr = strchr(buf, (int)'\r');
+ if (ptr)
+ *ptr = '\0';
+ ptr = strchr(buf, (int)'\n');
+ if (ptr)
+ *ptr = '\0';
+
+ /* all commands with no arguments go first */
+
+ if (strcmp(buf,"o.users") == 0) {
+ twalk(el_node_list, print_users);
+ return;
+ }
+
+ if (strcmp(buf, "o.rec") == 0) {
+ if (instp->fdr >= 0) {
+ close(instp->fdr);
+ instp->fdr = -1;
+ ast_log(LOG_NOTICE, "rec stopped\n");
+ }
+ else {
+ instp->fdr = open(instp->fdr_file, O_CREAT | O_WRONLY | O_APPEND | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ if (instp->fdr >= 0)
+ ast_log(LOG_NOTICE, "rec into %s started\n", instp->fdr_file);
+ }
+ return;
+ }
+
+ cmd = strtok_r(buf, &delim, &saveptr);
+ if (!cmd)
+ {
+ return;
+ }
+
+ /* This version: up to 3 parameters */
+ arg1 = strtok_r(NULL, &delim, &saveptr);
+ arg2 = strtok_r(NULL, &delim, &saveptr);
+ arg3 = strtok_r(NULL, &delim, &saveptr);
+
+ if ((strcmp(cmd, "o.conip") == 0) ||
+ (strcmp(cmd, "o.dconip") == 0)) {
+ if (!arg1)
+ {
+ return;
+ }
+
+ if (strcmp(cmd, "o.conip") == 0)
+ pack_length = rtcp_make_sdes(pack,sizeof(pack),instp->mycall,instp->myname);
+ else
+ pack_length = rtcp_make_bye(pack,"bye");
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(instp->ctrl_port);
+ sin.sin_addr.s_addr = inet_addr(arg1);
+
+ if (strcmp(cmd, "o.dconip") == 0) {
+ strncpy(key.ip,arg1,EL_IP_SIZE);
+ if (find_delete(&key)) {
+ for (i = 0; i < 20; i++)
+ sendto(instp->ctrl_sock, pack, pack_length,
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ ast_log(LOG_NOTICE,"disconnect request sent to %s\n",key.ip);
+ }
+ else
+ ast_log(LOG_NOTICE, "Did not find ip=%s to request disconnect\n",key.ip);
+ }
+ else {
+ for (i = 0; i < 20; i++)
+ {
+ sendto(instp->ctrl_sock, pack, pack_length,
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+ ast_log(LOG_NOTICE,"connect request sent to %s\n", arg1);
+ }
+ return;
+ }
+ return;
+}
+
+static struct ast_frame *el_xread(struct ast_channel *ast)
+{
+ struct el_pvt *p = ast->tech_pvt;
+
+ p->fr.frametype = 0;
+ p->fr.subclass = 0;
+ p->fr.datalen = 0;
+ p->fr.samples = 0;
+ p->fr.data = NULL;
+ p->fr.src = type;
+ p->fr.offset = 0;
+ p->fr.mallocd=0;
+ p->fr.delivery.tv_sec = 0;
+ p->fr.delivery.tv_usec = 0;
+ return &p->fr;
+}
+
+static int el_xwrite(struct ast_channel *ast, struct ast_frame *frame)
+{
+ int bye_length;
+ unsigned char bye[50];
+ unsigned short i;
+ struct sockaddr_in sin;
+ struct el_pvt *p = ast->tech_pvt;
+ struct el_instance *instp = p->instp;
+ struct ast_frame fr,*f1, *f2;
+ struct el_rxqast *qpast;
+ int n,m,x;
+ struct el_rxqel *qpel;
+ char buf[GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET];
+
+ if (frame->frametype != AST_FRAME_VOICE) return 0;
+
+ if (!p->firstsent)
+ {
+ struct sockaddr_in sin;
+ unsigned char sdes_packet[256];
+ int sdes_length;
+
+ p->firstsent = 1;
+ memset(sdes_packet,0,sizeof(sdes_packet));
+ sdes_length = rtcp_make_sdes(sdes_packet,sizeof(sdes_packet),
+ instp->mycall,instp->myname);
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(instp->ctrl_port);
+ sin.sin_addr.s_addr = inet_addr(p->ip);
+ sendto(instp->ctrl_sock, sdes_packet, sdes_length,
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ }
+
+ /* Echolink to Asterisk */
+ if (p->rxqast.qe_forw != &p->rxqast) {
+ for(n = 0,qpast = p->rxqast.qe_forw; qpast != &p->rxqast; qpast = qpast->qe_forw) {
+ n++;
+ }
+ if (n > QUEUE_OVERLOAD_THRESHOLD_AST) {
+ while(p->rxqast.qe_forw != &p->rxqast) {
+ qpast = p->rxqast.qe_forw;
+ remque((struct qelem *)qpast);
+ ast_free(qpast);
+ }
+ if (p->rxkey) p->rxkey = 1;
+ } else {
+ if (!p->rxkey) {
+ fr.datalen = 0;
+ fr.samples = 0;
+ fr.frametype = AST_FRAME_CONTROL;
+ fr.subclass = AST_CONTROL_RADIO_KEY;
+ fr.data = 0;
+ fr.src = type;
+ fr.offset = 0;
+ fr.mallocd=0;
+ fr.delivery.tv_sec = 0;
+ fr.delivery.tv_usec = 0;
+ ast_queue_frame(ast,&fr);
+ }
+ p->rxkey = MAX_RXKEY_TIME;
+ qpast = p->rxqast.qe_forw;
+ remque((struct qelem *)qpast);
+ memcpy(buf + AST_FRIENDLY_OFFSET,qpast->buf,GSM_FRAME_SIZE);
+ ast_free(qpast);
+
+ fr.datalen = GSM_FRAME_SIZE;
+ fr.samples = 160;
+ fr.frametype = AST_FRAME_VOICE;
+ fr.subclass = AST_FORMAT_GSM;
+ fr.data = buf + AST_FRIENDLY_OFFSET;
+ fr.src = type;
+ fr.offset = AST_FRIENDLY_OFFSET;
+ fr.mallocd=0;
+ fr.delivery.tv_sec = 0;
+ fr.delivery.tv_usec = 0;
+
+ x = 0;
+ if (p->dsp && (!instp->confmode))
+ {
+ f2 = ast_translate(p->xpath,&fr,0);
+ f1 = ast_dsp_process(NULL,p->dsp,f2);
+ ast_frfree(f2);
+ if ((f1->frametype == AST_FRAME_DTMF_END) ||
+ (f1->frametype == AST_FRAME_DTMF_BEGIN))
+ {
+ if ((f1->subclass != 'm') && (f1->subclass != 'u'))
+ {
+ if (f1->frametype == AST_FRAME_DTMF_END)
+ ast_log(LOG_NOTICE,"Echolink %s Got DTMF char %c from IP %s\n",p->stream,f1->subclass,p->ip);
+ ast_queue_frame(ast,f1);
+ x = 1;
+ }
+ }
+ ast_frfree(f1);
+ }
+ if (!x) ast_queue_frame(ast,&fr);
+ }
+ }
+ if (p->rxkey == 1) {
+ fr.datalen = 0;
+ fr.samples = 0;
+ fr.frametype = AST_FRAME_CONTROL;
+ fr.subclass = AST_CONTROL_RADIO_UNKEY;
+ fr.data = 0;
+ fr.src = type;
+ fr.offset = 0;
+ fr.mallocd=0;
+ fr.delivery.tv_sec = 0;
+ fr.delivery.tv_usec = 0;
+ ast_queue_frame(ast,&fr);
+ }
+ if (p->rxkey) p->rxkey--;
+
+ if (instp->confmode && (p->rxqel.qe_forw != &p->rxqel))
+ {
+ for(m = 0,qpel = p->rxqel.qe_forw; qpel != &p->rxqel; qpel = qpel->qe_forw)
+ m++;
+
+ if (m > QUEUE_OVERLOAD_THRESHOLD_EL)
+ {
+ while(p->rxqel.qe_forw != &p->rxqel)
+ {
+ qpel = p->rxqel.qe_forw;
+ remque((struct qelem *)qpel);
+ ast_free(qpel);
+ }
+ }
+ else
+ {
+ qpel = p->rxqel.qe_forw;
+ remque((struct qelem *)qpel);
+
+ memcpy(instp->audio_all_but_one.data,qpel->buf,BLOCKING_FACTOR * GSM_FRAME_SIZE);
+ strncpy(instp->el_node_test.ip, qpel->fromip, EL_IP_SIZE);
+
+ ast_free(qpel);
+ ast_mutex_lock(&instp->lock);
+ twalk(el_node_list, send_audio_all_but_one);
+ ast_mutex_unlock(&instp->lock);
+
+ if (instp->fdr >= 0)
+ write(instp->fdr, instp->audio_all_but_one.data, BLOCKING_FACTOR * GSM_FRAME_SIZE);
+ }
+ }
+ else
+ {
+ /* Asterisk to Echolink */
+ if (!(frame->subclass & (AST_FORMAT_GSM))) {
+ ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
+ ast_mutex_unlock(&instp->lock);
+ return 0;
+ }
+ if (p->txkey || p->txindex) {
+ memcpy(instp->audio_all.data + (GSM_FRAME_SIZE * p->txindex++), frame->data,GSM_FRAME_SIZE);
+ }
+ if (p->txindex >= BLOCKING_FACTOR) {
+ ast_mutex_lock(&instp->lock);
+ if (instp->confmode)
+ {
+ twalk(el_node_list, send_audio_all);
+ }
+ else
+ {
+ strcpy(instp->el_node_test.ip,p->ip);
+ twalk(el_node_list, send_audio_only_one);
+ }
+ ast_mutex_unlock(&instp->lock);
+ p->txindex = 0;
+ }
+ }
+
+ if (p->keepalive--) return 0;
+ p->keepalive = KEEPALIVE_TIME;
+
+ /* Echolink: send heartbeats and drop dead stations */
+ ast_mutex_lock(&instp->lock);
+ instp->el_node_test.ip[0] = '\0';
+ twalk(el_node_list, send_heartbeat);
+ if (instp->el_node_test.ip[0] != '\0') {
+ if (find_delete(&instp->el_node_test)) {
+ bye_length = rtcp_make_bye(bye,"rtcp timeout");
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(instp->el_node_test.ip);
+ sin.sin_port = htons(instp->ctrl_port);
+ ast_mutex_lock(&instp->lock);
+ for (i = 0; i < 20; i++)
+ sendto(instp->ctrl_sock, bye, bye_length,
+ 0,(struct sockaddr *)&sin,sizeof(sin));
+ ast_mutex_unlock(&instp->lock);
+ ast_log(LOG_NOTICE,"call=%s RTCP timeout, removing\n",instp->el_node_test.call);
+ }
+ instp->el_node_test.ip[0] = '\0';
+ }
+ ast_mutex_unlock(&instp->lock);
+ return 0;
+}
+
+static struct ast_channel *el_new(struct el_pvt *i, int state, unsigned int nodenum)
+{
+ struct ast_channel *tmp;
+ struct el_instance *instp = i->instp;
+
+ tmp = ast_channel_alloc(1, state, 0, 0, "", instp->astnode, instp->context, 0, "echolink/%s", i->stream);
+ if (tmp) {
+ tmp->tech = &el_tech;
+ tmp->nativeformats = prefformat;
+ tmp->rawreadformat = prefformat;
+ tmp->rawwriteformat = prefformat;
+ tmp->writeformat = prefformat;
+ tmp->readformat = prefformat;
+ if (state == AST_STATE_RING)
+ tmp->rings = 1;
+ tmp->tech_pvt = i;
+ ast_copy_string(tmp->context, instp->context, sizeof(tmp->context));
+ ast_copy_string(tmp->exten, instp->astnode, sizeof(tmp->exten));
+ ast_string_field_set(tmp, language, "");
+ if (nodenum > 0)
+ {
+ char tmpstr[30];
+
+ sprintf(tmpstr,"3%06u",nodenum);
+ ast_set_callerid(tmp,tmpstr,NULL,NULL);
+ }
+ i->owner = tmp;
+ i->u = ast_module_user_add(tmp);
+ i->nodenum = nodenum;
+ if (state != AST_STATE_DOWN) {
+ if (ast_pbx_start(tmp)) {
+ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
+ ast_hangup(tmp);
+ }
+ }
+ } else
+ ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+ return tmp;
+}
+
+
+static struct ast_channel *el_request(const char *type, int format, void *data, int *cause)
+{
+ int oldformat,nodenum;
+ struct el_pvt *p;
+ struct ast_channel *tmp = NULL;
+ char *str,*cp;
+
+ oldformat = format;
+ format &= (AST_FORMAT_GSM);
+ if (!format) {
+ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
+ return NULL;
+ }
+ str = strdup((char *)data);
+ cp = strchr(str,'/');
+ if (cp) *cp++ = 0;
+ nodenum = 0;
+ if (*cp && *++cp) nodenum = atoi(cp);
+ p = el_alloc(str);
+ free(str);
+ if (p) {
+ tmp = el_new(p, AST_STATE_DOWN,nodenum);
+ if (!tmp)
+ el_destroy(p);
+ }
+ return tmp;
+}
+
+static int unload_module(void)
+{
+int n;
+
+ run_forever = 0;
+ tdestroy(el_node_list, free_node);
+ for(n = 0; n < ninstances; n++)
+ {
+ if (instances[n]->audio_sock != -1)
+ {
+ close(instances[n]->audio_sock);
+ instances[n]->audio_sock = -1;
+ }
+ if (instances[n]->ctrl_sock != -1)
+ {
+ close(instances[n]->ctrl_sock);
+ instances[n]->ctrl_sock = -1;
+ }
+ }
+ /* First, take us out of the channel loop */
+ ast_channel_unregister(&el_tech);
+ for(n = 0; n < ninstances; n++) ast_free(instances[n]);
+ return 0;
+}
+
+/*
+ If asterisk has a function that writes at least n bytes to a TCP socket,
+ remove writen function and use the one provided by Asterisk
+*/
+static int writen(int fd, char *ptr, int nbytes)
+{
+ int nleft, nwritten;
+ char *local_ptr;
+
+ nleft = nbytes;
+ local_ptr = ptr;
+
+ while (nleft > 0)
+ {
+ nwritten = write(fd, local_ptr, nleft);
+ if (nwritten < 0)
+ return nwritten;
+ nleft -= nwritten;
+ local_ptr += nwritten;
+ }
+ return (nbytes - nleft);
+}
+
+/* Feel free to make this code smaller, I know it works, so I use it */
+static int sendcmd(char *server, struct el_instance *instp)
+{
+ struct hostent *ahp;
+ struct ast_hostent ah;
+ struct in_addr ia;
+
+ char ip[EL_IP_SIZE + 1];
+ struct sockaddr_in el;
+ int el_len;
+ int sd;
+ int rc;
+ time_t now;
+ struct tm *p_tm;
+ char *id = NULL;
+ const size_t LOGINSIZE = 1023;
+ char buf[LOGINSIZE + 1];
+ size_t len;
+
+ ahp = ast_gethostbyname(server,&ah);
+ if (ahp) {
+ memcpy(&ia,ahp->h_addr,sizeof(in_addr_t));
+#ifdef OLD_ASTERISK
+ ast_inet_ntoa(ip,EL_IP_SIZE,ia);
+#else
+ strncpy(ip,ast_inet_ntoa(ia),EL_IP_SIZE);
+#endif
+ } else {
+ ast_log(LOG_NOTICE, "Failed to resolve Echolink server %s\n", server);
+ return -1;
+ }
+
+ memset(&el,0,sizeof(struct sockaddr_in));
+ el.sin_family = AF_INET;
+ el.sin_port = htons(5200);
+ el.sin_addr.s_addr = inet_addr(ip);
+ el_len = sizeof(el);
+
[... 1014 lines stripped ...]
More information about the asterisk-commits
mailing list