Added in contrib the libiax2 modified by Diana - now required for iaxchan.

git-svn-id: http://yate.null.ro/svn/yate/trunk@30 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2004-09-05 23:36:41 +00:00
parent 7c853174bf
commit fe6063f045
15 changed files with 4173 additions and 21 deletions

View File

@ -53,6 +53,7 @@ clean:
-rm $(CLEANS) 2>/dev/null
$(MAKE) -C ./modules $@
$(MAKE) -C ./test $@
$(MAKE) -C ./contrib/iax $@
.PHONY: engine
engine: tables yatepaths.h $(LIBS) $(SLIBS) $(PROGS)

View File

@ -215,7 +215,19 @@ AC_SUBST(GLIB2_LIB)
HAVE_IAX2=no
IAX2_INC=""
IAX2_LIB=""
AC_ARG_WITH(libIAX2,AC_HELP_STRING([--with-libiax2=DIR],[use IAX 2 from DIR (default /usr)]),[ac_cv_use_libiax2=$withval],[ac_cv_use_libiax2=yes])
IAX2_DEP=""
AC_ARG_WITH(libIAX2,AC_HELP_STRING([--with-libiax2=DIR],[use IAX 2 from DIR (default: included)]),[ac_cv_use_libiax2=$withval],[ac_cv_use_libiax2=included])
if [[ "x$ac_cv_use_libiax2" = "xincluded" ]]; then
AC_MSG_CHECKING([for IAX 2 in contrib])
inci2="contrib/iax"
if [[ -f "$inci2/iax2.h" ]]; then
HAVE_IAX2=yes
IAX2_INC="-I../$inci2"
IAX2_DEP="../$inci2/libiax.a"
ac_cv_use_libiax2="no"
fi
AC_MSG_RESULT([$HAVE_IAX2])
fi
if [[ "x$ac_cv_use_libiax2" = "xyes" ]]; then
AC_MSG_CHECKING([for IAX 2 using iax-config])
veri2=`iax-config --version 2>/dev/null`
@ -246,6 +258,7 @@ fi
AC_SUBST(HAVE_IAX2)
AC_SUBST(IAX2_INC)
AC_SUBST(IAX2_LIB)
AC_SUBST(IAX2_DEP)
HAVE_GTK=no
GTK_INC=""
@ -278,6 +291,7 @@ AC_CONFIG_FILES([yate.spec
Makefile
modules/Makefile
conf.d/Makefile
contrib/iax/Makefile
test/Makefile])
AC_CONFIG_FILES([yate-config],[chmod +x yate-config])
AC_CONFIG_FILES([run],[chmod +x run])

7
contrib/iax/.cvsignore Normal file
View File

@ -0,0 +1,7 @@
Makefile
core*
*.o
*.a
*.orig
*~
.*.swp

44
contrib/iax/Makefile.in Normal file
View File

@ -0,0 +1,44 @@
# Makefile
# This file holds the make rules for the libiax2 - Yate version
CC := gcc -Wall
AR := ar
RANLIB:= ranlib
SED := sed
DEFS :=
INCLUDES := -I@top_srcdir@
CFLAGS := -O2 -DDEBUG_SUPPORT -DLIBIAX -fsigned-char
LDFLAGS:=
PROGS=
LIBS = libiax.a
OBJS = iax2-parser.o iax.o md5.o
LOCALFLAGS =
LOCALLIBS =
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CFLAGS)
LINK = $(CC) $(LDFLAGS)
prefix = @prefix@
exec_prefix = @exec_prefix@
.PHONY: all
all: $(LIBS) $(PROGS)
.PHONY: strip
strip: all
strip --strip-debug --discard-locals $(PROGS)
.PHONY: clean
clean:
@-rm $(PROGS) $(LIBS) $(OBJS) core 2>/dev/null
%.o: @srcdir@/%.c
$(COMPILE) -c $<
Makefile: @srcdir@/Makefile.in ../../config.status
cd ../.. && ./config.status
libiax.a: $(OBJS)
$(AR) rcs $@ $^
$(RANLIB) $@

114
contrib/iax/frame.h Normal file
View File

@ -0,0 +1,114 @@
/*
* libiax: An implementation of the Inter-Asterisk eXchange protocol
*
* Asterisk internal frame definitions.
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU Lesser General Public License. Other components of
* Asterisk are distributed under The GNU General Public License
* only.
*/
#ifndef _LIBIAX_FRAME_H
#define _LIBIAX_FRAME_H
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Frame types */
#define AST_FRAME_DTMF 1 /* A DTMF digit, subclass is the digit */
#define AST_FRAME_VOICE 2 /* Voice data, subclass is AST_FORMAT_* */
#define AST_FRAME_VIDEO 3 /* Video frame, maybe?? :) */
#define AST_FRAME_CONTROL 4 /* A control frame, subclass is AST_CONTROL_* */
#define AST_FRAME_NULL 5 /* An empty, useless frame */
#define AST_FRAME_IAX 6 /* Inter Aterisk Exchange private frame type */
#define AST_FRAME_TEXT 7 /* Text messages */
#define AST_FRAME_IMAGE 8 /* Image Frames */
#define AST_FRAME_HTML 9 /* HTML Frames */
/* HTML subclasses */
#define AST_HTML_URL 1 /* Sending a URL */
#define AST_HTML_DATA 2 /* Data frame */
#define AST_HTML_BEGIN 4 /* Beginning frame */
#define AST_HTML_END 8 /* End frame */
#define AST_HTML_LDCOMPLETE 16 /* Load is complete */
#define AST_HTML_NOSUPPORT 17 /* Peer is unable to support HTML */
#define AST_HTML_LINKURL 18 /* Send URL and track */
#define AST_HTML_UNLINK 19 /* Request no more linkage */
#define AST_HTML_LINKREJECT 20 /* Reject LINKURL */
/* Data formats for capabilities and frames alike */
#define AST_FORMAT_G723_1 (1 << 0) /* G.723.1 compression */
#define AST_FORMAT_GSM (1 << 1) /* GSM compression */
#define AST_FORMAT_ULAW (1 << 2) /* Raw mu-law data (G.711) */
#define AST_FORMAT_ALAW (1 << 3) /* Raw A-law data (G.711) */
#define AST_FORMAT_MP3 (1 << 4) /* MPEG-2 layer 3 */
#define AST_FORMAT_ADPCM (1 << 5) /* ADPCM (whose?) */
#define AST_FORMAT_SLINEAR (1 << 6) /* Raw 16-bit Signed Linear (8000 Hz) PCM */
#define AST_FORMAT_LPC10 (1 << 7) /* LPC10, 180 samples/frame */
#define AST_FORMAT_G729A (1 << 8) /* G.729a Audio */
#define AST_FORMAT_MAX_AUDIO (1 << 15) /* Maximum audio format */
#define AST_FORMAT_JPEG (1 << 16) /* JPEG Images */
#define AST_FORMAT_PNG (1 << 17) /* PNG Images */
#define AST_FORMAT_H261 (1 << 18) /* H.261 Video */
#define AST_FORMAT_H263 (1 << 19) /* H.263 Video */
/* Control frame types */
#define AST_CONTROL_HANGUP 1 /* Other end has hungup */
#define AST_CONTROL_RING 2 /* Local ring */
#define AST_CONTROL_RINGING 3 /* Remote end is ringing */
#define AST_CONTROL_ANSWER 4 /* Remote end has answered */
#define AST_CONTROL_BUSY 5 /* Remote end is busy */
#define AST_CONTROL_TAKEOFFHOOK 6 /* Make it go off hook */
#define AST_CONTROL_OFFHOOK 7 /* Line is off hook */
#define AST_CONTROL_CONGESTION 8 /* Congestion (circuits busy) */
#define AST_CONTROL_FLASH 9 /* Flash hook */
#define AST_CONTROL_WINK 10 /* Wink */
#define AST_CONTROL_OPTION 11 /* Set an option */
#define AST_FRIENDLY_OFFSET 64 /* Reserved header space */
struct ast_frame {
/*! Kind of frame */
int frametype;
/*! Subclass, frame dependent */
int subclass;
/*! Length of data */
int datalen;
/*! Number of 8khz samples in this frame */
int samples;
/*! Was the data malloc'd? i.e. should we free it when we discard the f
rame? */
int mallocd;
/*! How far into "data" the data really starts */
int offset;
/*! Optional source of frame for debugging */
char *src;
/*! Pointer to actual data */
void *data;
/*! Next/Prev for linking stand alone frames */
struct ast_frame *prev;
/*! Next/Prev for linking stand alone frames */
struct ast_frame *next;
/* Unused except
if debugging is turned on, but left
in the struct
so that it can be turned on without
requiring a r
ecompile of the whole thing */
};
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

254
contrib/iax/iax-client.h Normal file
View File

@ -0,0 +1,254 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Implementation of Inter-Asterisk eXchange
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU Lesser General Public License (LGPL)
*/
#ifndef _ASTERISK_IAX_CLIENT_H
#define _ASTERISK_IAX_CLIENT_H
#ifndef LINUX
#define socklen_t int
#endif
#include "frame.h"
#include "iax2.h"
#include "iax2-parser.h"
#define MAXSTRLEN 80
#define IAX_AUTHMETHOD_PLAINTEXT IAX_AUTH_PLAINTEXT
#define IAX_AUTHMETHOD_MD5 IAX_AUTH_MD5
extern char iax_errstr[];
#define IAX_EVENT_CONNECT 0 /* Connect a new call */
#define IAX_EVENT_ACCEPT 1 /* Accept a call */
#define IAX_EVENT_HANGUP 2 /* Hang up a call */
#define IAX_EVENT_REJECT 3 /* Rejected call */
#define IAX_EVENT_VOICE 4 /* Voice Data */
#define IAX_EVENT_DTMF 5 /* A DTMF Tone */
#define IAX_EVENT_TIMEOUT 6 /* Connection timeout... session will be
a pointer to free()'d memory! */
#define IAX_EVENT_LAGRQ 7 /* Lag request -- Internal use only */
#define IAX_EVENT_LAGRP 8 /* Lag Measurement. See event.lag */
#define IAX_EVENT_RINGA 9 /* Announce we/they are ringing */
#define IAX_EVENT_PING 10 /* Ping -- internal use only */
#define IAX_EVENT_PONG 11 /* Pong -- internal use only */
#define IAX_EVENT_BUSY 12 /* Report a line busy */
#define IAX_EVENT_ANSWER 13 /* Answer the line */
#define IAX_EVENT_IMAGE 14 /* Send/Receive an image */
#define IAX_EVENT_AUTHRQ 15 /* Authentication request */
#define IAX_EVENT_AUTHRP 16 /* Authentication reply */
#define IAX_EVENT_REGREQ 17 /* Registration request */
#define IAX_EVENT_REGACK 18 /* Registration reply */
#define IAX_EVENT_URL 19 /* URL received */
#define IAX_EVENT_LDCOMPLETE 20 /* URL loading complete */
#define IAX_EVENT_TRANSFER 21 /* Transfer has taken place */
#define IAX_EVENT_DPREQ 22 /* Dialplan request */
#define IAX_EVENT_DPREP 23 /* Dialplan reply */
#define IAX_EVENT_DIAL 24 /* Dial on a TBD call */
#define IAX_EVENT_QUELCH 25 /* Quelch Audio */
#define IAX_EVENT_UNQUELCH 26 /* Unquelch Audio */
#define IAX_EVENT_UNLINK 27 /* Unlink */
#define IAX_EVENT_LINKREJECT 28 /* Link Rejection */
#define IAX_EVENT_TEXT 29 /* Text Frame :-) */
#define IAX_EVENT_REGREJ 30 /* Registration reply */
#define IAX_EVENT_LINKURL 31 /* Unlink */
#define IAX_SCHEDULE_FUZZ 0 /* ms of fuzz to drop */
#ifdef WIN32
typedef int PASCAL (*sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
#else
typedef int (*sendto_t)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
#endif
#define MEMORY_SIZE 100
struct iax_session {
/* Private data */
void *pvt;
/* Sendto function */
sendto_t sendto;
/* Is voice quelched (e.g. hold) */
int quelch;
/* Last received voice format */
int voiceformat;
/* Last transmitted voice format */
int svoiceformat;
/* Last received timestamp */
unsigned int last_ts;
/* Last transmitted timestamp */
unsigned int lastsent;
/* Last transmitted voice timestamp */
unsigned int lastvoicets;
/* Our last measured ping time */
unsigned int pingtime;
/* Address of peer */
struct sockaddr_in peeraddr;
/* Our call number */
int callno;
/* Peer's call number */
int peercallno;
/* Our next outgoing sequence number */
unsigned char oseqno;
/* Next sequence number they have not yet acknowledged */
unsigned char rseqno;
/* Our last received incoming sequence number */
unsigned char iseqno;
/* Last acknowledged sequence number */
unsigned char aseqno;
/* Peer supported formats */
int peerformats;
/* Time value that we base our transmission on */
struct timeval offset;
/* Time value we base our delivery on */
struct timeval rxcore;
/* History of lags */
int history[MEMORY_SIZE];
/* Current base jitterbuffer */
int jitterbuffer;
/* Informational jitter */
int jitter;
/* Measured lag */
int lag;
/* Current link state */
int state;
/* Peer name */
char peer[MAXSTRLEN];
/* Default Context */
char context[MAXSTRLEN];
/* Caller ID if available */
char callerid[MAXSTRLEN];
/* DNID */
char dnid[MAXSTRLEN];
/* Requested Extension */
char exten[MAXSTRLEN];
/* Expected Username */
char username[MAXSTRLEN];
/* Expected Secret */
char secret[MAXSTRLEN];
/* permitted authentication methods */
char methods[MAXSTRLEN];
/* MD5 challenge */
char challenge[12];
#ifdef VOICE_SMOOTHING
unsigned int lastts;
#endif
/* Refresh if applicable */
int refresh;
/* Transfer stuff */
struct sockaddr_in transfer;
int transferring;
int transfercallno;
int transferid;
/* For linking if there are multiple connections */
struct iax_session *next;
};
struct iax_event {
int etype; /* Type of event */
int subclass; /* Subclass data (event specific) */
unsigned int ts; /* Timestamp */
struct iax_session *session; /* Applicable session */
int datalen; /* Length of raw data */
struct iax_ies ies; /* IE's for IAX2 frames */
unsigned char data[0]; /* Raw data if applicable */
};
/* All functions return 0 on success and -1 on failure unless otherwise
specified */
/* Called to initialize IAX structures and sockets. Returns actual
portnumber (which it will try preferred portno first, but if not
take what it can get */
extern int iax_init(int preferredportno);
/* Get filedescriptor for IAX to use with select or gtk_input_add */
extern int iax_get_fd(void);
/* Find out how many milliseconds until the next scheduled event */
extern int iax_time_to_next_event(void);
/* Generate a new IAX session */
extern struct iax_session *iax_session_new(void);
/* Return exactly one iax event (if there is one pending). If blocking is
non-zero, IAX will block until some event is received */
extern struct iax_event *iax_get_event(int blocking);
extern int iax_auth_reply(struct iax_session *session, char *password,
char *challenge, int methods);
/* Stop iax, hangup file descriptors, free memory, etc. */
extern void iax_end(void);
/* Free an event */
extern void iax_event_free(struct iax_event *event);
struct sockaddr_in;
/* Front ends for sending events */
extern void iax_set_formats(int fmt);
extern int iax_send_dtmf(struct iax_session *session, char digit);
extern int iax_send_voice(struct iax_session *session, int format, char *data, int datalen);
extern int iax_send_image(struct iax_session *session, int format, char *data, int datalen);
extern int iax_send_url(struct iax_session *session, char *url, int link);
extern int iax_send_text(struct iax_session *session, char *text);
extern int iax_load_complete(struct iax_session *session);
extern int iax_reject(struct iax_session *session, char *reason);
extern int iax_busy(struct iax_session *session);
extern int iax_hangup(struct iax_session *session, char *byemsg);
extern int iax_call(struct iax_session *session, char *cidnum, char *cidname, char *ich, char *lang, int wait);
extern int iax_accept(struct iax_session *session,int format);
extern int iax_answer(struct iax_session *session);
extern int iax_sendurl(struct iax_session *session, char *url);
extern int iax_send_unlink(struct iax_session *session);
extern int iax_send_link_reject(struct iax_session *session);
extern int iax_ring_announce(struct iax_session *session);
extern struct sockaddr_in iax_get_peer_addr(struct iax_session *session);
extern int iax_register(struct iax_session *session, char *hostname, char *peer, char *secret, int refresh);
extern int iax_lag_request(struct iax_session *session);
extern int iax_dial(struct iax_session *session, char *number); /* Dial on a TBD call */
extern int iax_dialplan_request(struct iax_session *session, char *number); /* Request dialplan status for number */
extern int iax_quelch(struct iax_session *session);
extern int iax_unquelch(struct iax_session * session);
extern int iax_transfer(struct iax_session *session, char *number);
extern void iax_destroy(struct iax_session * session);
extern void iax_enable_debug(void);
extern void iax_disable_debug(void);
void iax_set_private(struct iax_session *s, void *pvt);
void *iax_get_private(struct iax_session *s);
void iax_set_sendto(struct iax_session *s, sendto_t sendto);
/* Handle externally received frames */
struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_in *sin);
/* this function allows you to use libiax for a server */
int iax_send_regauth(struct iax_session *session, int authmethod);
int iax_send_authreq(struct iax_session *session, int authmethod);
int iax_send_regack(struct iax_session *session);
int iax_send_regrej(struct iax_session *session);
/* we need this low level function */
int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
#endif /* _ASTERISK_IAX_CLIENT_H */

2203
contrib/iax/iax.c Normal file

File diff suppressed because it is too large Load Diff

86
contrib/iax/iax.h Normal file
View File

@ -0,0 +1,86 @@
/*
* libIAX
*
* Implementation of Inter-IAXerisk eXchange
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _IAX_H
#define _IAX_H
/* Max version of IAX protocol we support */
#define IAX_PROTO_VERSION 1
#define IAX_MAX_CALLS 32768
#define IAX_FLAG_FULL 0x8000
#define IAX_FLAG_SC_LOG 0x80
#define IAX_MAX_SHIFT 0x1F
/* Maximum size of an IAX frame (max size of UDP frame) */
#define IAX_MAX_BUF_SIZE 65536
/* Subclass for IAX_FRAME_IAX */
#define IAX_COMMAND_NEW 1
#define IAX_COMMAND_PING 2
#define IAX_COMMAND_PONG 3
#define IAX_COMMAND_ACK 4
#define IAX_COMMAND_HANGUP 5
#define IAX_COMMAND_REJECT 6
#define IAX_COMMAND_ACCEPT 7
#define IAX_COMMAND_AUTHREQ 8
#define IAX_COMMAND_AUTHREP 9
#define IAX_COMMAND_INVAL 10
#define IAX_COMMAND_LAGRQ 11
#define IAX_COMMAND_LAGRP 12
#define IAX_COMMAND_REGREQ 13 /* Registration request */
#define IAX_COMMAND_REGAUTH 14 /* Registration authentication required */
#define IAX_COMMAND_REGACK 15 /* Registration accepted */
#define IAX_COMMAND_REGREJ 16 /* Registration rejected */
#define IAX_COMMAND_REGREL 17 /* Force release of registration */
#define IAX_COMMAND_VNAK 18 /* If we receive voice before valid first voice frame, send this */
#define IAX_COMMAND_DPREQ 19 /* Request status of a dialplan entry */
#define IAX_COMMAND_DPREP 20 /* Request status of a dialplan entry */
#define IAX_COMMAND_DIAL 21 /* Request a dial on channel brought up TBD */
#define IAX_COMMAND_TXREQ 22 /* Transfer Request */
#define IAX_COMMAND_TXCNT 23 /* Transfer Connect */
#define IAX_COMMAND_TXACC 24 /* Transfer Accepted */
#define IAX_COMMAND_TXREADY 25 /* Transfer ready */
#define IAX_COMMAND_TXREL 26 /* Transfer release */
#define IAX_COMMAND_TXREJ 27 /* Transfer reject */
#define IAX_COMMAND_QUELCH 28 /* Stop audio/video transmission */
#define IAX_COMMAND_UNQUELCH 29 /* Resume audio/video transmission */
#define IAX_DEFAULT_REG_EXPIRE 60
#define IAX_DEFAULT_PORTNO 5036
/* Full frames are always delivered reliably */
struct iax_full_hdr {
short callno; /* Source call number -- high bit must be 1 */
short dcallno; /* Destination call number */
unsigned int ts; /* 32-bit timestamp in milliseconds */
unsigned short seqno; /* Packet number */
char type; /* Frame type */
unsigned char csub; /* Compressed subclass */
char data[0];
};
/* Mini header is used only for voice frames -- delivered unreliably */
struct iax_mini_hdr {
short callno; /* Source call number -- high bit must be 0 */
unsigned short ts; /* 16-bit Timestamp (high 16 bits from last IAX_full_hdr) */
/* Frametype implicitly VOICE_FRAME */
/* subclass implicit from last IAX_full_hdr */
char data[0];
};
#endif

581
contrib/iax/iax2-parser.c Normal file
View File

@ -0,0 +1,581 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Implementation of Inter-Asterisk eXchange
*
* Copyright (C) 2003, Digium
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU Lesser (Library) General Public License
*/
#ifdef WIN32
#include <winsock.h>
#define snprintf _snprintf
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <string.h>
#include "frame.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "iax2.h"
#include "iax2-parser.h"
static int frames = 0;
static int iframes = 0;
static int oframes = 0;
static void internaloutput(const char *str)
{
printf(str);
}
static void internalerror(const char *str)
{
fprintf(stderr, "WARNING: %s", str);
}
static void (*outputf)(const char *str) = internaloutput;
static void (*errorf)(const char *str) = internalerror;
static void dump_addr(char *output, int maxlen, void *value, int len)
{
struct sockaddr_in sin;
if (len == sizeof(sin)) {
memcpy(&sin, value, len);
snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
} else {
snprintf(output, maxlen, "Invalid Address");
}
}
static void dump_string(char *output, int maxlen, void *value, int len)
{
maxlen--;
if (maxlen > len)
maxlen = len;
strncpy(output,value, maxlen);
output[maxlen] = '\0';
}
static void dump_int(char *output, int maxlen, void *value, int len)
{
if (len == sizeof(unsigned int))
snprintf(output, maxlen, "%ld", (long)ntohl(*((unsigned int *)value)));
else
snprintf(output, maxlen, "Invalid INT");
}
static void dump_short(char *output, int maxlen, void *value, int len)
{
if (len == sizeof(unsigned short))
snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
else
snprintf(output, maxlen, "Invalid SHORT");
}
static void dump_byte(char *output, int maxlen, void *value, int len)
{
if (len == sizeof(unsigned char))
snprintf(output, maxlen, "%d", ntohs(*((unsigned char *)value)));
else
snprintf(output, maxlen, "Invalid BYTE");
}
static struct iax2_ie {
int ie;
char *name;
void (*dump)(char *output, int maxlen, void *value, int len);
} ies[] = {
{ IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
{ IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
{ IAX_IE_CALLING_ANI, "ANI", dump_string },
{ IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
{ IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
{ IAX_IE_USERNAME, "USERNAME", dump_string },
{ IAX_IE_PASSWORD, "PASSWORD", dump_string },
{ IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
{ IAX_IE_FORMAT, "FORMAT", dump_int },
{ IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
{ IAX_IE_VERSION, "VERSION", dump_short },
{ IAX_IE_ADSICPE, "ADSICPE", dump_short },
{ IAX_IE_DNID, "DNID", dump_string },
{ IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
{ IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
{ IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
{ IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
{ IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
{ IAX_IE_REFRESH, "REFRESH", dump_short },
{ IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
{ IAX_IE_CALLNO, "CALL NUMBER", dump_short },
{ IAX_IE_CAUSE, "CAUSE", dump_string },
{ IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
{ IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
{ IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
{ IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
{ IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
{ IAX_IE_PROVISIONING, "PROVISIONING" },
{ IAX_IE_AESPROVISIONING, "AES PROVISIONING" },
{ IAX_IE_DATETIME, "DATE TIME", dump_int },
};
const char *iax_ie2str(int ie)
{
int x;
for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
if (ies[x].ie == ie)
return ies[x].name;
}
return "Unknown IE";
}
static void dump_ies(unsigned char *iedata, int len)
{
int ielen;
int ie;
int x;
int found;
char interp[80];
char tmp[256];
if (len < 2)
return;
while(len > 2) {
ie = iedata[0];
ielen = iedata[1];
if (ielen + 2> len) {
snprintf(tmp, sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
outputf(tmp);
return;
}
found = 0;
for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) {
if (ies[x].ie == ie) {
if (ies[x].dump) {
ies[x].dump(interp, sizeof(interp), iedata + 2, ielen);
snprintf(tmp, sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
outputf(tmp);
} else {
snprintf(tmp, sizeof(tmp), " %-15.15s : Present\n", ies[x].name);
outputf(tmp);
}
found++;
}
}
if (!found) {
snprintf(tmp, sizeof(tmp), " Unknown IE %03d : Present\n", ie);
outputf(tmp);
}
iedata += (2 + ielen);
len -= (2 + ielen);
}
outputf("\n");
}
void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
{
char *frames[] = {
"(0?)",
"DTMF ",
"VOICE ",
"VIDEO ",
"CONTROL",
"NULL ",
"IAX ",
"TEXT ",
"IMAGE " };
char *iaxs[] = {
"(0?)",
"NEW ",
"PING ",
"PONG ",
"ACK ",
"HANGUP ",
"REJECT ",
"ACCEPT ",
"AUTHREQ",
"AUTHREP",
"INVAL ",
"LAGRQ ",
"LAGRP ",
"REGREQ ",
"REGAUTH",
"REGACK ",
"REGREJ ",
"REGREL ",
"VNAK ",
"DPREQ ",
"DPREP ",
"DIAL ",
"TXREQ ",
"TXCNT ",
"TXACC ",
"TXREADY",
"TXREL ",
"TXREJ ",
"QUELCH ",
"UNQULCH",
"POKE",
"PAGE",
"MWI",
"UNSUPPORTED",
"TRANSFER",
"PROVISION",
};
char *cmds[] = {
"(0?)",
"HANGUP ",
"RING ",
"RINGING",
"ANSWER ",
"BUSY ",
"TKOFFHK ",
"OFFHOOK" };
struct ast_iax2_full_hdr *fh;
char retries[20];
char class2[20];
char subclass2[20];
char *class;
char *subclass;
char tmp[256];
if (f) {
fh = f->data;
snprintf(retries, sizeof(retries), "%03d", f->retries);
} else {
fh = fhi;
if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
strcpy(retries, "Yes");
else
strcpy(retries, "No");
}
if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
/* Don't mess with mini-frames */
return;
}
if (fh->type > sizeof(frames)/sizeof(char *)) {
snprintf(class2, sizeof(class2), "(%d?)", fh->type);
class = class2;
} else {
class = frames[(int)fh->type];
}
if (fh->type == AST_FRAME_DTMF) {
sprintf(subclass2, "%c", fh->csub);
subclass = subclass2;
} else if (fh->type == AST_FRAME_IAX) {
if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) {
snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
subclass = subclass2;
} else {
subclass = iaxs[(int)fh->csub];
}
} else if (fh->type == AST_FRAME_CONTROL) {
if (fh->csub > sizeof(cmds)/sizeof(char *)) {
snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub);
subclass = subclass2;
} else {
subclass = cmds[(int)fh->csub];
}
} else {
snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
subclass = subclass2;
}
snprintf(tmp, sizeof(tmp),
"%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
(rx ? "Rx" : "Tx"),
retries, fh->oseqno, fh->iseqno, class, subclass);
outputf(tmp);
snprintf(tmp, sizeof(tmp),
" Timestamp: %05ldms SCall: %5.5d DCall: %5.5d [%s:%d]\n",
(long)ntohl(fh->ts),
ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
outputf(tmp);
if (fh->type == AST_FRAME_IAX)
dump_ies(fh->iedata, datalen);
}
int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen)
{
char tmp[256];
if (datalen > (sizeof(ied->buf) - ied->pos)) {
snprintf(tmp, sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, sizeof(ied->buf) - ied->pos);
errorf(tmp);
return -1;
}
ied->buf[ied->pos++] = ie;
ied->buf[ied->pos++] = datalen;
memcpy(ied->buf + ied->pos, data, datalen);
ied->pos += datalen;
return 0;
}
int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
{
return iax_ie_append_raw(ied, ie, sin, sizeof(struct sockaddr_in));
}
int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
{
unsigned int newval;
newval = htonl(value);
return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
}
int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
{
unsigned short newval;
newval = htons(value);
return iax_ie_append_raw(ied, ie, &newval, sizeof(newval));
}
int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str)
{
return iax_ie_append_raw(ied, ie, str, strlen(str));
}
int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
{
return iax_ie_append_raw(ied, ie, &dat, 1);
}
int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
{
return iax_ie_append_raw(ied, ie, NULL, 0);
}
void iax_set_output(void (*func)(const char *))
{
outputf = func;
}
void iax_set_error(void (*func)(const char *))
{
errorf = func;
}
int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
{
/* Parse data into information elements */
int len;
int ie;
char tmp[256];
memset(ies, 0, sizeof(struct iax_ies));
ies->msgcount = -1;
while(datalen >= 2) {
ie = data[0];
len = data[1];
if (len > datalen - 2) {
errorf("Information element length exceeds message size\n");
return -1;
}
switch(ie) {
case IAX_IE_CALLED_NUMBER:
ies->called_number = data + 2;
break;
case IAX_IE_CALLING_NUMBER:
ies->calling_number = data + 2;
break;
case IAX_IE_CALLING_ANI:
ies->calling_ani = data + 2;
break;
case IAX_IE_CALLING_NAME:
ies->calling_name = data + 2;
break;
case IAX_IE_CALLED_CONTEXT:
ies->called_context = data + 2;
break;
case IAX_IE_USERNAME:
ies->username = data + 2;
break;
case IAX_IE_PASSWORD:
ies->password = data + 2;
break;
case IAX_IE_CAPABILITY:
if (len != sizeof(unsigned int)) {
snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
errorf(tmp);
} else
ies->capability = ntohl(*((unsigned int *)(data + 2)));
break;
case IAX_IE_FORMAT:
if (len != sizeof(unsigned int)) {
snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
errorf(tmp);
} else
ies->format = ntohl(*((unsigned int *)(data + 2)));
break;
case IAX_IE_LANGUAGE:
ies->language = data + 2;
break;
case IAX_IE_VERSION:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->version = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_ADSICPE:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_DNID:
ies->dnid = data + 2;
break;
case IAX_IE_RDNIS:
ies->rdnis = data + 2;
break;
case IAX_IE_AUTHMETHODS:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_CHALLENGE:
ies->challenge = data + 2;
break;
case IAX_IE_MD5_RESULT:
ies->md5_result = data + 2;
break;
case IAX_IE_RSA_RESULT:
ies->rsa_result = data + 2;
break;
case IAX_IE_APPARENT_ADDR:
ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
break;
case IAX_IE_REFRESH:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->refresh = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_DPSTATUS:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_CALLNO:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->callno = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_CAUSE:
ies->cause = data + 2;
break;
case IAX_IE_IAX_UNKNOWN:
if (len == 1)
ies->iax_unknown = data[2];
else {
snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
errorf(tmp);
}
break;
case IAX_IE_MSGCOUNT:
if (len != sizeof(unsigned short)) {
snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
errorf(tmp);
} else
ies->msgcount = ntohs(*((unsigned short *)(data + 2)));
break;
case IAX_IE_AUTOANSWER:
ies->autoanswer = 1;
break;
case IAX_IE_MUSICONHOLD:
ies->musiconhold = 1;
break;
case IAX_IE_TRANSFERID:
if (len != sizeof(unsigned int)) {
snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
errorf(tmp);
} else
ies->transferid = ntohl(*((unsigned int *)(data + 2)));
break;
case IAX_IE_DATETIME:
if (len != sizeof(unsigned int)) {
snprintf(tmp, sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", sizeof(unsigned int), len);
errorf(tmp);
} else
ies->datetime = ntohl(*((unsigned int *)(data + 2)));
break;
default:
snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
errorf(tmp);
}
/* Overwrite information element with 0, to null terminate previous portion */
data[0] = 0;
datalen -= (len + 2);
data += (len + 2);
}
/* Null-terminate last field */
*data = '\0';
if (datalen) {
errorf("Invalid information element contents, strange boundary\n");
return -1;
}
return 0;
}
void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
{
fr->af.frametype = f->frametype;
fr->af.subclass = f->subclass;
fr->af.mallocd = 0; /* Our frame is static relative to the container */
fr->af.datalen = f->datalen;
fr->af.samples = f->samples;
fr->af.offset = AST_FRIENDLY_OFFSET;
fr->af.src = f->src;
fr->af.data = fr->afdata;
if (fr->af.datalen)
memcpy(fr->af.data, f->data, fr->af.datalen);
}
struct iax_frame *iax_frame_new(int direction, int datalen)
{
struct iax_frame *fr;
fr = malloc(sizeof(struct iax_frame) + datalen);
if (fr) {
fr->direction = direction;
fr->retrans = -1;
frames++;
if (fr->direction == DIRECTION_INGRESS)
iframes++;
else
oframes++;
}
return fr;
}
void iax_frame_free(struct iax_frame *fr)
{
/* Note: does not remove from scheduler! */
if (fr->direction == DIRECTION_INGRESS)
iframes--;
else if (fr->direction == DIRECTION_OUTGRESS)
oframes--;
else {
errorf("Attempt to double free frame detected\n");
return;
}
fr->direction = 0;
free(fr);
frames--;
}
int iax_get_frames(void) { return frames; }
int iax_get_iframes(void) { return iframes; }
int iax_get_oframes(void) { return oframes; }

126
contrib/iax/iax2-parser.h Normal file
View File

@ -0,0 +1,126 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Implementation of Inter-Asterisk eXchange
*
* Copyright (C) 2003, Digium
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _IAX2_PARSER_H
#define _IAX2_PARSER_H
struct iax_ies {
char *called_number;
char *calling_number;
char *calling_ani;
char *calling_name;
char *called_context;
char *username;
char *password;
unsigned int capability;
unsigned int format;
char *language;
int version;
unsigned short adsicpe;
char *dnid;
char *rdnis;
unsigned int authmethods;
char *challenge;
char *md5_result;
char *rsa_result;
struct sockaddr_in *apparent_addr;
unsigned short refresh;
unsigned short dpstatus;
unsigned short callno;
char *cause;
unsigned char iax_unknown;
int msgcount;
int autoanswer;
int musiconhold;
unsigned int transferid;
unsigned int datetime;
};
#define DIRECTION_INGRESS 1
#define DIRECTION_OUTGRESS 2
struct iax_frame {
#ifdef LIBIAX
struct iax_session *session;
struct iax_event *event;
#endif
/* /Our/ call number */
unsigned short callno;
/* /Their/ call number */
unsigned short dcallno;
/* Start of raw frame (outgoing only) */
void *data;
/* Length of frame (outgoing only) */
int datalen;
/* How many retries so far? */
int retries;
/* Outgoing relative timestamp (ms) */
unsigned int ts;
/* How long to wait before retrying */
int retrytime;
/* Are we received out of order? */
int outoforder;
/* Have we been sent at all yet? */
int sentyet;
/* Outgoing Packet sequence number */
int oseqno;
/* Next expected incoming packet sequence number */
int iseqno;
/* Non-zero if should be sent to transfer peer */
int transfer;
/* Non-zero if this is the final message */
int final;
/* Ingress or outgres */
int direction;
/* Retransmission ID */
int retrans;
/* Easy linking */
struct iax_frame *next;
struct iax_frame *prev;
/* Actual, isolated frame header */
struct ast_frame af;
unsigned char unused[AST_FRIENDLY_OFFSET];
unsigned char afdata[0]; /* Data for frame */
};
struct iax_ie_data {
unsigned char buf[1024];
int pos;
};
/* Choose a different function for output */
extern void iax_set_output(void (*output)(const char *data));
/* Choose a different function for errors */
extern void iax_set_error(void (*output)(const char *data));
extern void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
extern const char *iax_ie2str(int ie);
extern int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, void *data, int datalen);
extern int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin);
extern int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value);
extern int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);
extern int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str);
extern int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat);
extern int iax_ie_append(struct iax_ie_data *ied, unsigned char ie);
extern int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen);
extern int iax_get_frames(void);
extern int iax_get_iframes(void);
extern int iax_get_oframes(void);
extern void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f);
extern struct iax_frame *iax_frame_new(int direction, int datalen);
extern void iax_frame_free(struct iax_frame *fr);
#endif

179
contrib/iax/iax2.h Normal file
View File

@ -0,0 +1,179 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Implementation of Inter-Asterisk eXchange
*
* Copyright (C) 2003, Digium
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _IAX2_H
#define _IAX2_H
/* Max version of IAX protocol we support */
#define IAX_PROTO_VERSION 2
#define IAX_MAX_CALLS 32768
#define IAX_FLAG_FULL 0x8000
#define IAX_FLAG_RETRANS 0x8000
#define IAX_FLAG_SC_LOG 0x80
#define IAX_MAX_SHIFT 0x1F
#define IAX_WINDOW 64
/* Subclass for AST_FRAME_IAX */
#define IAX_COMMAND_NEW 1
#define IAX_COMMAND_PING 2
#define IAX_COMMAND_PONG 3
#define IAX_COMMAND_ACK 4
#define IAX_COMMAND_HANGUP 5
#define IAX_COMMAND_REJECT 6
#define IAX_COMMAND_ACCEPT 7
#define IAX_COMMAND_AUTHREQ 8
#define IAX_COMMAND_AUTHREP 9
#define IAX_COMMAND_INVAL 10
#define IAX_COMMAND_LAGRQ 11
#define IAX_COMMAND_LAGRP 12
#define IAX_COMMAND_REGREQ 13 /* Registration request */
#define IAX_COMMAND_REGAUTH 14 /* Registration authentication required */
#define IAX_COMMAND_REGACK 15 /* Registration accepted */
#define IAX_COMMAND_REGREJ 16 /* Registration rejected */
#define IAX_COMMAND_REGREL 17 /* Force release of registration */
#define IAX_COMMAND_VNAK 18 /* If we receive voice before valid first voice frame, send this */
#define IAX_COMMAND_DPREQ 19 /* Request status of a dialplan entry */
#define IAX_COMMAND_DPREP 20 /* Request status of a dialplan entry */
#define IAX_COMMAND_DIAL 21 /* Request a dial on channel brought up TBD */
#define IAX_COMMAND_TXREQ 22 /* Transfer Request */
#define IAX_COMMAND_TXCNT 23 /* Transfer Connect */
#define IAX_COMMAND_TXACC 24 /* Transfer Accepted */
#define IAX_COMMAND_TXREADY 25 /* Transfer ready */
#define IAX_COMMAND_TXREL 26 /* Transfer release */
#define IAX_COMMAND_TXREJ 27 /* Transfer reject */
#define IAX_COMMAND_QUELCH 28 /* Stop audio/video transmission */
#define IAX_COMMAND_UNQUELCH 29 /* Resume audio/video transmission */
#define IAX_COMMAND_POKE 30 /* Like ping, but does not require an open connection */
#define IAX_COMMAND_PAGE 31 /* Paging description */
#define IAX_COMMAND_MWI 32 /* Stand-alone message waiting indicator */
#define IAX_COMMAND_UNSUPPORT 33 /* Unsupported message received */
#define IAX_COMMAND_TRANSFER 34 /* Request remote transfer */
#define IAX_COMMAND_PROVISION 35 /* Provision device */
#define IAX_DEFAULT_REG_EXPIRE 60 /* By default require re-registration once per minute */
#define IAX_LINGER_TIMEOUT 10 /* How long to wait before closing bridged call */
#define IAX_DEFAULT_PORTNO 4569
/* IAX Information elements */
#define IAX_IE_CALLED_NUMBER 1 /* Number/extension being called - string */
#define IAX_IE_CALLING_NUMBER 2 /* Calling number - string */
#define IAX_IE_CALLING_ANI 3 /* Calling number ANI for billing - string */
#define IAX_IE_CALLING_NAME 4 /* Name of caller - string */
#define IAX_IE_CALLED_CONTEXT 5 /* Context for number - string */
#define IAX_IE_USERNAME 6 /* Username (peer or user) for authentication - string */
#define IAX_IE_PASSWORD 7 /* Password for authentication - string */
#define IAX_IE_CAPABILITY 8 /* Actual codec capability - unsigned int */
#define IAX_IE_FORMAT 9 /* Desired codec format - unsigned int */
#define IAX_IE_LANGUAGE 10 /* Desired language - string */
#define IAX_IE_VERSION 11 /* Protocol version - short */
#define IAX_IE_ADSICPE 12 /* CPE ADSI capability - short */
#define IAX_IE_DNID 13 /* Originally dialed DNID - string */
#define IAX_IE_AUTHMETHODS 14 /* Authentication method(s) - short */
#define IAX_IE_CHALLENGE 15 /* Challenge data for MD5/RSA - string */
#define IAX_IE_MD5_RESULT 16 /* MD5 challenge result - string */
#define IAX_IE_RSA_RESULT 17 /* RSA challenge result - string */
#define IAX_IE_APPARENT_ADDR 18 /* Apparent address of peer - struct sockaddr_in */
#define IAX_IE_REFRESH 19 /* When to refresh registration - short */
#define IAX_IE_DPSTATUS 20 /* Dialplan status - short */
#define IAX_IE_CALLNO 21 /* Call number of peer - short */
#define IAX_IE_CAUSE 22 /* Cause - string */
#define IAX_IE_IAX_UNKNOWN 23 /* Unknown IAX command - byte */
#define IAX_IE_MSGCOUNT 24 /* How many messages waiting - short */
#define IAX_IE_AUTOANSWER 25 /* Request auto-answering -- none */
#define IAX_IE_MUSICONHOLD 26 /* Request musiconhold with QUELCH -- none or string */
#define IAX_IE_TRANSFERID 27 /* Transfer Request Identifier -- int */
#define IAX_IE_RDNIS 28 /* Referring DNIS -- string */
#define IAX_IE_PROVISIONING 29 /* Provisioning info */
#define IAX_IE_AESPROVISIONING 30 /* AES Provisioning info */
#define IAX_IE_DATETIME 31 /* Date/Time */
#define IAX_AUTH_PLAINTEXT (1 << 0)
#define IAX_AUTH_MD5 (1 << 1)
#define IAX_AUTH_RSA (1 << 2)
#define IAX_META_TRUNK 1 /* Trunk meta-message */
#define IAX_META_VIDEO 2 /* Video frame */
#define IAX_DPSTATUS_EXISTS (1 << 0)
#define IAX_DPSTATUS_CANEXIST (1 << 1)
#define IAX_DPSTATUS_NONEXISTANT (1 << 2)
#define IAX_DPSTATUS_IGNOREPAT (1 << 14)
#define IAX_DPSTATUS_MATCHMORE (1 << 15)
#if defined(_MSC_VER)
#pragma pack(push,1)
#define __PACKED
#else
#define __PACKED __attribute__ ((__packed__))
#endif
/* Full frames are always delivered reliably */
struct ast_iax2_full_hdr {
unsigned short scallno; /* Source call number -- high bit must be 1 */
unsigned short dcallno; /* Destination call number -- high bit is 1 if retransmission */
unsigned int ts; /* 32-bit timestamp in milliseconds (from 1st transmission) */
unsigned char oseqno; /* Packet number (outgoing) */
unsigned char iseqno; /* Packet number (next incoming expected) */
char type; /* Frame type */
unsigned char csub; /* Compressed subclass */
unsigned char iedata[0];
} __PACKED;
/* Mini header is used only for voice frames -- delivered unreliably */
struct ast_iax2_mini_hdr {
unsigned short callno; /* Source call number -- high bit must be 0, rest must be non-zero */
unsigned short ts; /* 16-bit Timestamp (high 16 bits from last ast_iax2_full_hdr) */
/* Frametype implicitly VOICE_FRAME */
/* subclass implicit from last ast_iax2_full_hdr */
unsigned char data[0];
} __PACKED;
struct ast_iax2_meta_hdr {
unsigned short zeros; /* Zeros field -- must be zero */
unsigned char metacmd; /* Meta command */
unsigned char cmddata; /* Command Data */
unsigned char data[0];
} __PACKED;
struct ast_iax2_video_hdr {
unsigned short zeros; /* Zeros field -- must be zero */
unsigned short callno; /* Video call number */
unsigned short ts; /* Timestamp and mark if present */
unsigned char data[0];
} __PACKED;
struct ast_iax2_meta_trunk_hdr {
unsigned int ts; /* 32-bit timestamp for all messages */
unsigned char data[0];
} __PACKED;
struct ast_iax2_meta_trunk_entry {
unsigned short callno; /* Call number */
unsigned short len; /* Length of data for this callno */
} __PACKED;
#if defined(_MSC_VER)
#pragma pack(pop)
#endif
#undef __PACKED
#endif

273
contrib/iax/md5.c Normal file
View File

@ -0,0 +1,273 @@
/* MD5 checksum routines used for authentication. Not covered by GPL, but
in the public domain as per the copyright below */
#ifdef FREEBSD
# include <machine/endian.h>
#elif defined(LINUX)
# include <endian.h>
# include <features.h>
# include <sys/types.h>
#elif defined(SOLARIS)
/* each solaris is different -- this won't work on 2.6 or 2.7 */
# include <sys/isa_defs.h>
#endif
#if __BYTE_ORDER == __BIG_ENDIAN || BYTE_ORDER == BIG_ENDIAN
# define HIGHFIRST 1
#elif __BYTE_ORDER == __LITTLE_ENDIAN || BYTE_ORDER == LITLE_ENDIAN
# undef HIGHFIRST
#else
# error "Please fix <bits/endian.h>"
#endif
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include <string.h> /* for memcpy() */
#include "md5.h"
#ifndef HIGHFIRST
#define byteReverse(buf, len) /* Nothing */
#else
void byteReverse(unsigned char *buf, unsigned longs);
#ifndef ASM_MD5
/*
* Note: this code is harmless on little-endian machines.
*/
void byteReverse(unsigned char *buf, unsigned longs)
{
uint32 t;
do {
t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32 *) buf = t;
buf += 4;
} while (--longs);
}
#endif
#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
uint32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32 *) ctx->in)[14] = ctx->bits[0];
((uint32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
#ifndef ASM_MD5
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
void MD5Transform(uint32 buf[4], uint32 const in[16])
{
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
#endif

27
contrib/iax/md5.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef MD5_H
#define MD5_H
#ifdef __alpha
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif
struct MD5Context {
uint32 buf[4];
uint32 bits[2];
unsigned char in[64];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
void MD5Transform(uint32 buf[4], uint32 const in[16]);
/*
* This is needed to make RSAREF happy on some MS-DOS compilers.
*/
typedef struct MD5Context MD5_CTX;
#endif /* !MD5_H */

View File

@ -122,8 +122,13 @@ pgsqlroute.yate cdrpgsql.yate register.yate: LOCALFLAGS = @PGSQL_INC@ -lpq
sipchan.yate: LOCALFLAGS = @EXOSIP_INC@ @ORTP_INC@ @GLIB2_INC@ @EXOSIP_LIB@ @ORTP_LIB@ @GLIB2_LIB@
iaxchan.yate: @IAX2_DEP@
iaxchan.yate: LOCALLIBS = @IAX2_DEP@
iaxchan.yate: LOCALFLAGS = @IAX2_INC@ @IAX2_LIB@
gsmcodec.yate: LOCALLIBS = -lgsm
gtkclient.yate: LOCALFLAGS = @GTK_INC@ @GTK_LIB@
../contrib/iax/libiax.a:
$(MAKE) -C ../contrib/iax

View File

@ -10,13 +10,18 @@
#include <telephony.h>
#include <yateversn.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
extern "C" {
#include <iax/iax-client.h>
#include <iax-client.h>
#include <md5.h>
};
@ -31,6 +36,14 @@ static TokenDict dict_iaxformats[] = {
{ 0, 0 }
};
static TokenDict dict_tos[] = {
{ "lowdelay", IPTOS_LOWDELAY },
{ "throughput", IPTOS_THROUGHPUT },
{ "reliability", IPTOS_RELIABILITY },
{ "mincost", IPTOS_MINCOST },
{ 0, 0 }
};
static int s_ast_formats = 0;
static Configuration s_cfg;
static Mutex s_mutex;
@ -38,14 +51,24 @@ static Mutex s_mutex;
static ObjList m_calls;
class YateIAXConnection;
class IAXSource : public DataSource
{
public:
IAXSource(const char *frm) : DataSource(frm),m_total(0),m_time(Time::now())
{ Debug(DebugInfo,"IAXSource::IAXSource [%p] frm %s",this,frm);};
~IAXSource();
void Forward(const DataBlock &data);
private:
unsigned m_total;
unsigned long long m_time;
};
class YateIAXAudioConsumer : public DataConsumer
{
public:
YateIAXAudioConsumer(YateIAXConnection *conn, iax_session *session,
int ast_format = AST_FORMAT_SLINEAR, const char *format = "slin");
~YateIAXAudioConsumer()
{ Debug(DebugAll,"YateIAXAudioConsumer::~YateIAXAudioConsumer() [%p]",this); }
~YateIAXAudioConsumer();
virtual void Consume(const DataBlock &data);
@ -54,6 +77,8 @@ private:
iax_session *m_session;
DataBlock m_buffer;
int m_ast_format;
unsigned m_total;
unsigned long long m_time;
};
@ -63,7 +88,9 @@ public:
YateIAXEndPoint();
~YateIAXEndPoint();
static bool Init(void);
bool accepting(iax_event *e);
void answer(iax_event *e);
void reg(iax_event *e);
void run(void);
void terminateall(void);
YateIAXConnection *findconn(iax_session *session);
@ -85,7 +112,7 @@ public:
int makeCall(char *cidnum, char *cidname, char *target = 0, char *lang = 0);
void hangup(char *reason = "Unexpected problem");
void reject(char *reason = "Unexpected problem");
void startAudio(int format);
void startAudio(int format,int capability);
void sourceAudio(void *buffer, int len, int format);
void handleEvent(iax_event *event);
inline iax_session *session() const
@ -142,6 +169,10 @@ bool YateIAXEndPoint::Init(void)
Debug(DebugFail,"I can't initialize the IAX library");
return false;
}
int fd = iax_get_fd();
int tos = s_cfg.getIntValue("general","tos",dict_tos,0);
if (tos)
::setsockopt(fd,IPPROTO_IP,IP_TOS,&tos,sizeof(tos));
if (s_cfg.getBoolValue("general","debug",false))
::iax_enable_debug();
else
@ -195,6 +226,11 @@ void YateIAXEndPoint::handleEvent(iax_event *event)
case IAX_EVENT_REGREJ:
break;
#endif
case IAX_EVENT_TEXT:
{
Debug(DebugInfo,"this text is inside a call: %s",(char *)event->data);
}
break;
default:
Debug(DebugInfo,"Unhandled connectionless IAX event %d/%d",event->etype,event->subclass);
}
@ -234,6 +270,13 @@ void YateIAXEndPoint::run(void)
conn->destruct();
}
break;
case IAX_EVENT_REGREQ:
reg(e);
Debug(DebugInfo,"am primit un registration request");
break;
case IAX_EVENT_AUTHRP:
answer(e);
break;
default:
conn = (YateIAXConnection *)::iax_get_private(e->session);
if (conn)
@ -248,19 +291,99 @@ void YateIAXEndPoint::run(void)
}
}
bool YateIAXEndPoint::accepting(iax_event *e)
{
if (s_cfg.getBoolValue("users","unauth",false))
{
s_mutex.lock();
iax_accept(e->session,2);
s_mutex.unlock();
return 1;
}
Message m("auth");
if (e->ies.username)
m.addParam("username",e->ies.username);
else
m.addParam("username",e->session->username);
if (Engine::dispatch(m) && m.retValue().null())
{
s_mutex.lock();
iax_accept(e->session,2);
s_mutex.unlock();
return 1;
}
if (e->etype != IAX_EVENT_AUTHRP)
{
int methods = IAX_AUTH_MD5;
String s(::rand());
strncpy(e->session->username,e->ies.username,sizeof(e->session->username));
strncpy(e->session->dnid,e->ies.called_number,sizeof(e->session->dnid));
strncpy(e->session->callerid,e->ies.calling_name,sizeof(e->session->callerid));
e->session->voiceformat = e->ies.format;
e->session->peerformats = e->ies.capability;
strncpy(e->session->challenge,s.safe(),sizeof(e->session->challenge));
s_mutex.lock();
iax_send_authreq(e->session, methods);
s_mutex.unlock();
return 0;
}
if (e->ies.md5_result)
{
const char *ret = m.retValue();
if (!ret)
{
s_mutex.lock();
iax_send_regrej(e->session);
s_mutex.unlock();
return 0;
}
struct MD5Context md5;
MD5Init(&md5);
MD5Update(&md5, (const unsigned char *) e->session->challenge, strlen(e->session->challenge));
MD5Update(&md5, (const unsigned char *) ret, strlen(ret));
unsigned char reply[16];
char realreply[256];
MD5Final(reply, &md5);
char *ptr = realreply;
for (int x=0;x<16;x++)
ptr+=sprintf(ptr,"%02x", (unsigned int)reply[x]);
if (!strcmp(e->ies.md5_result,realreply))
{
e->session->refresh = 100;
s_mutex.lock();
iax_accept(e->session,2);
s_mutex.unlock();
return 1;
} else
{
s_mutex.lock();
iax_send_regrej(e->session);
s_mutex.unlock();
return 0;
}
}
return 0;
}
void YateIAXEndPoint::answer(iax_event *e)
{
if (!accepting(e))
return;
Debug(DebugInfo,"answer 1");
Message *m = new Message("route");
m->addParam("driver","iax");
// m->addParam("id",String(e->did));
m->addParam("callername",e->ies.calling_number);
m->addParam("called",e->ies.called_number);
// m->addParam("id",String(e->did));
if (e->ies.calling_name)
m->addParam("callername",e->ies.calling_name);
else
m->addParam("callername",e->session->callerid);
if (e->ies.called_number)
m->addParam("called",e->ies.called_number);
else
m->addParam("called",e->session->dnid);
Debug(DebugInfo,"callername %s and called %s",e->ies.calling_number,e->ies.called_number);
Engine::dispatch(m);
if (m->retValue() != NULL) {
s_mutex.lock();
::iax_accept(e->session);
s_mutex.unlock();
YateIAXConnection *conn = new YateIAXConnection(e->session);
*m = "call";
@ -278,7 +401,17 @@ void YateIAXEndPoint::answer(iax_event *e)
s_mutex.lock();
::iax_answer(e->session);
s_mutex.unlock();
conn->startAudio(e->ies.format);
int format,capability;
if (e->ies.format != 0)
format = e->ies.format;
else
format = e->session->voiceformat;
if (e->ies.capability != 0)
capability = e->ies.capability;
else
capability = e->session->peerformats;
conn->startAudio(format,capability);
Debug(DebugInfo,"The return value of the message is %s %p",m->retValue().c_str(),m->userData());
} else {
@ -294,6 +427,63 @@ void YateIAXEndPoint::answer(iax_event *e)
delete m;
}
void YateIAXEndPoint::reg(iax_event *e)
{
Message m("auth");
if (e->ies.username)
m.addParam("username",e->ies.username);
else
m.addParam("username",e->session->username);
if (Engine::dispatch(m) && m.retValue().null())
{
s_mutex.lock();
iax_send_regack(e->session);
s_mutex.unlock();
return;
}
if (e->ies.md5_result)
{
const char *ret = m.retValue();
if (!ret)
{
s_mutex.lock();
iax_send_regrej(e->session);
s_mutex.unlock();
return;
}
struct MD5Context md5;
MD5Init(&md5);
MD5Update(&md5, (const unsigned char *) e->session->challenge, strlen(e->session->challenge));
MD5Update(&md5, (const unsigned char *) ret, strlen(ret));
unsigned char reply[16];
char realreply[256];
MD5Final(reply, &md5);
char *ptr = realreply;
for (int x=0;x<16;x++)
ptr+=sprintf(ptr,"%02x", (unsigned int)reply[x]);
if (!strcmp(e->ies.md5_result,realreply))
{
e->session->refresh = 100;
strncpy(e->session->username,e->ies.username,sizeof(e->session->username));
s_mutex.lock();
iax_send_regack(e->session);
s_mutex.unlock();
} else
{
s_mutex.lock();
iax_send_regrej(e->session);
s_mutex.unlock();
}
return;
}
int methods = IAX_AUTH_MD5;
String s(::rand());
strncpy(e->session->challenge,s.safe(),sizeof(e->session->challenge));
s_mutex.lock();
iax_send_regauth(e->session, methods);
s_mutex.unlock();
}
YateIAXConnection * YateIAXEndPoint::findconn(iax_session *session)
{
ObjList *p = &m_calls;
@ -344,11 +534,17 @@ void YateIAXConnection::handleEvent(iax_event *event)
#endif
switch(event->etype) {
case IAX_EVENT_ACCEPT:
startAudio(event->ies.format);
startAudio(event->ies.format,event->ies.capability);
break;
case IAX_EVENT_VOICE:
// Debug(DebugInfo,"session->jitter %d session->jitterbuffer %d",event->session->jitter,event->session->jitterbuffer);
sourceAudio(event->data,event->datalen,event->subclass);
break;
case IAX_EVENT_TEXT:
{
Debug(DebugInfo,"this text is outside a call: %s",(char *)event->data);
}
break;
#if 0
case IAX_EVENT_DTMF:
break;
@ -403,19 +599,27 @@ int YateIAXConnection::makeCall(char *cidnum, char *cidname, char *target, char
return ::iax_call(m_session,cidnum,cidname,target,lang,0);
}
void YateIAXConnection::startAudio(int format)
void YateIAXConnection::startAudio(int format,int capability)
{
if (getConsumer())
return;
int masked = format & s_ast_formats;
const TokenDict *frm = dict_iaxformats;
for (; frm->token; frm++) {
if (frm->value & masked)
if (frm->value == masked)
break;
}
if (!frm->token) {
Debug(DebugGoOn,"IAX format 0x%X (local: 0x%X, common: 0x%X) not available in [%p]",
format,s_ast_formats,masked,this);
masked = capability & s_ast_formats;
frm = dict_iaxformats;
for (; frm->token; frm++) {
if (frm->value & masked)
break;
}
}
if (!frm->token) {
Debug(DebugGoOn,"IAX format 0x%X (local: 0x%X, remote: 0x%X, common: 0x%X) not available in [%p]",
format,s_ast_formats,capability,masked,this);
return;
}
Debug(DebugAll,"Creating IAX DataConsumer format \"%s\" (0x%X) in [%p]",frm->token,frm->value,this);
@ -433,14 +637,14 @@ void YateIAXConnection::sourceAudio(void *buffer, int len, int format)
const char *frm = lookup(format,dict_iaxformats);
if (!frm)
return;
Debug(DebugAll,"Creating IAX DataSource format \"%s\" (0x%X) in [%p]",frm,format,this);
Debug(DebugAll,"Creating IAXSource format \"%s\" (0x%X) in [%p]",frm,format,this);
m_ast_format = format;
setSource(new DataSource(frm));
setSource(new IAXSource(frm));
getSource()->deref();
}
if ((format == m_ast_format) && getSource()) {
DataBlock data(buffer,len,false);
getSource()->Forward(data);
((IAXSource *)(getSource()))->Forward(data);
data.clear(false);
}
}
@ -450,14 +654,48 @@ void YateIAXConnection::disconnected()
Debug(DebugAll,"YateIAXConnection::disconnected()");
}
IAXSource::~IAXSource()
{
Debug(DebugAll,"IAXSource::~IAXSource() [%p] total=%u",this,m_total);
if (m_time) {
m_time = Time::now() - m_time;
if (m_time) {
m_time = (m_total*1000000ULL + m_time/2) / m_time;
Debug(DebugInfo,"IAXSource rate=%llu b/s",m_time);
}
}
}
void IAXSource::Forward(const DataBlock &data)
{
m_total += data.length();
DataSource::Forward(data);
}
YateIAXAudioConsumer::YateIAXAudioConsumer(YateIAXConnection *conn, iax_session *session, int ast_format, const char *format)
: DataConsumer(format), m_conn(conn), m_session(session), m_ast_format(ast_format)
: DataConsumer(format), m_conn(conn), m_session(session),
m_ast_format(ast_format), m_total(0), m_time(Time::now())
{
Debug(DebugAll,"YateIAXAudioConsumer::YateIAXAudioConsumer(%p) [%p]",conn,this);
}
YateIAXAudioConsumer::~YateIAXAudioConsumer()
{
Debug(DebugAll,"YateIAXAudioConsumer::~YateIAXAudioConsumer() [%p] total=%u",this,m_total);
if (m_time) {
m_time = Time::now() - m_time;
if (m_time) {
m_time = (m_total*1000000ULL + m_time/2) / m_time;
Debug(DebugInfo,"YateIAXAudioConsumer rate=%llu b/s",m_time);
}
}
}
void YateIAXAudioConsumer::Consume(const DataBlock &data)
{
m_total += data.length();
::iax_send_voice(m_session,m_ast_format,(char *)data.data(),data.length());
}