📄 iax.c
字号:
/* * libiax: An implementation of Inter-Asterisk eXchange * * Copyright (C) 2001, Linux Support Services, Inc. * * Mark Spencer <markster@linux-support.net> * Frik Strecker <frik@gatherworks.com> * * This program is free software, distributed under the terms of * the GNU Lesser (Library) General Public License */#ifdef HAVE_CONFIG_H#include "config.h"#endif#if defined(WIN32) || defined(_WIN32_WCE)#undef __STRICT_ANSI__ //for strdup with ms#if defined(_WIN32_WCE)#define strdup _strdup#else#include <process.h>#include <fcntl.h>#include <io.h>#include <errno.h>#endif#include <string.h>#include <windows.h>#include <winsock.h>#include <time.h>#include <stdlib.h>#include <malloc.h>#include <stdarg.h>#include <stdio.h>#include <limits.h>#define snprintf _snprintf#if defined(_MSC_VER)#define close closesocket#if !defined(_WIN32_WCE)#define inline __inline#endif#endif#ifdef __cplusplusextern "C" {#endifvoid gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);#ifdef __cplusplus}#endif#else#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/time.h>#include <stdlib.h>#ifdef __GNUC__#ifndef __USE_SVID#define __USE_SVID#endif#endif#include <string.h>#include <stdarg.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/select.h>#include <netinet/in.h>#include <arpa/inet.h>#include <time.h>#ifndef MACOSX#include <malloc.h>#ifndef SOLARIS#include <error.h>#endif#endif#endif#include "jitterbuf.h"#include "iax-client.h"#include "md5.h"/* Define socket options for IAX2 sockets, based on platform * availability of flags */#if defined(WIN32) || defined(_WIN32_WCE)#define IAX_SOCKOPTS 0#else#ifdef MACOSX#define IAX_SOCKOPTS MSG_DONTWAIT#else#ifdef SOLARIS#define IAX_SOCKOPTS MSG_DONTWAIT#else /* Linux and others */#define IAX_SOCKOPTS MSG_DONTWAIT | MSG_NOSIGNAL#endif#endif#endif#ifdef SNOM_HACK/* The snom phone seems to improperly execute memset in some cases */#include "../../snom_phonecore2/include/snom_memset.h"#endif/* Voice TS Prediction causes libiax2 to clean up the timestamps on * outgoing frames. It works best with either continuous voice, or * callers who call iax_send_cng to indicate DTX for silence */#define USE_VOICE_TS_PREDICTION#define MIN_RETRY_TIME 10#define MAX_RETRY_TIME 4000#define MEMORY_SIZE 1000#define TRANSFER_NONE 0#define TRANSFER_BEGIN 1#define TRANSFER_READY 2#define TRANSFER_REL 3/* Video frames bypass jitterbuffer */static int video_bypass_jitterbuffer = 0;/* UDP Socket (file descriptor) */static int netfd = -1;/* Max timeouts */static const int maxretries = 10;/* configurable jitterbuffer options */static long jb_target_extra = -1;/* external global networking replacements */static iax_sendto_t iax_sendto = (iax_sendto_t) sendto;static iax_recvfrom_t iax_recvfrom = (iax_recvfrom_t) recvfrom;/* ping interval (seconds) */static int ping_time = 10;static void send_ping(void *session);struct iax_session { /* Private data */ void *pvt; /* session-local Sendto function */ iax_sendto_t sendto; /* Is voice quelched (e.g. hold) */ int quelch; /* Codec Pref Order */ char codec_order[32]; /* Codec Pref Order Index*/ int codec_order_len; /* Last received voice format */ int voiceformat; /* Last transmitted voice format */ int svoiceformat; /* Last received video format */ int videoformat; /* Last transmitted video format */ int svideoformat; /* Per session capability */ int capability; /* Last received timestamp */ unsigned int last_ts; /* Last transmitted timestamp */ unsigned int lastsent;#ifdef USE_VOICE_TS_PREDICTION /* Next predicted voice ts */ unsigned int nextpred; /* True if the last voice we transmitted was not silence/CNG */ int notsilenttx;#endif /* 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; /* Last sequence number we VNAKd */ unsigned char lastvnak; /* Time value that we base our transmission on */ struct timeval offset; /* Time value we base our delivery on */ struct timeval rxcore; /* Current link state */ int state; /* Expected Username */ char username[MAXSTRLEN]; /* Expected Secret */ char secret[MAXSTRLEN]; /* Refresh if applicable */ int refresh; /* ping scheduler id */ int pingid; /* Transfer stuff */ struct sockaddr_in transfer; int transferring; int transfercallno; int transferid; int transferpeer; /* for attended transfer */ int transfer_moh; /* for music on hold while performing attended transfer */ jitterbuf *jb; struct iax_netstat remote_netstats; /* For linking if there are multiple connections */ struct iax_session *next;};char iax_errstr[256];#define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr),#ifdef DEBUG_SUPPORT#ifdef DEBUG_DEFAULTstatic int debug = 1;#elsestatic int debug = 0;#endifvoid iax_enable_debug(void){ debug = 1;}void iax_disable_debug(void){ debug = 0;}void iax_set_private(struct iax_session *s, void *ptr){ s->pvt = ptr;}void *iax_get_private(struct iax_session *s){ return s->pvt;}void iax_set_sendto(struct iax_session *s, iax_sendto_t ptr){ s->sendto = ptr;}/* This is a little strange, but to debug you call DEBU(G "Hello World!\n"); */#if defined(WIN32) || defined(_WIN32_WCE)#define G __FILE__, __LINE__,#else#define G __FILE__, __LINE__, __PRETTY_FUNCTION__,#endif#define DEBU __debug#if defined(WIN32) || defined(_WIN32_WCE)static int __debug(char *file, int lineno, char *fmt, ...){ va_list args; va_start(args, fmt); if (debug) { fprintf(stderr, "%s line %d: ", file, lineno); vfprintf(stderr, fmt, args); } va_end(args); return 0;}#elsestatic int __debug(char *file, int lineno, char *func, char *fmt, ...){ va_list args; va_start(args, fmt); if (debug) { fprintf(stderr, "%s line %d in %s: ", file, lineno, func); vfprintf(stderr, fmt, args); } va_end(args); return 0;}#endif#else /* No debug support */#if defined(WIN32) || defined(_WIN32_WCE)#define DEBU#else#define DEBU(fmt...) \ do {} while(0)#endif#define G#endiftypedef void (*sched_func)(void *);struct iax_sched { /* These are scheduled things to be delivered */ struct timeval when; /* If event is non-NULL then we're delivering an event */ struct iax_event *event; /* If frame is non-NULL then we're transmitting a frame */ struct iax_frame *frame; /* If func is non-NULL then we should call it */ sched_func func; /* and pass it this argument */ void *arg; /* Easy linking */ struct iax_sched *next;};static struct iax_sched *schedq = NULL;static struct iax_session *sessions = NULL;static int callnums = 1;static int transfer_id = 1; /* for attended transfer */void iax_set_private(struct iax_session *s, void *ptr){ s->pvt = ptr;}void *iax_get_private(struct iax_session *s){ return s->pvt;}void iax_set_sendto(struct iax_session *s, iax_sendto_t ptr){ s->sendto = ptr;}unsigned int iax_session_get_capability(struct iax_session *s){ return s->capability;}static int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2){ return (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) || (sin1->sin_port != sin2->sin_port);}static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int ms){ /* Schedule event to be delivered to the client in ms milliseconds from now, or a reliable frame to be retransmitted */ struct iax_sched *sched, *cur, *prev = NULL; if (!event && !frame && !func) { DEBU(G "No event, no frame, no func? what are we scheduling?\n"); return -1; } //fprintf(stderr, "scheduling event %d ms from now\n", ms); sched = (struct iax_sched*)malloc(sizeof(struct iax_sched)); if (sched) { memset(sched, 0, sizeof(struct iax_sched)); gettimeofday(&sched->when, NULL); sched->when.tv_sec += (ms / 1000); ms = ms % 1000; sched->when.tv_usec += (ms * 1000); if (sched->when.tv_usec > 1000000) { sched->when.tv_usec -= 1000000; sched->when.tv_sec++; } sched->event = event; sched->frame = frame; sched->func = func; sched->arg = arg; /* Put it in the list, in order */ cur = schedq; while(cur && ((cur->when.tv_sec < sched->when.tv_sec) || ((cur->when.tv_usec <= sched->when.tv_usec) && (cur->when.tv_sec == sched->when.tv_sec)))) { prev = cur; cur = cur->next; } sched->next = cur; if (prev) { prev->next = sched; } else { schedq = sched; } return 0; } else { DEBU(G "Out of memory!\n"); return -1; }}static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all){ struct iax_sched *cur, *tmp, *prev = NULL; cur = schedq; while (cur) { if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) { if (prev) prev->next = cur->next; else schedq = cur->next; tmp = cur; cur = cur->next; free(tmp); if (!all) return -1; } else { prev = cur; cur = cur->next; } } return 0;}int iax_time_to_next_event(void){ struct timeval tv; struct iax_sched *cur = schedq; int ms, min = 999999999; /* If there are no pending events, we don't need to timeout */ if (!cur) return -1; gettimeofday(&tv, NULL); while(cur) { ms = (cur->when.tv_sec - tv.tv_sec) * 1000 + (cur->when.tv_usec - tv.tv_usec) / 1000; if (ms < min) min = ms; cur = cur->next; } if (min < 0) min = 0; return min;}struct iax_session *iax_session_new(void){ struct iax_session *s; s = (struct iax_session *)malloc(sizeof(struct iax_session)); if (s) { jb_conf jbconf; memset(s, 0, sizeof(struct iax_session)); /* Initialize important fields */ s->voiceformat = -1; s->svoiceformat = -1; s->videoformat = -1; /* Default pingtime to 100 ms -- should cover most decent net connections */ s->pingtime = 100; /* XXX Not quite right -- make sure it's not in use, but that won't matter unless you've had at least 65k calls. XXX */ s->callno = callnums++; if (callnums > 32767) callnums = 1; s->peercallno = 0; s->lastvnak = -1; s->transferpeer = 0; /* for attended transfer */ s->next = sessions; s->sendto = iax_sendto; s->pingid = -1; s->jb = jb_new(); if ( !s->jb ) { free(s); return 0; } jbconf.max_jitterbuf = 0; jbconf.resync_threshold = 1000; jbconf.max_contig_interp = 0; jbconf.target_extra = jb_target_extra; jb_setconf(s->jb, &jbconf); sessions = s; } return s;}static int iax_session_valid(struct iax_session *session){ /* Return -1 on a valid iax session pointer, 0 on a failure */ struct iax_session *cur = sessions; while(cur) { if (session == cur)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -