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:
parent
7c853174bf
commit
fe6063f045
|
@ -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)
|
||||
|
|
16
configure.in
16
configure.in
|
@ -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])
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Makefile
|
||||
core*
|
||||
*.o
|
||||
*.a
|
||||
*.orig
|
||||
*~
|
||||
.*.swp
|
|
@ -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) $@
|
|
@ -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
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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; }
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue